Whamcloud - gitweb
merge b_devel to b_eq: 20031010
authorericm <ericm>
Fri, 10 Oct 2003 09:32:02 +0000 (09:32 +0000)
committerericm <ericm>
Fri, 10 Oct 2003 09:32:02 +0000 (09:32 +0000)
kernel only

54 files changed:
lnet/include/linux/kp30.h
lnet/include/linux/portals_lib.h
lnet/include/lnet/lltrace.h
lnet/include/lnet/lnetctl.h
lnet/include/lnet/ptlctl.h
lnet/klnds/gmlnd/gmlnd.h
lnet/klnds/qswlnd/qswlnd.c
lnet/klnds/socklnd/socklnd.c
lnet/klnds/toelnd/toenal.c
lnet/klnds/toelnd/toenal_cb.c
lnet/libcfs/Makefile.mk
lnet/libcfs/module.c
lnet/lnet/lib-md.c
lnet/router/router.h
lnet/utils/acceptor.c
lnet/utils/portals.c
lustre/kernel_patches/patches/2.6.0-test6-mm4.patch [new file with mode: 0644]
lustre/kernel_patches/patches/export_symbols-2.6.0-test6.patch [new file with mode: 0644]
lustre/kernel_patches/patches/ext3-ea-in-inode-2.4.22-rh.patch [new file with mode: 0644]
lustre/kernel_patches/patches/ext3-htree-2.4.22-rh.patch
lustre/kernel_patches/patches/ext3-htree.patch
lustre/kernel_patches/patches/iopen-2.6.0-test6.patch [new file with mode: 0644]
lustre/kernel_patches/patches/kexec-2.6.0-test6-full.patch [new file with mode: 0644]
lustre/kernel_patches/patches/lkcd-cvs-2.6.0-test6.patch [new file with mode: 0644]
lustre/kernel_patches/patches/lkcd-kernel-changes-2.6.0-test6.patch [new file with mode: 0644]
lustre/kernel_patches/patches/nfs_export_kernel-2.4.20-hp.patch [new file with mode: 0644]
lustre/kernel_patches/patches/nfs_export_kernel-2.4.20-rh.patch [new file with mode: 0644]
lustre/kernel_patches/patches/nfs_export_kernel-2.4.22-rh.patch [new file with mode: 0644]
lustre/kernel_patches/patches/vfs_intent_2.6.0-test6.patch [new file with mode: 0644]
lustre/kernel_patches/patches/vfs_nointent_2.6.0-test6.patch [new file with mode: 0644]
lustre/kernel_patches/pc/ext3-ea-in-inode-2.4.22-rh.pc [new file with mode: 0644]
lustre/kernel_patches/pc/nfs_export_kernel-2.4.20-hp.pc [new file with mode: 0644]
lustre/kernel_patches/pc/nfs_export_kernel-2.4.20-rh.pc [new file with mode: 0644]
lustre/kernel_patches/pc/nfs_export_kernel-2.4.22-rh.pc [new file with mode: 0644]
lustre/kernel_patches/series/rh-2.4.22
lustre/lvfs/Makefile.mk [new file with mode: 0644]
lustre/mds/Makefile.mk
lustre/obdclass/llog_internal.h [new file with mode: 0644]
lustre/portals/include/linux/kp30.h
lustre/portals/include/linux/portals_lib.h
lustre/portals/include/portals/lltrace.h
lustre/portals/include/portals/ptlctl.h
lustre/portals/knals/gmnal/gmnal.h
lustre/portals/knals/qswnal/qswnal.c
lustre/portals/knals/socknal/socknal.c
lustre/portals/knals/toenal/toenal.c
lustre/portals/knals/toenal/toenal_cb.c
lustre/portals/libcfs/Makefile.mk
lustre/portals/libcfs/module.c
lustre/portals/portals/lib-md.c
lustre/portals/router/router.h
lustre/portals/utils/acceptor.c
lustre/portals/utils/portals.c
lustre/tests/cmknod.c [new file with mode: 0644]

index 69ae296..cea5a32 100644 (file)
@@ -58,7 +58,7 @@ extern unsigned int portal_cerror;
 #define D_IOCTL     (1 << 7) /* ioctl related information */
 #define D_BLOCKS    (1 << 8) /* ext2 block allocation */
 #define D_NET       (1 << 9) /* network communications */
-#define D_WARNING   (1 << 10)
+#define D_WARNING   (1 << 10) /* CWARN(...) == CDEBUG (D_WARNING, ...) */
 #define D_BUFFS     (1 << 11)
 #define D_OTHER     (1 << 12)
 #define D_DENTRY    (1 << 13)
@@ -757,6 +757,39 @@ do {                                                                    \
  * USER LEVEL STUFF BELOW
  */
 
+#define PORTALS_CFG_VERSION 0x00010001;
+
+struct portals_cfg {
+        __u32 pcfg_version;
+        __u32 pcfg_command;
+
+        __u32 pcfg_nal;
+        __u32 pcfg_flags;
+
+        __u64 pcfg_nid;
+        __u64 pcfg_nid2;
+        __u64 pcfg_nid3;
+        __u32 pcfg_id;
+        __u32 pcfg_misc;
+        __u32 pcfg_fd;
+        __u32 pcfg_count;
+        __u32 pcfg_size;
+        __u32 pcfg_wait;
+
+        __u32 pcfg_plen1; /* buffers in userspace */
+        char *pcfg_pbuf1;
+        __u32 pcfg_plen2; /* buffers in userspace */
+        char *pcfg_pbuf2;
+};
+
+#define PCFG_INIT(pcfg, cmd)                            \
+do {                                                    \
+        memset(&pcfg, 0, sizeof(pcfg));                 \
+        pcfg.pcfg_version = PORTALS_CFG_VERSION;        \
+        pcfg.pcfg_command = (cmd);                      \
+                                                        \
+} while (0)
+
 #define PORTAL_IOCTL_VERSION 0x00010007
 #define PING_SYNC       0
 #define PING_ASYNC      1
@@ -1034,11 +1067,20 @@ struct lustre_peer {
         ptl_handle_ni_t peer_ni;
 };
 
+
 /* module.c */
-typedef int (*nal_cmd_handler_t)(struct portal_ioctl_data *, void * private);
+typedef int (*nal_cmd_handler_t)(struct portals_cfg *, void * private);
 int kportal_nal_register(int nal, nal_cmd_handler_t handler, void * private);
 int kportal_nal_unregister(int nal);
 
+enum cfg_record_type {
+        PORTALS_CFG_TYPE = 1,
+        LUSTRE_CFG_TYPE = 123,
+};
+
+typedef int (*cfg_record_cb_t)(enum cfg_record_type, int len, void *data);
+int kportal_nal_cmd(struct portals_cfg *);
+
 ptl_handle_ni_t *kportal_get_ni (int nal);
 void kportal_put_ni (int nal);
 
index a528a80..14d60c6 100644 (file)
@@ -42,6 +42,11 @@ static inline int size_round (int val)
         return (val + 7) & (~0x7);
 }
 
+static inline int size_round16(int val)
+{
+        return (val + 0xf) & (~0xf);
+}
+
 static inline int size_round0(int val)
 {
         if (!val)
index d389aab..5f266e2 100644 (file)
@@ -18,8 +18,8 @@
 #include <unistd.h>
 #include <sys/time.h>
 #include <portals/types.h>
-#include <portals/ptlctl.h>
 #include <linux/kp30.h>
+#include <portals/ptlctl.h>
 #include <linux/limits.h>
 #include <asm/page.h>
 #include <linux/version.h>
index 7763f1b..0466494 100644 (file)
@@ -71,6 +71,8 @@ int jt_dbg_mark_debug_buf(int argc, char **argv);
 int jt_dbg_modules(int argc, char **argv);
 int jt_dbg_panic(int argc, char **argv);
 
+int ptl_set_cfg_record_cb(cfg_record_cb_t cb);
+
 /* l_ioctl.c */
 int register_ioc_dev(int dev_id, const char * dev_name);
 void unregister_ioc_dev(int dev_id);
index 7763f1b..0466494 100644 (file)
@@ -71,6 +71,8 @@ int jt_dbg_mark_debug_buf(int argc, char **argv);
 int jt_dbg_modules(int argc, char **argv);
 int jt_dbg_panic(int argc, char **argv);
 
+int ptl_set_cfg_record_cb(cfg_record_cb_t cb);
+
 /* l_ioctl.c */
 int register_ioc_dev(int dev_id, const char * dev_name);
 void unregister_ioc_dev(int dev_id);
index fdde839..2db6c9b 100644 (file)
@@ -159,7 +159,11 @@ typedef struct     _gmnal_msghdr {
  *     transmit descriptors on the free list)
  */
 typedef struct _gmnal_rxtwe {
-       gm_recv_event_t *rx;
+       void                    *buffer;
+       unsigned                snode;
+       unsigned                sport;
+       unsigned                type;
+       unsigned                length;
        struct _gmnal_rxtwe     *next;
 } gmnal_rxtwe_t;
 
@@ -408,10 +412,10 @@ int               gmnal_start_kernel_threads(gmnal_data_t *);
  */
 int            gmnal_ct_thread(void *); /* caretaker thread */
 int            gmnal_rx_thread(void *); /* receive thread */
-int            gmnal_pre_receive(gmnal_data_t*, gm_recv_t*, int);
-int            gmnal_rx_bad(gmnal_data_t *, gm_recv_t *, gmnal_srxd_t *);
+int            gmnal_pre_receive(gmnal_data_t*, gmnal_rxtwe_t*, int);
+int            gmnal_rx_bad(gmnal_data_t *, gmnal_rxtwe_t *, gmnal_srxd_t*);
 int            gmnal_rx_requeue_buffer(gmnal_data_t *, gmnal_srxd_t *);
-int            gmnal_add_rxtwe(gmnal_data_t *, gm_recv_event_t *);
+int            gmnal_add_rxtwe(gmnal_data_t *, gm_recv_t *);
 gmnal_rxtwe_t * gmnal_get_rxtwe(gmnal_data_t *);
 void           gmnal_remove_rxtwe(gmnal_data_t *);
 
index cdafba9..4472e30 100644 (file)
@@ -113,12 +113,12 @@ kqswnal_init(int interface, ptl_pt_index_t ptl_size, ptl_ac_index_t ac_size,
 }
 
 int
-kqswnal_get_tx_desc (struct portal_ioctl_data *data)
+kqswnal_get_tx_desc (struct portals_cfg *pcfg)
 {
        unsigned long      flags;
        struct list_head  *tmp;
        kqswnal_tx_t      *ktx;
-       int                index = data->ioc_count;
+       int                index = pcfg->pcfg_count;
        int                rc = -ENOENT;
 
        spin_lock_irqsave (&kqswnal_data.kqn_idletxd_lock, flags);
@@ -129,13 +129,13 @@ kqswnal_get_tx_desc (struct portal_ioctl_data *data)
 
                ktx = list_entry (tmp, kqswnal_tx_t, ktx_list);
 
-               data->ioc_pbuf1 = (char *)ktx;
-               data->ioc_count = NTOH__u32(ktx->ktx_wire_hdr->type);
-               data->ioc_size  = NTOH__u32(PTL_HDR_LENGTH(ktx->ktx_wire_hdr));
-               data->ioc_nid   = NTOH__u64(ktx->ktx_wire_hdr->dest_nid);
-               data->ioc_nid2  = ktx->ktx_nid;
-               data->ioc_misc  = ktx->ktx_launcher;
-               data->ioc_flags = (list_empty (&ktx->ktx_delayed_list) ? 0 : 1) |
+               pcfg->pcfg_pbuf1 = (char *)ktx;
+               pcfg->pcfg_count = NTOH__u32(ktx->ktx_wire_hdr->type);
+               pcfg->pcfg_size  = NTOH__u32(PTL_HDR_LENGTH(ktx->ktx_wire_hdr));
+               pcfg->pcfg_nid   = NTOH__u64(ktx->ktx_wire_hdr->dest_nid);
+               pcfg->pcfg_nid2  = ktx->ktx_nid;
+               pcfg->pcfg_misc  = ktx->ktx_launcher;
+               pcfg->pcfg_flags = (list_empty (&ktx->ktx_delayed_list) ? 0 : 1) |
                                  (!ktx->ktx_isnblk                    ? 0 : 2) |
                                  (ktx->ktx_state << 2);
                rc = 0;
@@ -147,21 +147,21 @@ kqswnal_get_tx_desc (struct portal_ioctl_data *data)
 }
 
 int
-kqswnal_cmd (struct portal_ioctl_data *data, void *private)
+kqswnal_cmd (struct portals_cfg *pcfg, void *private)
 {
-       LASSERT (data != NULL);
+       LASSERT (pcfg != NULL);
        
-       switch (data->ioc_nal_cmd) {
+       switch (pcfg->pcfg_command) {
        case NAL_CMD_GET_TXDESC:
-               return (kqswnal_get_tx_desc (data));
+               return (kqswnal_get_tx_desc (pcfg));
 
        case NAL_CMD_REGISTER_MYNID:
                CDEBUG (D_IOCTL, "setting NID offset to "LPX64" (was "LPX64")\n",
-                       data->ioc_nid - kqswnal_data.kqn_elanid,
+                       pcfg->pcfg_nid - kqswnal_data.kqn_elanid,
                        kqswnal_data.kqn_nid_offset);
                kqswnal_data.kqn_nid_offset =
-                       data->ioc_nid - kqswnal_data.kqn_elanid;
-               kqswnal_lib.ni.nid = data->ioc_nid;
+                       pcfg->pcfg_nid - kqswnal_data.kqn_elanid;
+               kqswnal_lib.ni.nid = pcfg->pcfg_nid;
                return (0);
                
        default:
index 33f950e..c72717d 100644 (file)
@@ -1219,27 +1219,27 @@ ksocknal_push (ptl_nid_t nid)
 }
 
 int
-ksocknal_cmd(struct portal_ioctl_data * data, void * private)
+ksocknal_cmd(struct portals_cfg *pcfg, void * private)
 {
         int rc = -EINVAL;
 
-        LASSERT (data != NULL);
+        LASSERT (pcfg != NULL);
 
-        switch(data->ioc_nal_cmd) {
+        switch(pcfg->pcfg_command) {
         case NAL_CMD_GET_AUTOCONN: {
-                ksock_route_t *route = ksocknal_get_route_by_idx (data->ioc_count);
+                ksock_route_t *route = ksocknal_get_route_by_idx (pcfg->pcfg_count);
 
                 if (route == NULL)
                         rc = -ENOENT;
                 else {
                         rc = 0;
-                        data->ioc_nid   = route->ksnr_peer->ksnp_nid;
-                        data->ioc_id    = route->ksnr_ipaddr;
-                        data->ioc_misc  = route->ksnr_port;
-                        data->ioc_count = route->ksnr_generation;
-                        data->ioc_size  = route->ksnr_buffer_size;
-                        data->ioc_wait  = route->ksnr_sharecount;
-                        data->ioc_flags = (route->ksnr_nonagel      ? 1 : 0) |
+                        pcfg->pcfg_nid   = route->ksnr_peer->ksnp_nid;
+                        pcfg->pcfg_id    = route->ksnr_ipaddr;
+                        pcfg->pcfg_misc  = route->ksnr_port;
+                        pcfg->pcfg_count = route->ksnr_generation;
+                        pcfg->pcfg_size  = route->ksnr_buffer_size;
+                        pcfg->pcfg_wait  = route->ksnr_sharecount;
+                        pcfg->pcfg_flags = (route->ksnr_nonagel      ? 1 : 0) |
                                           (route->ksnr_xchange_nids ? 2 : 0) |
                                           (route->ksnr_irq_affinity ? 4 : 0) |
                                           (route->ksnr_eager        ? 8 : 0);
@@ -1248,56 +1248,56 @@ ksocknal_cmd(struct portal_ioctl_data * data, void * private)
                 break;
         }
         case NAL_CMD_ADD_AUTOCONN: {
-                rc = ksocknal_add_route (data->ioc_nid, data->ioc_id,
-                                         data->ioc_misc, data->ioc_size,
-                                         (data->ioc_flags & 0x01) != 0,
-                                         (data->ioc_flags & 0x02) != 0,
-                                         (data->ioc_flags & 0x04) != 0,
-                                         (data->ioc_flags & 0x08) != 0,
-                                         (data->ioc_flags & 0x10) != 0);
+                rc = ksocknal_add_route (pcfg->pcfg_nid, pcfg->pcfg_id,
+                                         pcfg->pcfg_misc, pcfg->pcfg_size,
+                                         (pcfg->pcfg_flags & 0x01) != 0,
+                                         (pcfg->pcfg_flags & 0x02) != 0,
+                                         (pcfg->pcfg_flags & 0x04) != 0,
+                                         (pcfg->pcfg_flags & 0x08) != 0,
+                                         (pcfg->pcfg_flags & 0x10) != 0);
                 break;
         }
         case NAL_CMD_DEL_AUTOCONN: {
-                rc = ksocknal_del_route (data->ioc_nid, data->ioc_id, 
-                                         (data->ioc_flags & 1) != 0,
-                                         (data->ioc_flags & 2) != 0);
+                rc = ksocknal_del_route (pcfg->pcfg_nid, pcfg->pcfg_id, 
+                                         (pcfg->pcfg_flags & 1) != 0,
+                                         (pcfg->pcfg_flags & 2) != 0);
                 break;
         }
         case NAL_CMD_GET_CONN: {
-                ksock_conn_t *conn = ksocknal_get_conn_by_idx (data->ioc_count);
+                ksock_conn_t *conn = ksocknal_get_conn_by_idx (pcfg->pcfg_count);
 
                 if (conn == NULL)
                         rc = -ENOENT;
                 else {
                         rc = 0;
-                        data->ioc_nid  = conn->ksnc_peer->ksnp_nid;
-                        data->ioc_id   = conn->ksnc_ipaddr;
-                        data->ioc_misc = conn->ksnc_port;
+                        pcfg->pcfg_nid  = conn->ksnc_peer->ksnp_nid;
+                        pcfg->pcfg_id   = conn->ksnc_ipaddr;
+                        pcfg->pcfg_misc = conn->ksnc_port;
                         ksocknal_put_conn (conn);
                 }
                 break;
         }
         case NAL_CMD_REGISTER_PEER_FD: {
-                struct socket *sock = sockfd_lookup (data->ioc_fd, &rc);
+                struct socket *sock = sockfd_lookup (pcfg->pcfg_fd, &rc);
 
                 if (sock != NULL) {
-                        rc = ksocknal_create_conn (data->ioc_nid, NULL,
-                                                   sock, data->ioc_flags);
+                        rc = ksocknal_create_conn (pcfg->pcfg_nid, NULL,
+                                                   sock, pcfg->pcfg_flags);
                         if (rc != 0)
                                 fput (sock->file);
                 }
                 break;
         }
         case NAL_CMD_CLOSE_CONNECTION: {
-                rc = ksocknal_close_conn (data->ioc_nid, data->ioc_id);
+                rc = ksocknal_close_conn (pcfg->pcfg_nid, pcfg->pcfg_id);
                 break;
         }
         case NAL_CMD_REGISTER_MYNID: {
-                rc = ksocknal_set_mynid (data->ioc_nid);
+                rc = ksocknal_set_mynid (pcfg->pcfg_nid);
                 break;
         }
         case NAL_CMD_PUSH_CONNECTION: {
-                rc = ksocknal_push (data->ioc_nid);
+                rc = ksocknal_push (pcfg->pcfg_nid);
                 break;
         }
         }
index dc7e447..a85b281 100644 (file)
@@ -354,23 +354,23 @@ ktoenal_free_buffers (void)
 }
 
 int
-ktoenal_cmd(struct portal_ioctl_data * data, void * private)
+ktoenal_cmd(struct portals_cfg *pcfg, void * private)
 {
         int rc = -EINVAL;
 
-        LASSERT (data != NULL);
+        LASSERT (pcfg != NULL);
 
-        switch(data->ioc_nal_cmd) {
+        switch(pcfg->pcfg_command) {
         case NAL_CMD_REGISTER_PEER_FD: {
-                rc = ktoenal_add_sock(data->ioc_nid, data->ioc_fd);
+                rc = ktoenal_add_sock(pcfg->pcfg_nid, pcfg->pcfg_fd);
                 break;
         }
         case NAL_CMD_CLOSE_CONNECTION: {
-                rc = ktoenal_close_sock(data->ioc_nid);
+                rc = ktoenal_close_sock(pcfg->pcfg_nid);
                 break;
         }
         case NAL_CMD_REGISTER_MYNID: {
-                rc = ktoenal_set_mynid (data->ioc_nid);
+                rc = ktoenal_set_mynid (pcfg->pcfg_nid);
                 break;
         }
         }
index 8282141..f92511a 100644 (file)
@@ -300,7 +300,7 @@ ktoenal_process_transmit (ksock_conn_t *conn, long *irq_flags)
                         rc = 0;                 /* nothing sent */
                 else
                 {
-                        /* FIXME: handle socket errors properly */
+                        //warning FIXME: handle socket errors properly
                         CERROR ("Error socknal send(%d) %p: %d\n", tx->tx_nob, conn, rc);
                         rc = tx->tx_nob;        /* kid on for now whole packet went */
                 }
@@ -862,7 +862,7 @@ ktoenal_process_receive (ksock_conn_t *conn, long *irq_flags)
                 if (len != -EAGAIN &&           /* ! nothing to read now */
                     len != 0)                   /* ! nothing to read ever */
                 {
-                        /* FIXME: handle socket errors properly */
+                        // warning FIXME: handle socket errors properly
                         CERROR ("Error socknal read(%d) %p: %d\n",
                                 conn->ksnc_rx_nob_wanted, conn, len);
                 }
index 9aa838f..c201429 100644 (file)
@@ -6,4 +6,4 @@
 include fs/lustre/portals/Kernelenv
 
 obj-y += libcfs.o
-libcfs-objs    := module.o proc.o debug.o
+libcfs-objs    := module.o proc.o debug.o lwt.o
index 308158b..6beae25 100644 (file)
@@ -207,17 +207,19 @@ kportal_get_route(int index, __u32 *gateway_nalidp, ptl_nid_t *gateway_nidp,
         return (rc);
 }
 
-static int
-kportal_nal_cmd(int nal, struct portal_ioctl_data *data)
+int
+kportal_nal_cmd(struct portals_cfg *pcfg)
 {
+        __u32 nal = pcfg->pcfg_nal;
         int rc = -EINVAL;
 
         ENTRY;
 
         down(&nal_cmd_sem);
         if (nal > 0 && nal <= NAL_MAX_NR && nal_cmd[nal].nch_handler) {
-                CDEBUG(D_IOCTL, "calling handler nal: %d, cmd: %d\n", nal, data->ioc_nal_cmd);
-                rc = nal_cmd[nal].nch_handler(data, nal_cmd[nal].nch_private);
+                CDEBUG(D_IOCTL, "calling handler nal: %d, cmd: %d\n", nal, 
+                       pcfg->pcfg_command);
+                rc = nal_cmd[nal].nch_handler(pcfg, nal_cmd[nal].nch_private);
         }
         up(&nal_cmd_sem);
         RETURN(rc);
@@ -445,15 +447,25 @@ static int kportal_ioctl(struct inode *inode, struct file *file,
                 break;
         }
 
-        case IOC_PORTAL_NAL_CMD:
-                CDEBUG (D_IOCTL, "nal command nal %d cmd %d\n", data->ioc_nal,
-                        data->ioc_nal_cmd);
-                err = kportal_nal_cmd(data->ioc_nal, data);
+        case IOC_PORTAL_NAL_CMD: {
+                struct portals_cfg pcfg;
+
+                LASSERT (data->ioc_plen1 == sizeof(pcfg));
+                err = copy_from_user(&pcfg, (void *)data->ioc_pbuf1, 
+                                     sizeof(pcfg));
+                if ( err ) {
+                        EXIT;
+                        return err;
+                }
+
+                CDEBUG (D_IOCTL, "nal command nal %d cmd %d\n", pcfg.pcfg_nal,
+                        pcfg.pcfg_command);
+                err = kportal_nal_cmd(&pcfg);
                 if (err == 0)
                         if (copy_to_user((char *)arg, data, sizeof (*data)))
                                 err = -EFAULT;
                 break;
-
+        }
         case IOC_PORTAL_FAIL_NID: {
                 const ptl_handle_ni_t *nip;
 
@@ -643,6 +655,7 @@ EXPORT_SYMBOL(kportal_assertion_failed);
 EXPORT_SYMBOL(dispatch_name);
 EXPORT_SYMBOL(kportal_get_ni);
 EXPORT_SYMBOL(kportal_put_ni);
+EXPORT_SYMBOL(kportal_nal_cmd);
 
 module_init(init_kportals_module);
 module_exit (exit_kportals_module);
index 415eda6..be6949c 100644 (file)
@@ -396,8 +396,7 @@ int do_PtlMDUpdate_internal(nal_cb_t * nal, void *private, void *v_args,
             test_eq->sequence == args->sequence_in) {
                 lib_me_t *me = md->me;
 
-                /* XXX this does not track eq refcounts properly */
-
+                // #warning this does not track eq refcounts properly 
                 ret->rc = lib_md_build(nal, md, private,
                                        new, &new->eventq, md->unlink);
 
index dc9e4ed..4ace247 100644 (file)
@@ -71,7 +71,11 @@ typedef struct
 
 typedef struct
 {
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+        struct work_struct        kpru_tq;
+#else
         struct tq_struct        kpru_tq;
+#endif
         int                     kpru_nal_id;
         ptl_nid_t               kpru_nid;
         int                     kpru_alive;
index c6590db..9fb2759 100644 (file)
@@ -409,6 +409,7 @@ int main(int argc, char **argv)
                 int len = sizeof(clntaddr);
                 int cfd;
                 struct portal_ioctl_data data;
+                struct portals_cfg pcfg;
                 ptl_nid_t peer_nid;
                 
                 cfd = accept(fd, (struct sockaddr *)&clntaddr, &len);
@@ -441,13 +442,16 @@ int main(int argc, char **argv)
                 }
 
                 show_connection (cfd, clntaddr.sin_addr.s_addr, peer_nid);
-                
+
+                PCFG_INIT(pcfg, NAL_CMD_REGISTER_PEER_FD);
+                pcfg.pcfg_nal = nal;
+                pcfg.pcfg_fd = cfd;
+                pcfg.pcfg_nid = peer_nid;
+                pcfg.pcfg_flags = bind_irq;
+
                 PORTAL_IOC_INIT(data);
-                data.ioc_fd = cfd;
-                data.ioc_nal = nal;
-                data.ioc_nal_cmd = NAL_CMD_REGISTER_PEER_FD;
-                data.ioc_nid = peer_nid;
-                data.ioc_flags = bind_irq;
+                data.ioc_pbuf1 = (char*)&pcfg;
+                data.ioc_plen1 = sizeof(pcfg);
                 
                 if (ioctl(pfd, IOC_PORTAL_NAL_CMD, &data) < 0) {
                         perror("ioctl failed");
index c5e374f..94ac0f1 100644 (file)
@@ -84,6 +84,38 @@ static name2num_t nalnames[] = {
         {NULL,         -1}
 };
 
+static cfg_record_cb_t g_record_cb;
+
+int 
+ptl_set_cfg_record_cb(cfg_record_cb_t cb)
+{
+        g_record_cb = cb;
+        return 0;
+}
+
+int 
+pcfg_ioctl(struct portals_cfg *pcfg) 
+{
+        int rc;
+
+        pcfg->pcfg_nal    = g_nal;
+
+        if (g_record_cb) {
+                rc = g_record_cb(PORTALS_CFG_TYPE, sizeof(*pcfg), pcfg);
+        } else {
+                struct portal_ioctl_data data;
+                PORTAL_IOC_INIT (data);
+                data.ioc_pbuf1   = (char*)pcfg;
+                data.ioc_plen1   = sizeof(*pcfg);
+
+                rc = l_ioctl (PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
+        }
+
+        return (rc);
+}
+
+
+
 static name2num_t *
 name2num_lookup_name (name2num_t *table, char *str)
 {
@@ -402,7 +434,7 @@ int jt_ptl_network(int argc, char **argv)
 int 
 jt_ptl_print_autoconnects (int argc, char **argv)
 {
-        struct portal_ioctl_data data;
+        struct portals_cfg        pcfg;
         char                     buffer[64];
         int                      index;
         int                      rc;
@@ -411,24 +443,22 @@ jt_ptl_print_autoconnects (int argc, char **argv)
                 return -1;
 
         for (index = 0;;index++) {
-                PORTAL_IOC_INIT (data);
-                data.ioc_nal     = g_nal;
-                data.ioc_nal_cmd = NAL_CMD_GET_AUTOCONN;
-                data.ioc_count   = index;
-                
-                rc = l_ioctl (PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
+                PCFG_INIT (pcfg, NAL_CMD_GET_AUTOCONN);
+                pcfg.pcfg_count   = index;
+
+                rc = pcfg_ioctl (&pcfg);
                 if (rc != 0)
                         break;
 
                 printf (LPX64"@%s:%d #%d buffer %d nonagle %s xchg %s "
                         "affinity %s eager %s share %d\n",
-                        data.ioc_nid, ptl_ipaddr_2_str (data.ioc_id, buffer),
-                        data.ioc_misc, data.ioc_count, data.ioc_size, 
-                        (data.ioc_flags & 1) ? "on" : "off",
-                        (data.ioc_flags & 2) ? "on" : "off",
-                        (data.ioc_flags & 4) ? "on" : "off",
-                        (data.ioc_flags & 8) ? "on" : "off",
-                        data.ioc_wait);
+                        pcfg.pcfg_nid, ptl_ipaddr_2_str (pcfg.pcfg_id, buffer),
+                        pcfg.pcfg_misc, pcfg.pcfg_count, pcfg.pcfg_size, 
+                        (pcfg.pcfg_flags & 1) ? "on" : "off",
+                        (pcfg.pcfg_flags & 2) ? "on" : "off",
+                        (pcfg.pcfg_flags & 4) ? "on" : "off",
+                        (pcfg.pcfg_flags & 8) ? "on" : "off",
+                        pcfg.pcfg_wait);
         }
 
         if (index == 0)
@@ -439,7 +469,7 @@ jt_ptl_print_autoconnects (int argc, char **argv)
 int 
 jt_ptl_add_autoconnect (int argc, char **argv)
 {
-        struct portal_ioctl_data data;
+        struct portals_cfg        pcfg;
         ptl_nid_t                nid;
         __u32                    ip;
         int                      port;
@@ -497,21 +527,19 @@ jt_ptl_add_autoconnect (int argc, char **argv)
                         }
         }
 
-        PORTAL_IOC_INIT (data);
-        data.ioc_nal     = g_nal;
-        data.ioc_nal_cmd = NAL_CMD_ADD_AUTOCONN;
-        data.ioc_nid     = nid;
-        data.ioc_id      = ip;
-        data.ioc_misc    = port;
+        PCFG_INIT(pcfg, NAL_CMD_ADD_AUTOCONN);
+        pcfg.pcfg_nid     = nid;
+        pcfg.pcfg_id      = ip;
+        pcfg.pcfg_misc    = port;
         /* only passing one buffer size! */
-        data.ioc_size    = MAX (g_socket_rxmem, g_socket_txmem);
-        data.ioc_flags   = (g_socket_nonagle ? 0x01 : 0) |
+        pcfg.pcfg_size    = MAX (g_socket_rxmem, g_socket_txmem);
+        pcfg.pcfg_flags   = (g_socket_nonagle ? 0x01 : 0) |
                            (xchange_nids     ? 0x02 : 0) |
                            (irq_affinity     ? 0x04 : 0) |
                            (share            ? 0x08 : 0) |
                            (eager            ? 0x10 : 0);
 
-        rc = l_ioctl (PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
+        rc = pcfg_ioctl (&pcfg);
         if (rc != 0) {
                 fprintf (stderr, "failed to enable autoconnect: %s\n",
                          strerror (errno));
@@ -524,7 +552,7 @@ jt_ptl_add_autoconnect (int argc, char **argv)
 int 
 jt_ptl_del_autoconnect (int argc, char **argv)
 {
-        struct portal_ioctl_data data;
+        struct portals_cfg       pcfg;
         ptl_nid_t                nid = PTL_NID_ANY;
         __u32                    ip  = 0;
         int                      share = 0;
@@ -570,15 +598,13 @@ jt_ptl_del_autoconnect (int argc, char **argv)
                         }
         }
 
-        PORTAL_IOC_INIT (data);
-        data.ioc_nal     = g_nal;
-        data.ioc_nal_cmd = NAL_CMD_DEL_AUTOCONN;
-        data.ioc_nid     = nid;
-        data.ioc_id      = ip;
-        data.ioc_flags   = (share     ? 1 : 0) |
+        PCFG_INIT(pcfg, NAL_CMD_DEL_AUTOCONN);
+        pcfg.pcfg_nid     = nid;
+        pcfg.pcfg_id      = ip;
+        pcfg.pcfg_flags   = (share     ? 1 : 0) |
                            (keep_conn ? 2 : 0);
-        
-        rc = l_ioctl (PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
+
+        rc = pcfg_ioctl (&pcfg);
         if (rc != 0) {
                 fprintf (stderr, "failed to remove autoconnect route: %s\n",
                          strerror (errno));
@@ -591,7 +617,7 @@ jt_ptl_del_autoconnect (int argc, char **argv)
 int 
 jt_ptl_print_connections (int argc, char **argv)
 {
-        struct portal_ioctl_data data;
+        struct portals_cfg       pcfg;
         char                     buffer[64];
         int                      index;
         int                      rc;
@@ -600,19 +626,17 @@ jt_ptl_print_connections (int argc, char **argv)
                 return -1;
 
         for (index = 0;;index++) {
-                PORTAL_IOC_INIT (data);
-                data.ioc_nal     = g_nal;
-                data.ioc_nal_cmd = NAL_CMD_GET_CONN;
-                data.ioc_count   = index;
+                PCFG_INIT (pcfg,  NAL_CMD_GET_CONN);
+                pcfg.pcfg_count   = index;
                 
-                rc = l_ioctl (PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
+                rc = pcfg_ioctl (&pcfg);
                 if (rc != 0)
                         break;
 
                 printf (LPX64"@%s:%d\n",
-                        data.ioc_nid, 
-                        ptl_ipaddr_2_str (data.ioc_id, buffer),
-                        data.ioc_misc);
+                        pcfg.pcfg_nid, 
+                        ptl_ipaddr_2_str (pcfg.pcfg_id, buffer),
+                        pcfg.pcfg_misc);
         }
 
         if (index == 0)
@@ -696,6 +720,7 @@ int jt_ptl_connect(int argc, char **argv)
 {
         ptl_nid_t peer_nid;
         struct portal_ioctl_data data;
+        struct portals_cfg pcfg;
         struct sockaddr_in srvaddr;
         __u32 ipaddr;
         char *flag;
@@ -820,14 +845,12 @@ int jt_ptl_connect(int argc, char **argv)
         printf("Connected host: %s NID "LPX64" snd: %d rcv: %d nagle: %s\n", argv[1],
                peer_nid, txmem, rxmem, nonagle ? "Disabled" : "Enabled");
 
-        PORTAL_IOC_INIT(data);
-        data.ioc_fd = fd;
-        data.ioc_nal = g_nal;
-        data.ioc_nal_cmd = NAL_CMD_REGISTER_PEER_FD;
-        data.ioc_nid = peer_nid;
-        data.ioc_flags = bind_irq;
+        PCFG_INIT(pcfg, NAL_CMD_REGISTER_PEER_FD);
+        pcfg.pcfg_fd = fd;
+        pcfg.pcfg_nid = peer_nid;
+        pcfg.pcfg_flags = bind_irq;
 
-        rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
+        rc = pcfg_ioctl(&pcfg);
         if (rc) {
                 fprintf(stderr, "failed to register fd with portals: %s\n", 
                         strerror(errno));
@@ -846,7 +869,7 @@ int jt_ptl_connect(int argc, char **argv)
 
 int jt_ptl_disconnect(int argc, char **argv)
 {
-        struct portal_ioctl_data data;
+        struct portals_cfg        pcfg;
         ptl_nid_t                nid = PTL_NID_ANY;
         __u32                    ipaddr = 0;
         int                      rc;
@@ -871,13 +894,11 @@ int jt_ptl_disconnect(int argc, char **argv)
                 return -1;
         }
 
-        PORTAL_IOC_INIT(data);
-        data.ioc_nal     = g_nal;
-        data.ioc_nal_cmd = NAL_CMD_CLOSE_CONNECTION;
-        data.ioc_nid     = nid;
-        data.ioc_id      = ipaddr;
+        PCFG_INIT(pcfg, NAL_CMD_CLOSE_CONNECTION);
+        pcfg.pcfg_nid     = nid;
+        pcfg.pcfg_id      = ipaddr;
         
-        rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
+        rc = pcfg_ioctl(&pcfg);
         if (rc) {
                 fprintf(stderr, "failed to remove connection: %s\n",
                         strerror(errno));
@@ -889,7 +910,7 @@ int jt_ptl_disconnect(int argc, char **argv)
 
 int jt_ptl_push_connection (int argc, char **argv)
 {
-        struct portal_ioctl_data data;
+        struct portals_cfg        pcfg;
         int                      rc;
         ptl_nid_t                nid = PTL_NID_ANY;
         __u32                    ipaddr = 0;
@@ -913,13 +934,11 @@ int jt_ptl_push_connection (int argc, char **argv)
                 fprintf(stderr, "Can't parse ipaddr: %s\n", argv[2]);
         }
 
-        PORTAL_IOC_INIT(data);
-        data.ioc_nal     = g_nal;
-        data.ioc_nal_cmd = NAL_CMD_PUSH_CONNECTION;
-        data.ioc_nid     = nid;
-        data.ioc_id      = ipaddr;
-
-        rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
+        PCFG_INIT(pcfg, NAL_CMD_PUSH_CONNECTION);
+        pcfg.pcfg_nid     = nid;
+        pcfg.pcfg_id      = ipaddr;
+        
+        rc = pcfg_ioctl(&pcfg);
         if (rc) {
                 fprintf(stderr, "failed to push connection: %s\n",
                         strerror(errno));
@@ -932,7 +951,7 @@ int jt_ptl_push_connection (int argc, char **argv)
 int 
 jt_ptl_print_active_txs (int argc, char **argv)
 {
-        struct portal_ioctl_data data;
+        struct portals_cfg        pcfg;
         int                      index;
         int                      rc;
 
@@ -940,28 +959,26 @@ jt_ptl_print_active_txs (int argc, char **argv)
                 return -1;
 
         for (index = 0;;index++) {
-                PORTAL_IOC_INIT (data);
-                data.ioc_nal     = g_nal;
-                data.ioc_nal_cmd = NAL_CMD_GET_TXDESC;
-                data.ioc_count   = index;
-                
-                rc = l_ioctl (PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
+                PCFG_INIT(pcfg, NAL_CMD_GET_TXDESC);
+                pcfg.pcfg_count   = index;
+        
+                rc = pcfg_ioctl(&pcfg);
                 if (rc != 0)
                         break;
 
                 printf ("%p: %5s payload %6d bytes to "LPX64" via "LPX64" by pid %6d: %s, %s, state %d\n",
-                        data.ioc_pbuf1,
-                        data.ioc_count == PTL_MSG_ACK ? "ACK" :
-                        data.ioc_count == PTL_MSG_PUT ? "PUT" :
-                        data.ioc_count == PTL_MSG_GET ? "GET" :
-                        data.ioc_count == PTL_MSG_REPLY ? "REPLY" : "<wierd message>",
-                        data.ioc_size,
-                        data.ioc_nid,
-                        data.ioc_nid2,
-                        data.ioc_misc,
-                        (data.ioc_flags & 1) ? "delayed" : "immediate",
-                        (data.ioc_flags & 2) ? "nblk"    : "normal",
-                        data.ioc_flags >> 2);
+                        pcfg.pcfg_pbuf1,
+                        pcfg.pcfg_count == PTL_MSG_ACK ? "ACK" :
+                        pcfg.pcfg_count == PTL_MSG_PUT ? "PUT" :
+                        pcfg.pcfg_count == PTL_MSG_GET ? "GET" :
+                        pcfg.pcfg_count == PTL_MSG_REPLY ? "REPLY" : "<wierd message>",
+                        pcfg.pcfg_size,
+                        pcfg.pcfg_nid,
+                        pcfg.pcfg_nid2,
+                        pcfg.pcfg_misc,
+                        (pcfg.pcfg_flags & 1) ? "delayed" : "immediate",
+                        (pcfg.pcfg_flags & 2) ? "nblk"    : "normal",
+                        pcfg.pcfg_flags >> 2);
         }
 
         if (index == 0)
@@ -1054,7 +1071,7 @@ int jt_ptl_mynid(int argc, char **argv)
         int rc;
         char hostname[1024];
         char *nidstr;
-        struct portal_ioctl_data data;
+        struct portals_cfg pcfg;
         ptl_nid_t mynid;
         
         if (argc > 2) {
@@ -1082,12 +1099,10 @@ int jt_ptl_mynid(int argc, char **argv)
                 return -1;
         }
         
-        PORTAL_IOC_INIT(data);
-        data.ioc_nid = mynid;
-        data.ioc_nal = g_nal;
-        data.ioc_nal_cmd = NAL_CMD_REGISTER_MYNID;
+        PCFG_INIT(pcfg, NAL_CMD_REGISTER_MYNID);
+        pcfg.pcfg_nid = mynid;
 
-        rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
+        rc = pcfg_ioctl(&pcfg);
         if (rc < 0)
                 fprintf(stderr, "setting my NID failed: %s\n",
                        strerror(errno));
diff --git a/lustre/kernel_patches/patches/2.6.0-test6-mm4.patch b/lustre/kernel_patches/patches/2.6.0-test6-mm4.patch
new file mode 100644 (file)
index 0000000..20d5af9
--- /dev/null
@@ -0,0 +1,113290 @@
+--- linux-2.6.0-test6/arch/alpha/Kconfig       2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/alpha/Kconfig      2003-10-05 00:36:11.000000000 -0700
+@@ -471,21 +471,6 @@ config EISA
+       bool
+       depends on ALPHA_GENERIC || ALPHA_JENSEN || ALPHA_ALCOR || ALPHA_MIKASA || ALPHA_SABLE || ALPHA_LYNX || ALPHA_NORITAKE || ALPHA_RAWHIDE
+       default y
+-      ---help---
+-        The Extended Industry Standard Architecture (EISA) bus was
+-        developed as an open alternative to the IBM MicroChannel bus.
+-
+-        The EISA bus provided some of the features of the IBM MicroChannel
+-        bus while maintaining backward compatibility with cards made for
+-        the older ISA bus.  The EISA bus saw limited use between 1988 and
+-        1995 when it was made obsolete by the PCI bus.
+-
+-        Say Y here if you are building a kernel for an EISA-based machine.
+-
+-        Otherwise, say N.
+-
+-config EISA_ALWAYS
+-      def_bool EISA
+ config SMP
+       bool "Symmetric multi-processing support"
+--- linux-2.6.0-test6/arch/alpha/kernel/core_irongate.c        2003-06-14 12:18:25.000000000 -0700
++++ 25/arch/alpha/kernel/core_irongate.c       2003-10-05 00:33:23.000000000 -0700
+@@ -391,7 +391,7 @@ irongate_ioremap(unsigned long addr, uns
+               cur_gatt = phys_to_virt(GET_GATT(baddr) & ~1);
+               pte = cur_gatt[GET_GATT_OFF(baddr)] & ~1;
+-              if (__alpha_remap_area_pages(VMALLOC_VMADDR(vaddr), 
++              if (__alpha_remap_area_pages(vaddr,
+                                            pte, PAGE_SIZE, 0)) {
+                       printk("AGP ioremap: FAILED to map...\n");
+                       vfree(area->addr);
+--- linux-2.6.0-test6/arch/alpha/kernel/core_marvel.c  2003-08-22 19:23:39.000000000 -0700
++++ 25/arch/alpha/kernel/core_marvel.c 2003-10-05 00:33:23.000000000 -0700
+@@ -696,7 +696,7 @@ marvel_ioremap(unsigned long addr, unsig
+                       }
+                       pfn >>= 1;      /* make it a true pfn */
+                       
+-                      if (__alpha_remap_area_pages(VMALLOC_VMADDR(vaddr), 
++                      if (__alpha_remap_area_pages(vaddr,
+                                                    pfn << PAGE_SHIFT, 
+                                                    PAGE_SIZE, 0)) {
+                               printk("FAILED to map...\n");
+--- linux-2.6.0-test6/arch/alpha/kernel/core_titan.c   2003-09-08 13:58:55.000000000 -0700
++++ 25/arch/alpha/kernel/core_titan.c  2003-10-05 00:33:23.000000000 -0700
+@@ -534,7 +534,7 @@ titan_ioremap(unsigned long addr, unsign
+                       }
+                       pfn >>= 1;      /* make it a true pfn */
+                       
+-                      if (__alpha_remap_area_pages(VMALLOC_VMADDR(vaddr), 
++                      if (__alpha_remap_area_pages(vaddr,
+                                                    pfn << PAGE_SHIFT, 
+                                                    PAGE_SIZE, 0)) {
+                               printk("FAILED to map...\n");
+--- linux-2.6.0-test6/arch/alpha/kernel/setup.c        2003-08-22 19:23:39.000000000 -0700
++++ 25/arch/alpha/kernel/setup.c       2003-10-05 00:36:11.000000000 -0700
+@@ -33,6 +33,7 @@
+ #include <linux/seq_file.h>
+ #include <linux/root_dev.h>
+ #include <linux/initrd.h>
++#include <linux/eisa.h>
+ #ifdef CONFIG_MAGIC_SYSRQ
+ #include <linux/sysrq.h>
+ #include <linux/reboot.h>
+@@ -680,6 +681,11 @@ setup_arch(char **cmdline_p)
+       /* Default root filesystem to sda2.  */
+       ROOT_DEV = Root_SDA2;
++#ifdef CONFIG_EISA
++      /* FIXME:  only set this when we actually have EISA in this box? */
++      EISA_bus = 1;
++#endif
++
+       /*
+        * Check ASN in HWRPB for validity, report if bad.
+        * FIXME: how was this failing?  Should we trust it instead,
+@@ -1203,7 +1209,7 @@ show_cpuinfo(struct seq_file *f, void *s
+                      platform_string(), nr_processors);
+ #ifdef CONFIG_SMP
+-      seq_printf(f, "cpus active\t\t: %d\n"
++      seq_printf(f, "cpus active\t\t: %ld\n"
+                     "cpu active mask\t\t: %016lx\n",
+                      num_online_cpus(), cpu_present_mask);
+ #endif
+--- linux-2.6.0-test6/arch/alpha/kernel/smp.c  2003-08-22 19:23:40.000000000 -0700
++++ 25/arch/alpha/kernel/smp.c 2003-10-05 00:33:23.000000000 -0700
+@@ -597,7 +597,7 @@ smp_cpus_done(unsigned int max_cpus)
+               if (cpu_online(cpu))
+                       bogosum += cpu_data[cpu].loops_per_jiffy;
+       
+-      printk(KERN_INFO "SMP: Total of %d processors activated "
++      printk(KERN_INFO "SMP: Total of %ld processors activated "
+              "(%lu.%02lu BogoMIPS).\n",
+              num_online_cpus(), 
+              (bogosum + 2500) / (500000/HZ),
+--- linux-2.6.0-test6/arch/alpha/kernel/time.c 2003-08-08 22:55:10.000000000 -0700
++++ 25/arch/alpha/kernel/time.c        2003-10-05 00:33:23.000000000 -0700
+@@ -89,6 +89,16 @@ static inline __u32 rpcc(void)
+     return result;
+ }
++/*
++ * Scheduler clock - returns current time in nanosec units.
++ *
++ * Copied from ARM code for expediency... ;-}
++ */
++unsigned long long sched_clock(void)
++{
++        return (unsigned long long)jiffies * (1000000000 / HZ);
++}
++
+ /*
+  * timer_interrupt() needs to keep up the real-time clock,
+@@ -239,8 +249,9 @@ validate_cc_value(unsigned long cc)
+  * arch/i386/time.c.
+  */
+-#define CALIBRATE_LATCH       (52 * LATCH)
+-#define CALIBRATE_TIME        (52 * 1000020 / HZ)
++#define PIC_TICK_RATE 1193180UL
++#define CALIBRATE_LATCH       0xffff
++#define TIMEOUT_COUNT 0x100000
+ static unsigned long __init
+ calibrate_cc_with_pic(void)
+@@ -263,19 +274,15 @@ calibrate_cc_with_pic(void)
+       cc = rpcc();
+       do {
+-        count+=100; /* by 1 takes too long to timeout from 0 */
+-      } while ((inb(0x61) & 0x20) == 0 && count > 0);
++              count++;
++      } while ((inb(0x61) & 0x20) == 0 && count < TIMEOUT_COUNT);
+       cc = rpcc() - cc;
+       /* Error: ECTCNEVERSET or ECPUTOOFAST.  */
+-      if (count <= 100)
+-              return 0;
+-
+-      /* Error: ECPUTOOSLOW.  */
+-      if (cc <= CALIBRATE_TIME)
++      if (count <= 1 || count == TIMEOUT_COUNT)
+               return 0;
+-      return (cc * 1000000UL) / CALIBRATE_TIME;
++      return ((long)cc * PIC_TICK_RATE) / (CALIBRATE_LATCH + 1);
+ }
+ /* The Linux interpretation of the CMOS clock register contents:
+--- linux-2.6.0-test6/arch/alpha/mm/init.c     2003-07-27 12:14:38.000000000 -0700
++++ 25/arch/alpha/mm/init.c    2003-10-05 00:33:23.000000000 -0700
+@@ -210,7 +210,8 @@ callback_init(void * kernel_end)
+       /* Allocate one PGD and one PMD.  In the case of SRM, we'll need
+          these to actually remap the console.  There is an assumption
+          here that only one of each is needed, and this allows for 8MB.
+-         Currently (late 1999), big consoles are still under 4MB.
++         On systems with larger consoles, additional pages will be
++         allocated as needed during the mapping process.
+          In the case of not SRM, but not CONFIG_ALPHA_LARGE_VMALLOC,
+          we need to allocate the PGD we use for vmalloc before we start
+@@ -237,6 +238,15 @@ callback_init(void * kernel_end)
+                       unsigned long pfn = crb->map[i].pa >> PAGE_SHIFT;
+                       crb->map[i].va = vaddr;
+                       for (j = 0; j < crb->map[i].count; ++j) {
++                              /* Newer console's (especially on larger
++                                 systems) may require more pages of
++                                 PTEs. Grab additional pages as needed. */
++                              if (pmd != pmd_offset(pgd, vaddr)) {
++                                      memset(kernel_end, 0, PAGE_SIZE);
++                                      pmd = pmd_offset(pgd, vaddr);
++                                      pmd_set(pmd, (pte_t *)kernel_end);
++                                      kernel_end += PAGE_SIZE;
++                              }
+                               set_pte(pte_offset_kernel(pmd, vaddr),
+                                       pfn_pte(pfn, PAGE_KERNEL));
+                               pfn++;
+--- linux-2.6.0-test6/arch/arm/boot/compressed/head.S  2003-06-14 12:18:33.000000000 -0700
++++ 25/arch/arm/boot/compressed/head.S 2003-10-05 00:33:23.000000000 -0700
+@@ -477,6 +477,12 @@ proc_types:
+ @             b       __arm6_cache_off
+ @             b       __armv3_cache_flush
++              .word   0x00000000              @ old ARM ID
++              .word   0x0000f000
++              mov     pc, lr
++              mov     pc, lr
++              mov     pc, lr
++
+               .word   0x41007000              @ ARM7/710
+               .word   0xfff8fe00
+               b       __arm7_cache_off
+@@ -489,6 +495,14 @@ proc_types:
+               b       __armv4_cache_off
+               mov     pc, lr
++              .word   0x00007000              @ ARM7 IDs
++              .word   0x0000f000
++              mov     pc, lr
++              mov     pc, lr
++              mov     pc, lr
++
++              @ Everything from here on will be the new ID system.
++
+               .word   0x41129200              @ ARM920T
+               .word   0xff00fff0
+               b       __armv4_cache_on
+@@ -507,8 +521,16 @@ proc_types:
+               b       __armv4_cache_off
+               b       __armv4_cache_flush
+-              .word   0x69050000              @ xscale
+-              .word   0xffff0000
++              @ These match on the architecture ID
++
++              .word   0x00050000              @ ARMv5TE
++              .word   0x000f0000
++              b       __armv4_cache_on
++              b       __armv4_cache_off
++              b       __armv4_cache_flush
++
++              .word   0x00060000              @ ARMv5TEJ
++              .word   0x000f0000
+               b       __armv4_cache_on
+               b       __armv4_cache_off
+               b       __armv4_cache_flush
+--- linux-2.6.0-test6/arch/arm/Kconfig 2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/arm/Kconfig        2003-10-05 00:33:23.000000000 -0700
+@@ -239,7 +239,7 @@ config DISCONTIGMEM
+ # Now handle the bus types
+ config PCI
+-      bool "PCI support" if ARCH_INTEGRATOR
++      bool "PCI support" if ARCH_INTEGRATOR_AP
+       default y if ARCH_FTVPCI || ARCH_SHARK || FOOTBRIDGE_HOST || ARCH_IOP3XX
+       help
+         Find out whether you have a PCI motherboard. PCI is the name of a
+@@ -645,8 +645,6 @@ source "drivers/misc/Kconfig"
+ source "drivers/usb/Kconfig"
+-source "net/bluetooth/Kconfig"
+-
+ menu "Kernel hacking"
+--- linux-2.6.0-test6/arch/arm/kernel/apm.c    2003-09-08 13:58:55.000000000 -0700
++++ 25/arch/arm/kernel/apm.c   2003-10-05 00:33:23.000000000 -0700
+@@ -179,13 +179,10 @@ static void queue_event(apm_event_t even
+       wake_up_interruptible(&apm_waitqueue);
+ }
+-/* defined in pm.c */
+-extern int suspend(void);
+-
+ static int apm_suspend(void)
+ {
+       struct list_head *l;
+-      int err = suspend();
++      int err = pm_suspend(PM_SUSPEND_MEM);
+       /*
+        * Anyone on the APM queues will think we're still suspended.
+--- linux-2.6.0-test6/arch/arm/kernel/entry-armv.S     2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/arm/kernel/entry-armv.S    2003-10-05 00:33:23.000000000 -0700
+@@ -439,20 +439,25 @@ ENTRY(soft_irq_mask)
+               .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
+ /* FIXME: should not be using soo many LDRs here */
+-              ldr     \irqnr, =IO_ADDRESS(INTEGRATOR_IC_BASE)
+-              ldr     \irqstat, [\irqnr, #IRQ_STATUS]         @ get masked status
+-              ldr     \irqnr, =IO_ADDRESS(INTEGRATOR_HDR_BASE)
+-              ldr     \irqnr, [\irqnr, #(INTEGRATOR_HDR_IC_OFFSET+IRQ_STATUS)]
+-              orr     \irqstat, \irqstat, \irqnr, lsl #INTEGRATOR_CM_INT0
++              ldr     \base, =IO_ADDRESS(INTEGRATOR_IC_BASE)
++              mov     \irqnr, #IRQ_PIC_START
++              ldr     \irqstat, [\base, #IRQ_STATUS]          @ get masked status
++              ldr     \base, =IO_ADDRESS(INTEGRATOR_HDR_BASE)
++              teq     \irqstat, #0
++              ldreq   \irqstat, [\base, #(INTEGRATOR_HDR_IC_OFFSET+IRQ_STATUS)]
++              moveq   \irqnr, #IRQ_CIC_START
+-              mov     \irqnr, #0
+-1001:         tst     \irqstat, #1
++1001:         tst     \irqstat, #15
+               bne     1002f
++              add     \irqnr, \irqnr, #4
++              movs    \irqstat, \irqstat, lsr #4
++              bne     1001b
++1002:         tst     \irqstat, #1
++              bne     1003f
+               add     \irqnr, \irqnr, #1
+-              mov     \irqstat, \irqstat, lsr #1
+-              cmp     \irqnr, #22
+-              bcc     1001b
+-1002:         /* EQ will be set if we reach 22 */
++              movs    \irqstat, \irqstat, lsr #1
++              bne     1002b
++1003:         /* EQ will be set if no irqs pending */
+               .endm
+               .macro  irq_prio_table
+--- linux-2.6.0-test6/arch/arm/kernel/pm.c     2003-09-08 13:58:55.000000000 -0700
++++ 25/arch/arm/kernel/pm.c    2003-10-05 00:33:23.000000000 -0700
+@@ -9,68 +9,18 @@
+  *  sleep.
+  */
+ #include <linux/config.h>
++#include <linux/init.h>
++#include <linux/sysctl.h>
+ #include <linux/pm.h>
+-#include <linux/device.h>
+-#include <linux/sysdev.h>
+ #include <linux/errno.h>
+ #include <linux/sched.h>
+-#include <asm/leds.h>
+-#include <asm/system.h>
+-
+-/*
+- * Tell the linker that pm_do_suspend may not be present.
+- */
+-extern int pm_do_suspend(void) __attribute__((weak));
+-
+-int suspend(void)
+-{
+-      int ret;
+-
+-      if (!pm_do_suspend)
+-              return -ENOSYS;
+-
+-      /*
+-       * Suspend "legacy" devices.
+-       */
+-      ret = pm_send_all(PM_SUSPEND, (void *)3);
+-      if (ret != 0)
+-              goto out;
+-
+-      ret = device_suspend(3);
+-      if (ret)
+-              goto resume_legacy;
+-
+-      local_irq_disable();
+-      leds_event(led_stop);
+-
+-      sysdev_suspend(3);
+-
+-      ret = pm_do_suspend();
+-
+-      sysdev_resume();
+-
+-      leds_event(led_start);
+-      local_irq_enable();
+-
+-      device_resume();
+-
+- resume_legacy:
+-      pm_send_all(PM_RESUME, (void *)0);
+-
+- out:
+-      return ret;
+-}
+-
+ #ifdef CONFIG_SYSCTL
+ /*
+  * We really want this to die.  It's a disgusting hack using unallocated
+  * sysctl numbers.  We should be using a real interface.
+  */
+-#include <linux/init.h>
+-#include <linux/sysctl.h>
+-
+ static int
+ pm_sysctl_proc_handler(ctl_table *ctl, int write, struct file *filp,
+                      void *buffer, size_t *lenp)
+@@ -79,7 +29,7 @@ pm_sysctl_proc_handler(ctl_table *ctl, i
+       printk("PM: task %s (pid %d) uses deprecated sysctl PM interface\n",
+               current->comm, current->pid);
+       if (write)
+-              ret = suspend();
++              ret = pm_suspend(PM_SUSPEND_MEM);
+       return ret;
+ }
+--- linux-2.6.0-test6/arch/arm/kernel/process.c        2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/arm/kernel/process.c       2003-10-05 00:33:23.000000000 -0700
+@@ -117,12 +117,10 @@ __setup("reboot=", reboot_setup);
+ void machine_halt(void)
+ {
+-      leds_event(led_halted);
+ }
+ void machine_power_off(void)
+ {
+-      leds_event(led_halted);
+       if (pm_power_off)
+               pm_power_off();
+ }
+--- linux-2.6.0-test6/arch/arm/kernel/setup.c  2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/arm/kernel/setup.c 2003-10-05 00:33:23.000000000 -0700
+@@ -182,7 +182,7 @@ static const char *proc_arch[] = {
+       "5",
+       "5T",
+       "5TE",
+-      "?(8)",
++      "5TEJ",
+       "?(9)",
+       "?(10)",
+       "?(11)",
+--- linux-2.6.0-test6/arch/arm/kernel/signal.c 2003-06-14 12:17:56.000000000 -0700
++++ 25/arch/arm/kernel/signal.c        2003-10-05 00:33:23.000000000 -0700
+@@ -21,6 +21,7 @@
+ #include <linux/tty.h>
+ #include <linux/binfmts.h>
+ #include <linux/elf.h>
++#include <linux/suspend.h>
+ #include <asm/pgalloc.h>
+ #include <asm/ucontext.h>
+@@ -539,6 +540,11 @@ static int do_signal(sigset_t *oldset, s
+       if (!user_mode(regs))
+               return 0;
++      if (current->flags & PF_FREEZE) {
++              refrigerator(0);
++              goto no_signal;
++      }
++
+       if (current->ptrace & PT_SINGLESTEP)
+               ptrace_cancel_bpt(current);
+@@ -550,6 +556,7 @@ static int do_signal(sigset_t *oldset, s
+               return 1;
+       }
++ no_signal:
+       /*
+        * No signal to deliver to the process - restart the syscall.
+        */
+--- linux-2.6.0-test6/arch/arm/kernel/time.c   2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/arm/kernel/time.c  2003-10-05 00:33:23.000000000 -0700
+@@ -26,6 +26,7 @@
+ #include <linux/timex.h>
+ #include <linux/errno.h>
+ #include <linux/profile.h>
++#include <linux/sysdev.h>
+ #include <asm/hardware.h>
+ #include <asm/io.h>
+@@ -72,8 +73,6 @@ unsigned long (*gettimeoffset)(void) = d
+  */
+ unsigned long long sched_clock(void)
+ {
+-      unsigned long long this_offset;
+-
+       return (unsigned long long)jiffies * (1000000000 / HZ);
+ }
+@@ -137,6 +136,47 @@ static void dummy_leds_event(led_event_t
+ void (*leds_event)(led_event_t) = dummy_leds_event;
++static int leds_suspend(struct sys_device *dev, u32 state)
++{
++      leds_event(led_stop);
++      return 0;
++}
++
++static int leds_resume(struct sys_device *dev)
++{
++      leds_event(led_start);
++      return 0;
++}
++
++static int leds_shutdown(struct sys_device *dev)
++{
++      leds_event(led_halted);
++      return 0;
++}
++
++static struct sysdev_class leds_sysclass = {
++      set_kset_name("leds"),
++      .shutdown       = leds_shutdown,
++      .suspend        = leds_suspend,
++      .resume         = leds_resume,
++};
++
++static struct sys_device leds_device = {
++      .id             = 0,
++      .cls            = &leds_sysclass,
++};
++
++static int __init leds_init(void)
++{
++      int ret;
++      ret = sysdev_class_register(&leds_sysclass);
++      if (ret == 0)
++              ret = sys_device_register(&leds_device);
++      return ret;
++}
++
++device_initcall(leds_init);
++
+ EXPORT_SYMBOL(leds_event);
+ #endif
+--- linux-2.6.0-test6/arch/arm/kernel/traps.c  2003-08-22 19:23:40.000000000 -0700
++++ 25/arch/arm/kernel/traps.c 2003-10-05 00:33:23.000000000 -0700
+@@ -212,10 +212,10 @@ NORET_TYPE void die(const char *str, str
+       printk("CPU: %d\n", smp_processor_id());
+       show_regs(regs);
+       printk("Process %s (pid: %d, stack limit = 0x%p)\n",
+-              current->comm, current->pid, tsk->thread_info + 1);
++              tsk->comm, tsk->pid, tsk->thread_info + 1);
+       if (!user_mode(regs) || in_interrupt()) {
+-              dump_mem("Stack: ", (unsigned long)(regs + 1), 8192+(unsigned long)tsk->thread_info);
++              dump_mem("Stack: ", regs->ARM_sp, 8192+(unsigned long)tsk->thread_info);
+               dump_backtrace(regs, tsk);
+               dump_instr(regs);
+       }
+--- linux-2.6.0-test6/arch/arm/lib/io-readsl-armv4.S   2003-06-14 12:18:30.000000000 -0700
++++ 25/arch/arm/lib/io-readsl-armv4.S  2003-10-05 00:33:23.000000000 -0700
+@@ -9,7 +9,6 @@
+  */
+ #include <linux/linkage.h>
+ #include <asm/assembler.h>
+-#include <asm/hardware.h>
+ /*
+  * Note that some reads can be aligned on half-word boundaries.
+@@ -31,6 +30,10 @@ ENTRY(__raw_readsl)
+               blt     4f
+               bgt     6f
++#ifndef       __ARMEB__
++
++              /* little endian code */
++
+               strh    ip, [r1], #2
+               mov     ip, ip, lsr #16
+ 3:            subs    r2, r2, #1
+@@ -68,3 +71,48 @@ ENTRY(__raw_readsl)
+               strb    ip, [r1]
+               mov     pc, lr
++#else
++
++              /* big endian code */
++
++
++              mov     r3, ip, lsr #16
++              strh    r3, [r1], #2
++3:            mov     r3, ip, lsl #16
++              subs    r2, r2, #1
++              ldrne   ip, [r0]
++              orrne   r3, r3, ip, lsr #16
++              strne   r3, [r1], #4
++              bne     3b
++              strh    ip, [r1], #2
++              mov     pc, lr
++
++4:            mov     r3, ip, lsr #24
++              strb    r3, [r1], #1
++              mov     r3, ip, lsr #8
++              strh    r3, [r1], #2
++5:            mov     r3, ip, lsl #24
++              subs    r2, r2, #1
++              ldrne   ip, [r0]
++              orrne   r3, r3, ip, lsr #8
++              strne   r3, [r1], #4
++              bne     5b
++              strb    ip, [r1], #1
++              mov     pc, lr
++
++6:            mov     r3, ip, lsr #24
++              strb    r3, [r1], #1
++7:            mov     r3, ip, lsl #8
++              subs    r2, r2, #1
++              ldrne   ip, [r0]
++              orrne   r3, r3, ip, lsr #24
++              strne   r3, [r1], #4
++              bne     7b
++              mov     r3, ip, lsr #8
++              strh    r3, [r1], #2
++              strb    ip, [r1], #1
++              mov     pc, lr
++
++#endif
++
++
+--- linux-2.6.0-test6/arch/arm/lib/io-readsw-armv4.S   2003-06-14 12:18:23.000000000 -0700
++++ 25/arch/arm/lib/io-readsw-armv4.S  2003-10-05 00:33:23.000000000 -0700
+@@ -9,7 +9,14 @@
+  */
+ #include <linux/linkage.h>
+ #include <asm/assembler.h>
+-#include <asm/hardware.h>
++
++              .macro  pack, rd, hw1, hw2
++#ifndef __ARMEB__
++              orr     \rd, \hw1, \hw2, lsl #16
++#else
++              orr     \rd, \hw2, \hw1, lsl #16
++#endif
++              .endm
+ .insw_bad_alignment:
+               adr     r0, .insw_bad_align_msg
+@@ -41,19 +48,19 @@ ENTRY(__raw_readsw)
+ .insw_8_lp:   ldrh    r3, [r0]
+               ldrh    r4, [r0]
+-              orr     r3, r3, r4, lsl #16
++              pack    r3, r3, r4
+               ldrh    r4, [r0]
+               ldrh    r5, [r0]
+-              orr     r4, r4, r5, lsl #16
++              pack    r4, r4, r5
+               ldrh    r5, [r0]
+               ldrh    ip, [r0]
+-              orr     r5, r5, ip, lsl #16
++              pack    r5, r5, ip
+               ldrh    ip, [r0]
+               ldrh    lr, [r0]
+-              orr     ip, ip, lr, lsl #16
++              pack    ip, ip, lr
+               stmia   r1!, {r3 - r5, ip}
+@@ -68,11 +75,11 @@ ENTRY(__raw_readsw)
+               ldrh    r3, [r0]
+               ldrh    r4, [r0]
+-              orr     r3, r3, r4, lsl #16
++              pack    r3, r3, r4
+               ldrh    r4, [r0]
+               ldrh    ip, [r0]
+-              orr     r4, r4, ip, lsl #16
++              pack    r4, r4, ip
+               stmia   r1!, {r3, r4}
+@@ -81,7 +88,7 @@ ENTRY(__raw_readsw)
+               ldrh    r3, [r0]
+               ldrh    ip, [r0]
+-              orr     r3, r3, ip, lsl #16
++              pack    r3, r3, ip
+               str     r3, [r1], #4
+--- linux-2.6.0-test6/arch/arm/lib/io-writesw-armv4.S  2003-06-14 12:18:34.000000000 -0700
++++ 25/arch/arm/lib/io-writesw-armv4.S 2003-10-05 00:33:23.000000000 -0700
+@@ -9,7 +9,18 @@
+  */
+ #include <linux/linkage.h>
+ #include <asm/assembler.h>
+-#include <asm/hardware.h>
++
++              .macro  outword, rd
++#ifndef __ARMEB__
++              strh    \rd, [r0]
++              mov     \rd, \rd, lsr #16
++              strh    \rd, [r0]
++#else
++              mov     lr, \rd, lsr #16
++              strh    lr, [r0]
++              strh    \rd, [r0]
++#endif
++              .endm
+ .outsw_bad_alignment:
+               adr     r0, .outsw_bad_align_msg
+@@ -40,20 +51,10 @@ ENTRY(__raw_writesw)
+               bmi     .no_outsw_8
+ .outsw_8_lp:  ldmia   r1!, {r3, r4, r5, ip}
+-
+-              strh    r3, [r0]
+-              mov     r3, r3, lsr #16
+-              strh    r3, [r0]
+-              strh    r4, [r0]
+-              mov     r4, r4, lsr #16
+-              strh    r4, [r0]
+-              strh    r5, [r0]
+-              mov     r5, r5, lsr #16
+-              strh    r5, [r0]
+-              strh    ip, [r0]
+-              mov     ip, ip, lsr #16
+-              strh    ip, [r0]
+-
++              outword r3
++              outword r4
++              outword r5
++              outword ip
+               subs    r2, r2, #8
+               bpl     .outsw_8_lp
+@@ -64,20 +65,14 @@ ENTRY(__raw_writesw)
+               beq     .no_outsw_4
+               ldmia   r1!, {r3, ip}
+-              strh    r3, [r0]
+-              mov     r3, r3, lsr #16
+-              strh    r3, [r0]
+-              strh    ip, [r0]
+-              mov     ip, ip, lsr #16
+-              strh    ip, [r0]
++              outword r3
++              outword ip
+ .no_outsw_4:  tst     r2, #2
+               beq     .no_outsw_2
+               ldr     r3, [r1], #4
+-              strh    r3, [r0]
+-              mov     r3, r3, lsr #16
+-              strh    r3, [r0]
++              outword r3
+ .no_outsw_2:  tst     r2, #1
+               ldrneh  r3, [r1]
+--- linux-2.6.0-test6/arch/arm/lib/lib1funcs.S 2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/arm/lib/lib1funcs.S        2003-10-05 00:33:23.000000000 -0700
+@@ -1,7 +1,12 @@
+-@ libgcc1 routines for ARM cpu.
+-@ Division routines, written by Richard Earnshaw, (rearnsha@armltd.co.uk)
++/*
++ * linux/arch/arm/lib/lib1funcs.S: Optimized ARM division routines
++ *
++ * Author: Nicolas Pitre <nico@cam.org>
++ *   - contributed to gcc-3.4 on Sep 30, 2003
++ *   - adapted for the Linux kernel on Oct 2, 2003
++ */
+-/* Copyright (C) 1995, 1996, 1998 Free Software Foundation, Inc.
++/* Copyright 1995, 1996, 1998, 1999, 2000, 2003 Free Software Foundation, Inc.
+ This file is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+@@ -10,11 +15,12 @@ later version.
+ In addition to the permissions in the GNU General Public License, the
+ Free Software Foundation gives you unlimited permission to link the
+-compiled version of this file with other programs, and to distribute
+-those programs without any restriction coming from the use of this
+-file.  (The General Public License restrictions do apply in other
+-respects; for example, they cover modification of the file, and
+-distribution when not linked into another program.)
++compiled version of this file into combinations with other programs,
++and to distribute those combinations without any restriction coming
++from the use of this file.  (The General Public License restrictions
++do apply in other respects; for example, they cover modification of
++the file, and distribution when not linked into a combine
++executable.)
+ This file is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+@@ -26,286 +32,283 @@ along with this program; see the file CO
+ the Free Software Foundation, 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.  */
+-/* As a special exception, if you link this library with other files,
+-   some of which are compiled with GCC, to produce an executable,
+-   this library does not by itself cause the resulting executable
+-   to be covered by the GNU General Public License.
+-   This exception does not however invalidate any other reasons why
+-   the executable file might be covered by the GNU General Public License.
+- */
+-/* This code is derived from gcc 2.95.3
+- * 29/07/01 Adapted for linux
+- * 27/03/03 Ian Molton Clean up CONFIG_CPU
+- */
+ #include <linux/linkage.h>
+ #include <asm/assembler.h>
+-#include <asm/hardware.h>
+-#define RET   mov
+-#define RETc(x)       mov##x
+-#define RETCOND
+-
+-dividend      .req    r0
+-divisor               .req    r1
+-result                .req    r2
+-overdone        .req    r2
+-curbit                .req    r3
++
++.macro ARM_DIV_BODY dividend, divisor, result, curbit
++
++#if __LINUX_ARM_ARCH__ >= 5
++
++      clz     \curbit, \divisor
++      clz     \result, \dividend
++      sub     \result, \curbit, \result
++      mov     \curbit, #1
++      mov     \divisor, \divisor, lsl \result
++      mov     \curbit, \curbit, lsl \result
++      mov     \result, #0
+       
+-ENTRY(__udivsi3)
+-      cmp     divisor, #0
+-      beq     Ldiv0
+-      mov     curbit, #1
+-      mov     result, #0
+-      cmp     dividend, divisor
+-      bcc     Lgot_result_udivsi3
+-1:
++#else
++
++      @ Initially shift the divisor left 3 bits if possible,
++      @ set curbit accordingly.  This allows for curbit to be located
++      @ at the left end of each 4 bit nibbles in the division loop
++      @ to save one loop in most cases.
++      tst     \divisor, #0xe0000000
++      moveq   \divisor, \divisor, lsl #3
++      moveq   \curbit, #8
++      movne   \curbit, #1
++
+       @ Unless the divisor is very big, shift it up in multiples of
+       @ four bits, since this is the amount of unwinding in the main
+       @ division loop.  Continue shifting until the divisor is 
+       @ larger than the dividend.
+-      cmp     divisor, #0x10000000
+-      cmpcc   divisor, dividend
+-      movcc   divisor, divisor, lsl #4
+-      movcc   curbit, curbit, lsl #4
+-      bcc     1b
++1:    cmp     \divisor, #0x10000000
++      cmplo   \divisor, \dividend
++      movlo   \divisor, \divisor, lsl #4
++      movlo   \curbit, \curbit, lsl #4
++      blo     1b
+-2:
+       @ For very big divisors, we must shift it a bit at a time, or
+       @ we will be in danger of overflowing.
+-      cmp     divisor, #0x80000000
+-      cmpcc   divisor, dividend
+-      movcc   divisor, divisor, lsl #1
+-      movcc   curbit, curbit, lsl #1
+-      bcc     2b
+-
+-3:
+-      @ Test for possible subtractions, and note which bits
+-      @ are done in the result.  On the final pass, this may subtract
+-      @ too much from the dividend, but the result will be ok, since the
+-      @ "bit" will have been shifted out at the bottom.
+-      cmp     dividend, divisor
+-      subcs   dividend, dividend, divisor
+-      orrcs   result, result, curbit
+-      cmp     dividend, divisor, lsr #1
+-      subcs   dividend, dividend, divisor, lsr #1
+-      orrcs   result, result, curbit, lsr #1
+-      cmp     dividend, divisor, lsr #2
+-      subcs   dividend, dividend, divisor, lsr #2
+-      orrcs   result, result, curbit, lsr #2
+-      cmp     dividend, divisor, lsr #3
+-      subcs   dividend, dividend, divisor, lsr #3
+-      orrcs   result, result, curbit, lsr #3
+-      cmp     dividend, #0                    @ Early termination?
+-      movnes  curbit, curbit, lsr #4          @ No, any more bits to do?
+-      movne   divisor, divisor, lsr #4
+-      bne     3b
+-Lgot_result_udivsi3:
+-      mov     r0, result
+-      RET     pc, lr
++1:    cmp     \divisor, #0x80000000
++      cmplo   \divisor, \dividend
++      movlo   \divisor, \divisor, lsl #1
++      movlo   \curbit, \curbit, lsl #1
++      blo     1b
+-Ldiv0:
+-      str     lr, [sp, #-4]!
+-      bl      __div0
+-      mov     r0, #0                  @ about as wrong as it could be
+-      ldmia   sp!, {pc}RETCOND
++      mov     \result, #0
+-/* __umodsi3 ----------------------- */
++#endif
++
++      @ Division loop
++1:    cmp     \dividend, \divisor
++      subhs   \dividend, \dividend, \divisor
++      orrhs   \result,   \result,   \curbit
++      cmp     \dividend, \divisor,  lsr #1
++      subhs   \dividend, \dividend, \divisor, lsr #1
++      orrhs   \result,   \result,   \curbit,  lsr #1
++      cmp     \dividend, \divisor,  lsr #2
++      subhs   \dividend, \dividend, \divisor, lsr #2
++      orrhs   \result,   \result,   \curbit,  lsr #2
++      cmp     \dividend, \divisor,  lsr #3
++      subhs   \dividend, \dividend, \divisor, lsr #3
++      orrhs   \result,   \result,   \curbit,  lsr #3
++      cmp     \dividend, #0                   @ Early termination?
++      movnes  \curbit,   \curbit,  lsr #4     @ No, any more bits to do?
++      movne   \divisor,  \divisor, lsr #4
++      bne     1b
++
++.endm
++
++
++.macro ARM_DIV2_ORDER divisor, order
++
++#if __LINUX_ARM_ARCH__ >= 5
++
++      clz     \order, \divisor
++      rsb     \order, \order, #31
++
++#else
++
++      cmp     \divisor, #(1 << 16)
++      movhs   \divisor, \divisor, lsr #16
++      movhs   \order, #16
++      movlo   \order, #0
++
++      cmp     \divisor, #(1 << 8)
++      movhs   \divisor, \divisor, lsr #8
++      addhs   \order, \order, #8
++
++      cmp     \divisor, #(1 << 4)
++      movhs   \divisor, \divisor, lsr #4
++      addhs   \order, \order, #4
++
++      cmp     \divisor, #(1 << 2)
++      addhi   \order, \order, #3
++      addls   \order, \order, \divisor, lsr #1
++
++#endif
++
++.endm
++
++
++.macro ARM_MOD_BODY dividend, divisor, order, spare
++
++#if __LINUX_ARM_ARCH__ >= 5
++
++      clz     \order, \divisor
++      clz     \spare, \dividend
++      sub     \order, \order, \spare
++      mov     \divisor, \divisor, lsl \order
++
++#else
++
++      mov     \order, #0
+-ENTRY(__umodsi3)
+-      cmp     divisor, #0
+-      beq     Ldiv0
+-      mov     curbit, #1
+-      cmp     dividend, divisor
+-      RETc(cc)        pc, lr
+-1:
+       @ Unless the divisor is very big, shift it up in multiples of
+       @ four bits, since this is the amount of unwinding in the main
+       @ division loop.  Continue shifting until the divisor is 
+       @ larger than the dividend.
+-      cmp     divisor, #0x10000000
+-      cmpcc   divisor, dividend
+-      movcc   divisor, divisor, lsl #4
+-      movcc   curbit, curbit, lsl #4
+-      bcc     1b
++1:    cmp     \divisor, #0x10000000
++      cmplo   \divisor, \dividend
++      movlo   \divisor, \divisor, lsl #4
++      addlo   \order, \order, #4
++      blo     1b
+-2:
+       @ For very big divisors, we must shift it a bit at a time, or
+       @ we will be in danger of overflowing.
+-      cmp     divisor, #0x80000000
+-      cmpcc   divisor, dividend
+-      movcc   divisor, divisor, lsl #1
+-      movcc   curbit, curbit, lsl #1
+-      bcc     2b
+-
+-3:
+-      @ Test for possible subtractions.  On the final pass, this may 
+-      @ subtract too much from the dividend, so keep track of which
+-      @ subtractions are done, we can fix them up afterwards...
+-      mov     overdone, #0
+-      cmp     dividend, divisor
+-      subcs   dividend, dividend, divisor
+-      cmp     dividend, divisor, lsr #1
+-      subcs   dividend, dividend, divisor, lsr #1
+-      orrcs   overdone, overdone, curbit, ror #1
+-      cmp     dividend, divisor, lsr #2
+-      subcs   dividend, dividend, divisor, lsr #2
+-      orrcs   overdone, overdone, curbit, ror #2
+-      cmp     dividend, divisor, lsr #3
+-      subcs   dividend, dividend, divisor, lsr #3
+-      orrcs   overdone, overdone, curbit, ror #3
+-      mov     ip, curbit
+-      cmp     dividend, #0                    @ Early termination?
+-      movnes  curbit, curbit, lsr #4          @ No, any more bits to do?
+-      movne   divisor, divisor, lsr #4
+-      bne     3b
+-
+-      @ Any subtractions that we should not have done will be recorded in
+-      @ the top three bits of "overdone".  Exactly which were not needed
+-      @ are governed by the position of the bit, stored in ip.
+-      @ If we terminated early, because dividend became zero,
+-      @ then none of the below will match, since the bit in ip will not be
+-      @ in the bottom nibble.
+-      ands    overdone, overdone, #0xe0000000
+-      RETc(eq)        pc, lr                          @ No fixups needed
+-      tst     overdone, ip, ror #3
+-      addne   dividend, dividend, divisor, lsr #3
+-      tst     overdone, ip, ror #2
+-      addne   dividend, dividend, divisor, lsr #2
+-      tst     overdone, ip, ror #1
+-      addne   dividend, dividend, divisor, lsr #1
+-      RET     pc, lr
++1:    cmp     \divisor, #0x80000000
++      cmplo   \divisor, \dividend
++      movlo   \divisor, \divisor, lsl #1
++      addlo   \order, \order, #1
++      blo     1b
++
++#endif
++
++      @ Perform all needed substractions to keep only the reminder.
++      @ Do comparisons in batch of 4 first.
++      subs    \order, \order, #3              @ yes, 3 is intended here
++      blt     2f
++
++1:    cmp     \dividend, \divisor
++      subhs   \dividend, \dividend, \divisor
++      cmp     \dividend, \divisor,  lsr #1
++      subhs   \dividend, \dividend, \divisor, lsr #1
++      cmp     \dividend, \divisor,  lsr #2
++      subhs   \dividend, \dividend, \divisor, lsr #2
++      cmp     \dividend, \divisor,  lsr #3
++      subhs   \dividend, \dividend, \divisor, lsr #3
++      cmp     \dividend, #1
++      mov     \divisor, \divisor, lsr #4
++      subges  \order, \order, #4
++      bge     1b
++
++      tst     \order, #3
++      teqne   \dividend, #0
++      beq     5f
++
++      @ Either 1, 2 or 3 comparison/substractions are left.
++2:    cmn     \order, #2
++      blt     4f
++      beq     3f
++      cmp     \dividend, \divisor
++      subhs   \dividend, \dividend, \divisor
++      mov     \divisor,  \divisor,  lsr #1
++3:    cmp     \dividend, \divisor
++      subhs   \dividend, \dividend, \divisor
++      mov     \divisor,  \divisor,  lsr #1
++4:    cmp     \dividend, \divisor
++      subhs   \dividend, \dividend, \divisor
++5:
++.endm
++
++
++ENTRY(__udivsi3)
++
++      subs    r2, r1, #1
++      moveq   pc, lr
++      bcc     Ldiv0
++      cmp     r0, r1
++      bls     11f
++      tst     r1, r2
++      beq     12f
++
++      ARM_DIV_BODY r0, r1, r2, r3
++
++      mov     r0, r2
++      mov     pc, lr
++
++11:   moveq   r0, #1
++      movne   r0, #0
++      mov     pc, lr
++
++12:   ARM_DIV2_ORDER r1, r2
++
++      mov     r0, r0, lsr r2
++      mov     pc, lr
++
++
++ENTRY(__umodsi3)
++
++      subs    r2, r1, #1                      @ compare divisor with 1
++      bcc     Ldiv0
++      cmpne   r0, r1                          @ compare dividend with divisor
++      moveq   r0, #0
++      tsthi   r1, r2                          @ see if divisor is power of 2
++      andeq   r0, r0, r2
++      movls   pc, lr
++
++      ARM_MOD_BODY r0, r1, r2, r3
++
++      mov     pc, lr
++
+ ENTRY(__divsi3)
+-      eor     ip, dividend, divisor           @ Save the sign of the result.
+-      mov     curbit, #1
+-      mov     result, #0
+-      cmp     divisor, #0
+-      rsbmi   divisor, divisor, #0            @ Loops below use unsigned.
++
++      cmp     r1, #0
++      eor     ip, r0, r1                      @ save the sign of the result.
+       beq     Ldiv0
+-      cmp     dividend, #0
+-      rsbmi   dividend, dividend, #0
+-      cmp     dividend, divisor
+-      bcc     Lgot_result_divsi3
++      rsbmi   r1, r1, #0                      @ loops below use unsigned.
++      subs    r2, r1, #1                      @ division by 1 or -1 ?
++      beq     10f
++      movs    r3, r0
++      rsbmi   r3, r0, #0                      @ positive dividend value
++      cmp     r3, r1
++      bls     11f
++      tst     r1, r2                          @ divisor is power of 2 ?
++      beq     12f
+-1:
+-      @ Unless the divisor is very big, shift it up in multiples of
+-      @ four bits, since this is the amount of unwinding in the main
+-      @ division loop.  Continue shifting until the divisor is 
+-      @ larger than the dividend.
+-      cmp     divisor, #0x10000000
+-      cmpcc   divisor, dividend
+-      movcc   divisor, divisor, lsl #4
+-      movcc   curbit, curbit, lsl #4
+-      bcc     1b
++      ARM_DIV_BODY r3, r1, r0, r2
+-2:
+-      @ For very big divisors, we must shift it a bit at a time, or
+-      @ we will be in danger of overflowing.
+-      cmp     divisor, #0x80000000
+-      cmpcc   divisor, dividend
+-      movcc   divisor, divisor, lsl #1
+-      movcc   curbit, curbit, lsl #1
+-      bcc     2b
+-
+-3:
+-      @ Test for possible subtractions, and note which bits
+-      @ are done in the result.  On the final pass, this may subtract
+-      @ too much from the dividend, but the result will be ok, since the
+-      @ "bit" will have been shifted out at the bottom.
+-      cmp     dividend, divisor
+-      subcs   dividend, dividend, divisor
+-      orrcs   result, result, curbit
+-      cmp     dividend, divisor, lsr #1
+-      subcs   dividend, dividend, divisor, lsr #1
+-      orrcs   result, result, curbit, lsr #1
+-      cmp     dividend, divisor, lsr #2
+-      subcs   dividend, dividend, divisor, lsr #2
+-      orrcs   result, result, curbit, lsr #2
+-      cmp     dividend, divisor, lsr #3
+-      subcs   dividend, dividend, divisor, lsr #3
+-      orrcs   result, result, curbit, lsr #3
+-      cmp     dividend, #0                    @ Early termination?
+-      movnes  curbit, curbit, lsr #4          @ No, any more bits to do?
+-      movne   divisor, divisor, lsr #4
+-      bne     3b
+-Lgot_result_divsi3:
+-      mov     r0, result
+       cmp     ip, #0
+       rsbmi   r0, r0, #0
+-      RET     pc, lr
++      mov     pc, lr
++
++10:   teq     ip, r0                          @ same sign ?
++      rsbmi   r0, r0, #0
++      mov     pc, lr
++
++11:   movlo   r0, #0
++      moveq   r0, ip, asr #31
++      orreq   r0, r0, #1
++      mov     pc, lr
++
++12:   ARM_DIV2_ORDER r1, r2
++
++      cmp     ip, #0
++      mov     r0, r3, lsr r2
++      rsbmi   r0, r0, #0
++      mov     pc, lr
++
+ ENTRY(__modsi3)
+-      mov     curbit, #1
+-      cmp     divisor, #0
+-      rsbmi   divisor, divisor, #0            @ Loops below use unsigned.
++
++      cmp     r1, #0
+       beq     Ldiv0
+-      @ Need to save the sign of the dividend, unfortunately, we need
+-      @ ip later on; this is faster than pushing lr and using that.
+-      str     dividend, [sp, #-4]!
+-      cmp     dividend, #0
+-      rsbmi   dividend, dividend, #0
+-      cmp     dividend, divisor
+-      bcc     Lgot_result_modsi3
++      rsbmi   r1, r1, #0                      @ loops below use unsigned.
++      movs    ip, r0                          @ preserve sign of dividend
++      rsbmi   r0, r0, #0                      @ if negative make positive
++      subs    r2, r1, #1                      @ compare divisor with 1
++      cmpne   r0, r1                          @ compare dividend with divisor
++      moveq   r0, #0
++      tsthi   r1, r2                          @ see if divisor is power of 2
++      andeq   r0, r0, r2
++      bls     10f
++
++      ARM_MOD_BODY r0, r1, r2, r3
++
++10:   cmp     ip, #0
++      rsbmi   r0, r0, #0
++      mov     pc, lr
++
++
++Ldiv0:
++
++      str     lr, [sp, #-4]!
++      bl      __div0
++      mov     r0, #0                  @ About as wrong as it could be.
++      ldr     pc, [sp], #4
+-1:
+-      @ Unless the divisor is very big, shift it up in multiples of
+-      @ four bits, since this is the amount of unwinding in the main
+-      @ division loop.  Continue shifting until the divisor is 
+-      @ larger than the dividend.
+-      cmp     divisor, #0x10000000
+-      cmpcc   divisor, dividend
+-      movcc   divisor, divisor, lsl #4
+-      movcc   curbit, curbit, lsl #4
+-      bcc     1b
+-2:
+-      @ For very big divisors, we must shift it a bit at a time, or
+-      @ we will be in danger of overflowing.
+-      cmp     divisor, #0x80000000
+-      cmpcc   divisor, dividend
+-      movcc   divisor, divisor, lsl #1
+-      movcc   curbit, curbit, lsl #1
+-      bcc     2b
+-
+-3:
+-      @ Test for possible subtractions.  On the final pass, this may 
+-      @ subtract too much from the dividend, so keep track of which
+-      @ subtractions are done, we can fix them up afterwards...
+-      mov     overdone, #0
+-      cmp     dividend, divisor
+-      subcs   dividend, dividend, divisor
+-      cmp     dividend, divisor, lsr #1
+-      subcs   dividend, dividend, divisor, lsr #1
+-      orrcs   overdone, overdone, curbit, ror #1
+-      cmp     dividend, divisor, lsr #2
+-      subcs   dividend, dividend, divisor, lsr #2
+-      orrcs   overdone, overdone, curbit, ror #2
+-      cmp     dividend, divisor, lsr #3
+-      subcs   dividend, dividend, divisor, lsr #3
+-      orrcs   overdone, overdone, curbit, ror #3
+-      mov     ip, curbit
+-      cmp     dividend, #0                    @ Early termination?
+-      movnes  curbit, curbit, lsr #4          @ No, any more bits to do?
+-      movne   divisor, divisor, lsr #4
+-      bne     3b
+-
+-      @ Any subtractions that we should not have done will be recorded in
+-      @ the top three bits of "overdone".  Exactly which were not needed
+-      @ are governed by the position of the bit, stored in ip.
+-      @ If we terminated early, because dividend became zero,
+-      @ then none of the below will match, since the bit in ip will not be
+-      @ in the bottom nibble.
+-      ands    overdone, overdone, #0xe0000000
+-      beq     Lgot_result_modsi3
+-      tst     overdone, ip, ror #3
+-      addne   dividend, dividend, divisor, lsr #3
+-      tst     overdone, ip, ror #2
+-      addne   dividend, dividend, divisor, lsr #2
+-      tst     overdone, ip, ror #1
+-      addne   dividend, dividend, divisor, lsr #1
+-Lgot_result_modsi3:
+-      ldr     ip, [sp], #4
+-      cmp     ip, #0
+-      rsbmi   dividend, dividend, #0
+-      RET     pc, lr
+--- linux-2.6.0-test6/arch/arm/mach-integrator/core.c  2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/arm/mach-integrator/core.c 2003-10-05 00:33:23.000000000 -0700
+@@ -1,134 +1,59 @@
+ /*
+- *  linux/arch/arm/mach-integrator/arch.c
++ *  linux/arch/arm/mach-integrator/core.c
+  *
+- *  Copyright (C) 2000 Deep Blue Solutions Ltd
++ *  Copyright (C) 2000-2003 Deep Blue Solutions Ltd
+  *
+  * 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
++ * it under the terms of the GNU General Public License version 2, as
++ * published by the Free Software Foundation.
+  */
+ #include <linux/types.h>
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+-#include <linux/list.h>
+ #include <linux/device.h>
+-#include <linux/slab.h>
+-#include <linux/string.h>
+ #include <asm/hardware.h>
+-#include <asm/io.h>
+ #include <asm/irq.h>
+-#include <asm/setup.h>
+-#include <asm/mach-types.h>
+ #include <asm/hardware/amba.h>
+-#include <asm/hardware/amba_kmi.h>
+-
+-#include <asm/arch/lm.h>
+-
+-#include <asm/mach/arch.h>
+-#include <asm/mach/irq.h>
+-#include <asm/mach/map.h>
+-
+-/* 
+- * All IO addresses are mapped onto VA 0xFFFx.xxxx, where x.xxxx
+- * is the (PA >> 12).
+- *
+- * Setup a VA for the Integrator interrupt controller (for header #0,
+- * just for now).
+- */
+-#define VA_IC_BASE    IO_ADDRESS(INTEGRATOR_IC_BASE) 
+-#define VA_SC_BASE    IO_ADDRESS(INTEGRATOR_SC_BASE)
+-#define VA_CMIC_BASE  IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_IC_OFFSET
+-
+-/*
+- * Logical      Physical
+- * e8000000   40000000        PCI memory              PHYS_PCI_MEM_BASE       (max 512M)
+- * ec000000   61000000        PCI config space        PHYS_PCI_CONFIG_BASE    (max 16M)
+- * ed000000   62000000        PCI V3 regs             PHYS_PCI_V3_BASE        (max 64k)
+- * ee000000   60000000        PCI IO                  PHYS_PCI_IO_BASE        (max 16M)
+- * ef000000                   Cache flush
+- * f1000000   10000000        Core module registers
+- * f1100000   11000000        System controller registers
+- * f1200000   12000000        EBI registers
+- * f1300000   13000000        Counter/Timer
+- * f1400000   14000000        Interrupt controller
+- * f1500000   15000000        RTC
+- * f1600000   16000000        UART 0
+- * f1700000   17000000        UART 1
+- * f1a00000   1a000000        Debug LEDs
+- * f1b00000   1b000000        GPIO
+- */
+-static struct map_desc integrator_io_desc[] __initdata = {
+- { IO_ADDRESS(INTEGRATOR_HDR_BASE),   INTEGRATOR_HDR_BASE,   SZ_4K,  MT_DEVICE },
+- { IO_ADDRESS(INTEGRATOR_SC_BASE),    INTEGRATOR_SC_BASE,    SZ_4K,  MT_DEVICE },
+- { IO_ADDRESS(INTEGRATOR_EBI_BASE),   INTEGRATOR_EBI_BASE,   SZ_4K,  MT_DEVICE },
+- { IO_ADDRESS(INTEGRATOR_CT_BASE),    INTEGRATOR_CT_BASE,    SZ_4K,  MT_DEVICE },
+- { IO_ADDRESS(INTEGRATOR_IC_BASE),    INTEGRATOR_IC_BASE,    SZ_4K,  MT_DEVICE },
+- { IO_ADDRESS(INTEGRATOR_RTC_BASE),   INTEGRATOR_RTC_BASE,   SZ_4K,  MT_DEVICE },
+- { IO_ADDRESS(INTEGRATOR_UART0_BASE), INTEGRATOR_UART0_BASE, SZ_4K,  MT_DEVICE },
+- { IO_ADDRESS(INTEGRATOR_UART1_BASE), INTEGRATOR_UART1_BASE, SZ_4K,  MT_DEVICE },
+- { IO_ADDRESS(INTEGRATOR_DBG_BASE),   INTEGRATOR_DBG_BASE,   SZ_4K,  MT_DEVICE },
+- { IO_ADDRESS(INTEGRATOR_GPIO_BASE),  INTEGRATOR_GPIO_BASE,  SZ_4K,  MT_DEVICE },
+- { PCI_MEMORY_VADDR,                  PHYS_PCI_MEM_BASE,     SZ_16M, MT_DEVICE },
+- { PCI_CONFIG_VADDR,                  PHYS_PCI_CONFIG_BASE,  SZ_16M, MT_DEVICE },
+- { PCI_V3_VADDR,                      PHYS_PCI_V3_BASE,      SZ_64K, MT_DEVICE },
+- { PCI_IO_VADDR,                      PHYS_PCI_IO_BASE,      SZ_64K, MT_DEVICE }
++static struct amba_device rtc_device = {
++      .dev            = {
++              .bus_id = "mb:15",
++      },
++      .res            = {
++              .start  = INTEGRATOR_RTC_BASE,
++              .end    = INTEGRATOR_RTC_BASE + SZ_4K - 1,
++              .flags  = IORESOURCE_MEM,
++      },
++      .irq            = IRQ_RTCINT,
++      .periphid       = 0x00041030,
+ };
+-static void __init integrator_map_io(void)
+-{
+-      iotable_init(integrator_io_desc, ARRAY_SIZE(integrator_io_desc));
+-}
+-
+-#define ALLPCI ( (1 << IRQ_PCIINT0) | (1 << IRQ_PCIINT1) | (1 << IRQ_PCIINT2) | (1 << IRQ_PCIINT3) )
+-
+-static void sc_mask_irq(unsigned int irq)
+-{
+-      writel(1 << irq, VA_IC_BASE + IRQ_ENABLE_CLEAR);
+-}
+-
+-static void sc_unmask_irq(unsigned int irq)
+-{
+-      writel(1 << irq, VA_IC_BASE + IRQ_ENABLE_SET);
+-}
+-
+-static struct irqchip sc_chip = {
+-      .ack    = sc_mask_irq,
+-      .mask   = sc_mask_irq,
+-      .unmask = sc_unmask_irq,
++static struct amba_device uart0_device = {
++      .dev            = {
++              .bus_id = "mb:16",
++      },
++      .res            = {
++              .start  = INTEGRATOR_UART0_BASE,
++              .end    = INTEGRATOR_UART0_BASE + SZ_4K - 1,
++              .flags  = IORESOURCE_MEM,
++      },
++      .irq            = IRQ_UARTINT0,
++      .periphid       = 0x0041010,
+ };
+-static void __init integrator_init_irq(void)
+-{
+-      unsigned int i;
+-
+-      /* Disable all interrupts initially. */
+-      /* Do the core module ones */
+-      writel(-1, VA_CMIC_BASE + IRQ_ENABLE_CLEAR);
+-
+-      /* do the header card stuff next */
+-      writel(-1, VA_IC_BASE + IRQ_ENABLE_CLEAR);
+-      writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR);
+-
+-      for (i = 0; i < NR_IRQS; i++) {
+-              if (((1 << i) && INTEGRATOR_SC_VALID_INT) != 0) {
+-                      set_irq_chip(i, &sc_chip);
+-                      set_irq_handler(i, do_level_IRQ);
+-                      set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+-              }
+-      }
+-}
++static struct amba_device uart1_device = {
++      .dev            = {
++              .bus_id = "mb:17",
++      },
++      .res            = {
++              .start  = INTEGRATOR_UART1_BASE,
++              .end    = INTEGRATOR_UART1_BASE + SZ_4K - 1,
++              .flags  = IORESOURCE_MEM,
++      },
++      .irq            = IRQ_UARTINT1,
++      .periphid       = 0x0041010,
++};
+ static struct amba_device kmi0_device = {
+       .dev            = {
+@@ -136,7 +61,7 @@ static struct amba_device kmi0_device = 
+       },
+       .res            = {
+               .start  = KMI0_BASE,
+-              .end    = KMI0_BASE + KMI_SIZE - 1,
++              .end    = KMI0_BASE + SZ_4K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       .irq            = IRQ_KMIINT0,
+@@ -149,7 +74,7 @@ static struct amba_device kmi1_device = 
+       },
+       .res            = {
+               .start  = KMI1_BASE,
+-              .end    = KMI1_BASE + KMI_SIZE - 1,
++              .end    = KMI1_BASE + SZ_4K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       .irq            = IRQ_KMIINT1,
+@@ -157,52 +82,23 @@ static struct amba_device kmi1_device = 
+ };
+ static struct amba_device *amba_devs[] __initdata = {
++      &rtc_device,
++      &uart0_device,
++      &uart1_device,
+       &kmi0_device,
+       &kmi1_device,
+ };
+-static int __init register_devices(void)
++static int __init integrator_init(void)
+ {
+-      unsigned long sc_dec;
+       int i;
+       for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
+               struct amba_device *d = amba_devs[i];
+-
+               amba_device_register(d, &iomem_resource);
+       }
+-      sc_dec = readl(VA_SC_BASE + INTEGRATOR_SC_DEC_OFFSET);
+-      for (i = 0; i < 4; i++) {
+-              struct lm_device *lmdev;
+-
+-              if ((sc_dec & (16 << i)) == 0)
+-                      continue;
+-
+-              lmdev = kmalloc(sizeof(struct lm_device), GFP_KERNEL);
+-              if (!lmdev)
+-                      continue;
+-
+-              memset(lmdev, 0, sizeof(struct lm_device));
+-
+-              lmdev->resource.start = 0xc0000000 + 0x10000000 * i;
+-              lmdev->resource.end = lmdev->resource.start + 0x0fffffff;
+-              lmdev->resource.flags = IORESOURCE_MEM;
+-              lmdev->irq = IRQ_EXPINT0 + i;
+-              lmdev->id = i;
+-
+-              lm_device_register(lmdev);
+-      }
+-
+       return 0;
+ }
+-arch_initcall(register_devices);
+-
+-MACHINE_START(INTEGRATOR, "ARM-Integrator")
+-      MAINTAINER("ARM Ltd/Deep Blue Solutions Ltd")
+-      BOOT_MEM(0x00000000, 0x16000000, 0xf1600000)
+-      BOOT_PARAMS(0x00000100)
+-      MAPIO(integrator_map_io)
+-      INITIRQ(integrator_init_irq)
+-MACHINE_END
++arch_initcall(integrator_init);
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/arch/arm/mach-integrator/integrator_ap.c        2003-10-05 00:33:23.000000000 -0700
+@@ -0,0 +1,294 @@
++/*
++ *  linux/arch/arm/mach-integrator/integrator_ap.c
++ *
++ *  Copyright (C) 2000-2003 Deep Blue Solutions Ltd
++ *
++ * 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/types.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/device.h>
++#include <linux/slab.h>
++#include <linux/string.h>
++#include <linux/sysdev.h>
++
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/setup.h>
++#include <asm/mach-types.h>
++#include <asm/hardware/amba.h>
++#include <asm/hardware/amba_kmi.h>
++
++#include <asm/arch/lm.h>
++
++#include <asm/mach/arch.h>
++#include <asm/mach/flash.h>
++#include <asm/mach/irq.h>
++#include <asm/mach/map.h>
++
++
++/* 
++ * All IO addresses are mapped onto VA 0xFFFx.xxxx, where x.xxxx
++ * is the (PA >> 12).
++ *
++ * Setup a VA for the Integrator interrupt controller (for header #0,
++ * just for now).
++ */
++#define VA_IC_BASE    IO_ADDRESS(INTEGRATOR_IC_BASE) 
++#define VA_SC_BASE    IO_ADDRESS(INTEGRATOR_SC_BASE)
++#define VA_EBI_BASE   IO_ADDRESS(INTEGRATOR_EBI_BASE)
++#define VA_CMIC_BASE  IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_IC_OFFSET
++
++/*
++ * Logical      Physical
++ * e8000000   40000000        PCI memory              PHYS_PCI_MEM_BASE       (max 512M)
++ * ec000000   61000000        PCI config space        PHYS_PCI_CONFIG_BASE    (max 16M)
++ * ed000000   62000000        PCI V3 regs             PHYS_PCI_V3_BASE        (max 64k)
++ * ee000000   60000000        PCI IO                  PHYS_PCI_IO_BASE        (max 16M)
++ * ef000000                   Cache flush
++ * f1000000   10000000        Core module registers
++ * f1100000   11000000        System controller registers
++ * f1200000   12000000        EBI registers
++ * f1300000   13000000        Counter/Timer
++ * f1400000   14000000        Interrupt controller
++ * f1500000   15000000        RTC
++ * f1600000   16000000        UART 0
++ * f1700000   17000000        UART 1
++ * f1a00000   1a000000        Debug LEDs
++ * f1b00000   1b000000        GPIO
++ */
++
++static struct map_desc ap_io_desc[] __initdata = {
++ { IO_ADDRESS(INTEGRATOR_HDR_BASE),   INTEGRATOR_HDR_BASE,   SZ_4K,  MT_DEVICE },
++ { IO_ADDRESS(INTEGRATOR_SC_BASE),    INTEGRATOR_SC_BASE,    SZ_4K,  MT_DEVICE },
++ { IO_ADDRESS(INTEGRATOR_EBI_BASE),   INTEGRATOR_EBI_BASE,   SZ_4K,  MT_DEVICE },
++ { IO_ADDRESS(INTEGRATOR_CT_BASE),    INTEGRATOR_CT_BASE,    SZ_4K,  MT_DEVICE },
++ { IO_ADDRESS(INTEGRATOR_IC_BASE),    INTEGRATOR_IC_BASE,    SZ_4K,  MT_DEVICE },
++ { IO_ADDRESS(INTEGRATOR_RTC_BASE),   INTEGRATOR_RTC_BASE,   SZ_4K,  MT_DEVICE },
++ { IO_ADDRESS(INTEGRATOR_UART0_BASE), INTEGRATOR_UART0_BASE, SZ_4K,  MT_DEVICE },
++ { IO_ADDRESS(INTEGRATOR_UART1_BASE), INTEGRATOR_UART1_BASE, SZ_4K,  MT_DEVICE },
++ { IO_ADDRESS(INTEGRATOR_DBG_BASE),   INTEGRATOR_DBG_BASE,   SZ_4K,  MT_DEVICE },
++ { IO_ADDRESS(INTEGRATOR_GPIO_BASE),  INTEGRATOR_GPIO_BASE,  SZ_4K,  MT_DEVICE },
++ { PCI_MEMORY_VADDR,                  PHYS_PCI_MEM_BASE,     SZ_16M, MT_DEVICE },
++ { PCI_CONFIG_VADDR,                  PHYS_PCI_CONFIG_BASE,  SZ_16M, MT_DEVICE },
++ { PCI_V3_VADDR,                      PHYS_PCI_V3_BASE,      SZ_64K, MT_DEVICE },
++ { PCI_IO_VADDR,                      PHYS_PCI_IO_BASE,      SZ_64K, MT_DEVICE }
++};
++
++static void __init ap_map_io(void)
++{
++      iotable_init(ap_io_desc, ARRAY_SIZE(ap_io_desc));
++}
++
++#define INTEGRATOR_SC_VALID_INT       0x003fffff
++
++static void sc_mask_irq(unsigned int irq)
++{
++      writel(1 << irq, VA_IC_BASE + IRQ_ENABLE_CLEAR);
++}
++
++static void sc_unmask_irq(unsigned int irq)
++{
++      writel(1 << irq, VA_IC_BASE + IRQ_ENABLE_SET);
++}
++
++static struct irqchip sc_chip = {
++      .ack    = sc_mask_irq,
++      .mask   = sc_mask_irq,
++      .unmask = sc_unmask_irq,
++};
++
++static void __init ap_init_irq(void)
++{
++      unsigned int i;
++
++      /* Disable all interrupts initially. */
++      /* Do the core module ones */
++      writel(-1, VA_CMIC_BASE + IRQ_ENABLE_CLEAR);
++
++      /* do the header card stuff next */
++      writel(-1, VA_IC_BASE + IRQ_ENABLE_CLEAR);
++      writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR);
++
++      for (i = 0; i < NR_IRQS; i++) {
++              if (((1 << i) && INTEGRATOR_SC_VALID_INT) != 0) {
++                      set_irq_chip(i, &sc_chip);
++                      set_irq_handler(i, do_level_IRQ);
++                      set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
++              }
++      }
++}
++
++#ifdef CONFIG_PM
++static unsigned long ic_irq_enable;
++
++static int irq_suspend(struct sys_device *dev, u32 state)
++{
++      ic_irq_enable = readl(VA_IC_BASE + IRQ_ENABLE);
++      return 0;
++}
++
++static int irq_resume(struct sys_device *dev)
++{
++      /* disable all irq sources */
++      writel(-1, VA_CMIC_BASE + IRQ_ENABLE_CLEAR);
++      writel(-1, VA_IC_BASE + IRQ_ENABLE_CLEAR);
++      writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR);
++
++      writel(ic_irq_enable, VA_IC_BASE + IRQ_ENABLE_SET);
++      return 0;
++}
++#else
++#define irq_suspend NULL
++#define irq_resume NULL
++#endif
++
++static struct sysdev_class irq_class = {
++      set_kset_name("irq"),
++      .suspend        = irq_suspend,
++      .resume         = irq_resume,
++};
++
++static struct sys_device irq_device = {
++      .id     = 0,
++      .cls    = &irq_class,
++};
++
++static int __init irq_init_sysfs(void)
++{
++      int ret = sysdev_class_register(&irq_class);
++      if (ret == 0)
++              ret = sys_device_register(&irq_device);
++      return ret;
++}
++
++device_initcall(irq_init_sysfs);
++
++/*
++ * Flash handling.
++ */
++#define SC_CTRLC (VA_SC_BASE + INTEGRATOR_SC_CTRLC_OFFSET)
++#define SC_CTRLS (VA_SC_BASE + INTEGRATOR_SC_CTRLS_OFFSET)
++#define EBI_CSR1 (VA_EBI_BASE + INTEGRATOR_EBI_CSR1_OFFSET)
++#define EBI_LOCK (VA_EBI_BASE + INTEGRATOR_EBI_LOCK_OFFSET)
++
++static int ap_flash_init(void)
++{
++      u32 tmp;
++
++      writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, SC_CTRLC);
++
++      tmp = readl(EBI_CSR1) | INTEGRATOR_EBI_WRITE_ENABLE;
++      writel(tmp, EBI_CSR1);
++
++      if (!(readl(EBI_CSR1) & INTEGRATOR_EBI_WRITE_ENABLE)) {
++              writel(0xa05f, EBI_LOCK);
++              writel(tmp, EBI_CSR1);
++              writel(0, EBI_LOCK);
++      }
++      return 0;
++}
++
++static void ap_flash_exit(void)
++{
++      u32 tmp;
++
++      writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, SC_CTRLC);
++
++      tmp = readl(EBI_CSR1) & ~INTEGRATOR_EBI_WRITE_ENABLE;
++      writel(tmp, EBI_CSR1);
++
++      if (readl(EBI_CSR1) & INTEGRATOR_EBI_WRITE_ENABLE) {
++              writel(0xa05f, EBI_LOCK);
++              writel(tmp, EBI_CSR1);
++              writel(0, EBI_LOCK);
++      }
++}
++
++static void ap_flash_set_vpp(int on)
++{
++      unsigned long reg = on ? SC_CTRLS : SC_CTRLC;
++
++      writel(INTEGRATOR_SC_CTRL_nFLVPPEN, reg);
++}
++
++static struct flash_platform_data ap_flash_data = {
++      .map_name       = "cfi_probe",
++      .width          = 4,
++      .init           = ap_flash_init,
++      .exit           = ap_flash_exit,
++      .set_vpp        = ap_flash_set_vpp,
++};
++
++static struct resource cfi_flash_resource = {
++      .start          = INTEGRATOR_FLASH_BASE,
++      .end            = INTEGRATOR_FLASH_BASE + INTEGRATOR_FLASH_SIZE - 1,
++      .flags          = IORESOURCE_MEM,
++};
++
++static struct platform_device cfi_flash_device = {
++      .name           = "armflash",
++      .id             = 0,
++      .dev            = {
++              .platform_data  = &ap_flash_data,
++      },
++      .num_resources  = 1,
++      .resource       = &cfi_flash_resource,
++};
++
++static int __init ap_init(void)
++{
++      unsigned long sc_dec;
++      int i;
++
++      platform_add_device(&cfi_flash_device);
++
++      sc_dec = readl(VA_SC_BASE + INTEGRATOR_SC_DEC_OFFSET);
++      for (i = 0; i < 4; i++) {
++              struct lm_device *lmdev;
++
++              if ((sc_dec & (16 << i)) == 0)
++                      continue;
++
++              lmdev = kmalloc(sizeof(struct lm_device), GFP_KERNEL);
++              if (!lmdev)
++                      continue;
++
++              memset(lmdev, 0, sizeof(struct lm_device));
++
++              lmdev->resource.start = 0xc0000000 + 0x10000000 * i;
++              lmdev->resource.end = lmdev->resource.start + 0x0fffffff;
++              lmdev->resource.flags = IORESOURCE_MEM;
++              lmdev->irq = IRQ_AP_EXPINT0 + i;
++              lmdev->id = i;
++
++              lm_device_register(lmdev);
++      }
++
++      return 0;
++}
++
++arch_initcall(ap_init);
++
++MACHINE_START(INTEGRATOR, "ARM-Integrator")
++      MAINTAINER("ARM Ltd/Deep Blue Solutions Ltd")
++      BOOT_MEM(0x00000000, 0x16000000, 0xf1600000)
++      BOOT_PARAMS(0x00000100)
++      MAPIO(ap_map_io)
++      INITIRQ(ap_init_irq)
++MACHINE_END
+--- linux-2.6.0-test6/arch/arm/mach-integrator/Kconfig 2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/arm/mach-integrator/Kconfig        2003-10-05 00:33:23.000000000 -0700
+@@ -1,8 +1,15 @@
+ menu "Integrator Options"
+       depends on ARCH_INTEGRATOR
++config ARCH_INTEGRATOR_AP
++      bool "Support Integrator/AP and Integrator/PP2 platforms"
++      help
++        Include support for the ARM(R) Integrator/AP and
++        Integrator/PP2 platforms.
++
+ config INTEGRATOR_IMPD1
+       tristate "Include support for Integrator/IM-PD1"
++      depends on ARCH_INTEGRATOR_AP
+       help
+         The IM-PD1 is an add-on logic module for the Integrator which
+         allows ARM(R) Ltd PrimeCells to be developed and evaluated.
+--- linux-2.6.0-test6/arch/arm/mach-integrator/Makefile        2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/arm/mach-integrator/Makefile       2003-10-05 00:33:23.000000000 -0700
+@@ -4,9 +4,10 @@
+ # Object file lists.
+-obj-y                 := core.o lm.o time.o
++obj-y                                 := core.o lm.o time.o
++obj-$(CONFIG_ARCH_INTEGRATOR_AP)      += integrator_ap.o
+-obj-$(CONFIG_LEDS)    += leds.o
+-obj-$(CONFIG_PCI)     += pci_v3.o pci.o
++obj-$(CONFIG_LEDS)                    += leds.o
++obj-$(CONFIG_PCI)                     += pci_v3.o pci.o
+ obj-$(CONFIG_CPU_FREQ_INTEGRATOR)     += cpu.o
+ obj-$(CONFIG_INTEGRATOR_IMPD1)                += impd1.o
+--- linux-2.6.0-test6/arch/arm/mach-integrator/pci.c   2003-06-14 12:18:51.000000000 -0700
++++ 25/arch/arm/mach-integrator/pci.c  2003-10-05 00:33:23.000000000 -0700
+@@ -96,7 +96,7 @@ static u8 __init integrator_swizzle(stru
+ }
+ static int irq_tab[4] __initdata = {
+-      IRQ_PCIINT0,    IRQ_PCIINT1,    IRQ_PCIINT2,    IRQ_PCIINT3
++      IRQ_AP_PCIINT0, IRQ_AP_PCIINT1, IRQ_AP_PCIINT2, IRQ_AP_PCIINT3
+ };
+ /*
+--- linux-2.6.0-test6/arch/arm/mach-integrator/pci_v3.c        2003-06-14 12:18:28.000000000 -0700
++++ 25/arch/arm/mach-integrator/pci_v3.c       2003-10-05 00:33:23.000000000 -0700
+@@ -575,7 +575,7 @@ void __init pci_v3_preinit(void)
+       /*
+        * Grab the PCI error interrupt.
+        */
+-      ret = request_irq(IRQ_V3INT, v3_irq, 0, "V3", NULL);
++      ret = request_irq(IRQ_AP_V3INT, v3_irq, 0, "V3", NULL);
+       if (ret)
+               printk(KERN_ERR "PCI: unable to grab PCI error "
+                      "interrupt: %d\n", ret);
+@@ -596,7 +596,7 @@ void __init pci_v3_postinit(void)
+       v3_writeb(V3_LB_IMASK, 0x68);
+ #if 0
+-      ret = request_irq(IRQ_LBUSTIMEOUT, lb_timeout, 0, "bus timeout", NULL);
++      ret = request_irq(IRQ_AP_LBUSTIMEOUT, lb_timeout, 0, "bus timeout", NULL);
+       if (ret)
+               printk(KERN_ERR "PCI: unable to grab local bus timeout "
+                      "interrupt: %d\n", ret);
+--- linux-2.6.0-test6/arch/arm/mach-pxa/irq.c  2003-06-14 12:18:33.000000000 -0700
++++ 25/arch/arm/mach-pxa/irq.c 2003-10-05 00:33:23.000000000 -0700
+@@ -58,7 +58,19 @@ static int pxa_gpio_irq_type(unsigned in
+ {
+       int gpio, idx;
+-      gpio = irq - ((irq >= IRQ_GPIO(2)) ? IRQ_GPIO(2) + 2 : IRQ_GPIO(0));
++      gpio = IRQ_TO_GPIO(irq);
++      idx = gpio >> 5;
++
++      if (type == IRQT_PROBE) {
++          /* Don't mess with enabled GPIOs using preconfigured edges or
++             GPIOs set to alternate function during probe */
++              if ((GPIO_IRQ_rising_edge[idx] | GPIO_IRQ_falling_edge[idx]) &
++                  GPIO_bit(gpio))
++                      return 0;
++              if (GAFR(gpio) & (0x3 << (((gpio) & 0xf)*2)))
++                      return 0;
++              type = __IRQT_RISEDGE | __IRQT_FALEDGE;
++      }
+       printk(KERN_DEBUG "IRQ%d (GPIO%d): ", irq, gpio);
+@@ -78,10 +90,8 @@ static int pxa_gpio_irq_type(unsigned in
+       printk("edges\n");
+-      idx = gpio >> 5;
+       GRER(gpio) = GPIO_IRQ_rising_edge[idx] & GPIO_IRQ_mask[idx];
+       GFER(gpio) = GPIO_IRQ_falling_edge[idx] & GPIO_IRQ_mask[idx];
+-
+       return 0;
+ }
+--- linux-2.6.0-test6/arch/arm/mach-pxa/leds.c 2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/arm/mach-pxa/leds.c        2003-10-05 00:33:23.000000000 -0700
+@@ -7,6 +7,7 @@
+  *
+  * Copyright (c) 2001 Jeff Sutherland, Accelent Systems Inc.
+  */
++#include <linux/compiler.h>
+ #include <linux/init.h>
+ #include <asm/leds.h>
+--- linux-2.6.0-test6/arch/arm/mach-pxa/lubbock.c      2003-08-22 19:23:40.000000000 -0700
++++ 25/arch/arm/mach-pxa/lubbock.c     2003-10-05 00:33:23.000000000 -0700
+@@ -78,7 +78,7 @@ static void __init lubbock_init_irq(void
+       pxa_init_irq();
+       /* setup extra lubbock irqs */
+-      for (irq = LUBBOCK_IRQ(0); irq <= LUBBOCK_IRQ(5); irq++) {
++      for (irq = LUBBOCK_IRQ(0); irq <= LUBBOCK_LAST_IRQ; irq++) {
+               set_irq_chip(irq, &lubbock_irq_chip);
+               set_irq_handler(irq, do_level_IRQ);
+               set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+@@ -124,6 +124,7 @@ static struct map_desc lubbock_io_desc[]
+   { 0xf0000000, 0x08000000, 0x00100000, MT_DEVICE }, /* CPLD */
+   { 0xf1000000, 0x0c000000, 0x00100000, MT_DEVICE }, /* LAN91C96 IO */
+   { 0xf1100000, 0x0e000000, 0x00100000, MT_DEVICE }, /* LAN91C96 Attr */
++  { 0xf4000000, 0x10000000, 0x00800000, MT_DEVICE }, /* SA1111 */
+ };
+ static void __init lubbock_map_io(void)
+--- linux-2.6.0-test6/arch/arm/mach-pxa/pm.c   2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/arm/mach-pxa/pm.c  2003-10-05 00:33:23.000000000 -0700
+@@ -11,13 +11,14 @@
+  * modify it under the terms of the GNU General Public License.
+  */
+ #include <linux/config.h>
++#include <linux/init.h>
++#include <linux/suspend.h>
+ #include <linux/errno.h>
+ #include <linux/time.h>
+ #include <asm/hardware.h>
+ #include <asm/memory.h>
+ #include <asm/system.h>
+-#include <asm/leds.h>
+ /*
+@@ -60,13 +61,16 @@ enum {     SLEEP_SAVE_START = 0,
+ };
+-int pm_do_suspend(void)
++static int pxa_pm_enter(u32 state)
+ {
+       unsigned long sleep_save[SLEEP_SAVE_SIZE];
+       unsigned long checksum = 0;
+       unsigned long delta;
+       int i;
++      if (state != PM_SUSPEND_MEM)
++              return -EINVAL;
++
+       /* preserve current time */
+       delta = xtime.tv_sec - RCNR;
+@@ -194,3 +198,37 @@ unsigned long sleep_phys_sp(void *sp)
+ {
+       return virt_to_phys(sp);
+ }
++
++/*
++ * Called after processes are frozen, but before we shut down devices.
++ */
++static int pxa_pm_prepare(u32 state)
++{
++      return 0;
++}
++
++/*
++ * Called after devices are re-setup, but before processes are thawed.
++ */
++static int pxa_pm_finish(u32 state)
++{
++      return 0;
++}
++
++/*
++ * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
++ */
++static struct pm_ops pxa_pm_ops = {
++      .pm_disk_mode   = PM_DISK_FIRMWARE,
++      .prepare        = pxa_pm_prepare,
++      .enter          = pxa_pm_enter,
++      .finish         = pxa_pm_finish,
++};
++
++static int __init pxa_pm_init(void)
++{
++      pm_set_ops(&pxa_pm_ops);
++      return 0;
++}
++
++late_initcall(pxa_pm_init);
+--- linux-2.6.0-test6/arch/arm/mach-sa1100/leds.c      2003-09-08 13:58:55.000000000 -0700
++++ 25/arch/arm/mach-sa1100/leds.c     2003-10-05 00:33:23.000000000 -0700
+@@ -5,6 +5,7 @@
+  * 
+  * Copyright (C) 2001 Nicolas Pitre
+  */
++#include <linux/compiler.h>
+ #include <linux/init.h>
+ #include <asm/leds.h>
+--- linux-2.6.0-test6/arch/arm/mach-sa1100/pm.c        2003-09-08 13:58:55.000000000 -0700
++++ 25/arch/arm/mach-sa1100/pm.c       2003-10-05 00:33:23.000000000 -0700
+@@ -22,6 +22,8 @@
+  * 2002-05-27:        Nicolas Pitre   Killed sleep.h and the kmalloced save array.
+  *                            Storage is local on the stack now.
+  */
++#include <linux/init.h>
++#include <linux/suspend.h>
+ #include <linux/errno.h>
+ #include <linux/time.h>
+@@ -54,11 +56,14 @@ enum {     SLEEP_SAVE_SP = 0,
+ };
+-int pm_do_suspend(void)
++static int sa11x0_pm_enter(u32 state)
+ {
+       unsigned long sleep_save[SLEEP_SAVE_SIZE];
+       unsigned long delta, gpio;
++      if (state != PM_SUSPEND_MEM)
++              return -EINVAL;
++
+       /* preserve current time */
+       delta = xtime.tv_sec - RCNR;
+       gpio = GPLR;
+@@ -139,3 +144,37 @@ unsigned long sleep_phys_sp(void *sp)
+ {
+       return virt_to_phys(sp);
+ }
++
++/*
++ * Called after processes are frozen, but before we shut down devices.
++ */
++static int sa11x0_pm_prepare(u32 state)
++{
++      return 0;
++}
++
++/*
++ * Called after devices are re-setup, but before processes are thawed.
++ */
++static int sa11x0_pm_finish(u32 state)
++{
++      return 0;
++}
++
++/*
++ * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
++ */
++static struct pm_ops sa11x0_pm_ops = {
++      .pm_disk_mode   = PM_DISK_FIRMWARE,
++      .prepare        = sa11x0_pm_prepare,
++      .enter          = sa11x0_pm_enter,
++      .finish         = sa11x0_pm_finish,
++};
++
++static int __init sa11x0_pm_init(void)
++{
++      pm_set_ops(&sa11x0_pm_ops);
++      return 0;
++}
++
++late_initcall(sa11x0_pm_init);
+--- linux-2.6.0-test6/arch/arm/Makefile        2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/arm/Makefile       2003-10-05 00:33:23.000000000 -0700
+@@ -182,7 +182,6 @@ define archhelp
+   echo  '* zImage        - Compressed kernel image (arch/$(ARCH)/boot/zImage)'
+   echo  '  Image         - Uncompressed kernel image (arch/$(ARCH)/boot/Image)'
+   echo  '  bootpImage    - Combined zImage and initial RAM disk' 
+-  echo  '  initrd        - Create an initial image'
+   echo  '  install       - Install uncompressed kernel'
+   echo  '  zinstall      - Install compressed kernel'
+   echo  '                  Install using (your) ~/bin/installkernel or'
+--- linux-2.6.0-test6/arch/arm/mm/discontig.c  2003-06-14 12:18:31.000000000 -0700
++++ 25/arch/arm/mm/discontig.c 2003-10-05 00:34:40.000000000 -0700
+@@ -15,7 +15,7 @@
+ #include <linux/init.h>
+ #include <linux/bootmem.h>
+-#if NR_NODES != 4
++#if MAX_NUMNODES != 4
+ #error Fix Me Please
+ #endif
+@@ -23,9 +23,9 @@
+  * Our node_data structure for discontiguous memory.
+  */
+-static bootmem_data_t node_bootmem_data[NR_NODES];
++static bootmem_data_t node_bootmem_data[MAX_NUMNODES];
+-pg_data_t discontig_node_data[NR_NODES] = {
++pg_data_t discontig_node_data[MAX_NUMNODES] = {
+   { .bdata = &node_bootmem_data[0] },
+   { .bdata = &node_bootmem_data[1] },
+   { .bdata = &node_bootmem_data[2] },
+--- linux-2.6.0-test6/arch/arm/mm/init.c       2003-07-10 18:50:30.000000000 -0700
++++ 25/arch/arm/mm/init.c      2003-10-05 00:34:40.000000000 -0700
+@@ -33,12 +33,6 @@
+ #include <asm/mach/arch.h>
+ #include <asm/mach/map.h>
+-#ifndef CONFIG_DISCONTIGMEM
+-#define NR_NODES      1
+-#else
+-#define NR_NODES      4
+-#endif
+-
+ #ifdef CONFIG_CPU_32
+ #define TABLE_OFFSET  (PTRS_PER_PTE)
+ #else
+@@ -178,7 +172,7 @@ find_memend_and_nodes(struct meminfo *mi
+ {
+       unsigned int i, bootmem_pages = 0, memend_pfn = 0;
+-      for (i = 0; i < NR_NODES; i++) {
++      for (i = 0; i < MAX_NUMNODES; i++) {
+               np[i].start = -1U;
+               np[i].end = 0;
+               np[i].bootmap_pages = 0;
+@@ -207,7 +201,7 @@ find_memend_and_nodes(struct meminfo *mi
+                        * we have, we're in trouble.  (maybe we ought to
+                        * limit, instead of bugging?)
+                        */
+-                      if (numnodes > NR_NODES)
++                      if (numnodes > MAX_NUMNODES)
+                               BUG();
+               }
+@@ -365,7 +359,7 @@ static inline void free_bootmem_node_ban
+  */
+ void __init bootmem_init(struct meminfo *mi)
+ {
+-      struct node_info node_info[NR_NODES], *np = node_info;
++      struct node_info node_info[MAX_NUMNODES], *np = node_info;
+       unsigned int bootmap_pages, bootmap_pfn, map_pg;
+       int node, initrd_node;
+--- linux-2.6.0-test6/arch/arm/mm/ioremap.c    2003-06-14 12:18:24.000000000 -0700
++++ 25/arch/arm/mm/ioremap.c   2003-10-05 00:33:23.000000000 -0700
+@@ -150,7 +150,7 @@ __ioremap(unsigned long phys_addr, size_
+       if (!area)
+               return NULL;
+       addr = area->addr;
+-      if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size, flags)) {
++      if (remap_area_pages((unsigned long) addr, phys_addr, size, flags)) {
+               vfree(addr);
+               return NULL;
+       }
+--- linux-2.6.0-test6/arch/cris/mm/ioremap.c   2003-07-10 18:50:30.000000000 -0700
++++ 25/arch/cris/mm/ioremap.c  2003-10-05 00:33:23.000000000 -0700
+@@ -157,7 +157,7 @@ void * __ioremap(unsigned long phys_addr
+       if (!area)
+               return NULL;
+       addr = area->addr;
+-      if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size, flags)) {
++      if (remap_area_pages((unsigned long) addr, phys_addr, size, flags)) {
+               vfree(addr);
+               return NULL;
+       }
+--- linux-2.6.0-test6/arch/h8300/README        2003-06-14 12:18:26.000000000 -0700
++++ 25/arch/h8300/README       2003-10-05 00:33:23.000000000 -0700
+@@ -16,7 +16,7 @@ H8S is planning.
+ 3.H8MAX 
+   Under development
+-  see http://www.strawbelly-linux.com (Japanese Only)
++  see http://www.strawberry-linux.com (Japanese Only)
+ * Toolchain Version
+ gcc-3.1 or higher and patch
+--- linux-2.6.0-test6/arch/i386/boot/setup.S   2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/i386/boot/setup.S  2003-10-05 00:36:48.000000000 -0700
+@@ -162,7 +162,7 @@ cmd_line_ptr:      .long 0                 # (Header versio
+                                       # can be located anywhere in
+                                       # low memory 0x10000 or higher.
+-ramdisk_max:  .long MAXMEM-1          # (Header version 0x0203 or later)
++ramdisk_max:  .long __MAXMEM-1        # (Header version 0x0203 or later)
+                                       # The highest safe address for
+                                       # the contents of an initrd
+--- linux-2.6.0-test6/arch/i386/Kconfig        2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/i386/Kconfig       2003-10-05 00:36:48.000000000 -0700
+@@ -397,6 +397,54 @@ config X86_OOSTORE
+       depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6
+       default y
++config X86_4G
++      bool "4 GB kernel-space and 4 GB user-space virtual memory support"
++      help
++          This option is only useful for systems that have more than 1 GB
++          of RAM.
++
++          The default kernel VM layout leaves 1 GB of virtual memory for
++          kernel-space mappings, and 3 GB of VM for user-space applications.
++          This option ups both the kernel-space VM and the user-space VM to
++          4 GB.
++
++          The cost of this option is additional TLB flushes done at
++          system-entry points that transition from user-mode into kernel-mode.
++          I.e. system calls and page faults, and IRQs that interrupt user-mode
++          code. There's also additional overhead to kernel operations that copy
++          memory to/from user-space. The overhead from this is hard to tell and
++          depends on the workload - it can be anything from no visible overhead
++          to 20-30% overhead. A good rule of thumb is to count with a runtime
++          overhead of 20%.
++
++          The upside is the much increased kernel-space VM, which more than
++          quadruples the maximum amount of RAM supported. Kernels compiled with
++          this option boot on 64GB of RAM and still have more than 3.1 GB of
++          'lowmem' left. Another bonus is that highmem IO bouncing decreases,
++          if used with drivers that still use bounce-buffers.
++
++          There's also a 33% increase in user-space VM size - database
++          applications might see a boost from this.
++
++          But the cost of the TLB flushes and the runtime overhead has to be
++          weighed against the bonuses offered by the larger VM spaces. The
++          dividing line depends on the actual workload - there might be 4 GB
++          systems that benefit from this option. Systems with less than 4 GB
++          of RAM will rarely see a benefit from this option - but it's not
++          out of question, the exact circumstances have to be considered.
++
++config X86_SWITCH_PAGETABLES
++      def_bool X86_4G
++
++config X86_4G_VM_LAYOUT
++      def_bool X86_4G
++
++config X86_UACCESS_INDIRECT
++      def_bool X86_4G
++
++config X86_HIGH_ENTRY
++      def_bool X86_4G
++
+ config HPET_TIMER
+       bool "HPET Timer Support"
+       help
+@@ -793,7 +841,8 @@ config HAVE_DEC_LOCK
+ # Summit needs it only when NUMA is on
+ config BOOT_IOREMAP
+       bool
+-      depends on ((X86_SUMMIT || X86_GENERICARCH) && NUMA)
++      depends on X86_PC
++# depends on (((X86_SUMMIT || X86_GENERICARCH) && NUMA)) || X86_GENERICARCH
+       default y
+ endmenu
+@@ -1030,6 +1079,25 @@ config PCI_DIRECT
+       depends on PCI && ((PCI_GODIRECT || PCI_GOANY) || X86_VISWS)
+       default y
++config PCI_USE_VECTOR
++      bool "Vector-based interrupt indexing"
++      depends on X86_LOCAL_APIC
++      default n
++      help
++         This replaces the current existing IRQ-based index interrupt scheme
++         with the vector-base index scheme. The advantages of vector base
++         over IRQ base are listed below:
++         1) Support MSI implementation.
++         2) Support future IOxAPIC hotplug
++
++         Note that this enables MSI, Message Signaled Interrupt, on all
++         MSI capable device functions detected if users also install the
++         MSI patch. Message Signal Interrupt enables an MSI-capable
++         hardware device to send an inbound Memory Write on its PCI bus
++         instead of asserting IRQ signal on device IRQ pin.
++
++         If you don't know what to do here, say N.
++
+ source "drivers/pci/Kconfig"
+ config ISA
+@@ -1231,6 +1299,15 @@ config DEBUG_PAGEALLOC
+         This results in a large slowdown, but helps to find certain types
+         of memory corruptions.
++config SPINLINE
++      bool "Spinlock inlining"
++      depends on DEBUG_KERNEL
++      help
++        This will change spinlocks from out of line to inline, making them
++        account cost to the callers in readprofile, rather than the lock
++        itself (as ".text.lock.filename"). This can be helpful for finding
++        the callers of locks.
++
+ config DEBUG_HIGHMEM
+       bool "Highmem debugging"
+       depends on DEBUG_KERNEL && HIGHMEM
+@@ -1247,20 +1324,208 @@ config DEBUG_INFO
+         Say Y here only if you plan to use gdb to debug the kernel.
+         If you don't debug the kernel, you can say N.
+         
++config LOCKMETER
++      bool "Kernel lock metering"
++      depends on SMP && !PREEMPT
++      help
++        Say Y to enable kernel lock metering, which adds overhead to SMP locks,
++        but allows you to see various statistics using the lockstat command.
++
+ config DEBUG_SPINLOCK_SLEEP
+       bool "Sleep-inside-spinlock checking"
+       help
+         If you say Y here, various routines which may sleep will become very
+         noisy if they are called with a spinlock held.        
++config KGDB
++      bool "Include kgdb kernel debugger"
++      depends on DEBUG_KERNEL
++      help
++        If you say Y here, the system will be compiled with the debug
++        option (-g) and a debugging stub will be included in the
++        kernel.  This stub communicates with gdb on another (host)
++        computer via a serial port.  The host computer should have
++        access to the kernel binary file (vmlinux) and a serial port
++        that is connected to the target machine.  Gdb can be made to
++        configure the serial port or you can use stty and setserial to
++        do this. See the 'target' command in gdb. This option also
++        configures in the ability to request a breakpoint early in the
++        boot process.  To request the breakpoint just include 'kgdb'
++        as a boot option when booting the target machine.  The system
++        will then break as soon as it looks at the boot options.  This
++        option also installs a breakpoint in panic and sends any
++        kernel faults to the debugger. For more information see the
++        Documentation/i386/kgdb.txt file.
++
++choice
++      depends on KGDB
++      prompt "Debug serial port BAUD"
++      default KGDB_115200BAUD
++      help
++        Gdb and the kernel stub need to agree on the baud rate to be
++        used.  Some systems (x86 family at this writing) allow this to
++        be configured.
++
++config KGDB_9600BAUD
++      bool "9600"
++
++config KGDB_19200BAUD
++      bool "19200"
++
++config KGDB_38400BAUD
++      bool "38400"
++
++config KGDB_57600BAUD
++      bool "57600"
++
++config KGDB_115200BAUD
++      bool "115200"
++endchoice
++
++config KGDB_PORT
++      hex "hex I/O port address of the debug serial port"
++      depends on KGDB
++      default  3f8
++      help
++        Some systems (x86 family at this writing) allow the port
++        address to be configured.  The number entered is assumed to be
++        hex, don't put 0x in front of it.  The standard address are:
++        COM1 3f8 , irq 4 and COM2 2f8 irq 3.  Setserial /dev/ttySx
++        will tell you what you have.  It is good to test the serial
++        connection with a live system before trying to debug.
++
++config KGDB_IRQ
++      int "IRQ of the debug serial port"
++      depends on KGDB
++      default 4
++      help
++        This is the irq for the debug port.  If everything is working
++        correctly and the kernel has interrupts on a control C to the
++        port should cause a break into the kernel debug stub.
++
++config DEBUG_INFO
++      bool
++      depends on KGDB
++      default y
++
++config KGDB_MORE
++      bool "Add any additional compile options"
++      depends on KGDB
++      default n
++      help
++        Saying yes here turns on the ability to enter additional
++        compile options.
++
++
++config KGDB_OPTIONS
++      depends on KGDB_MORE
++      string "Additional compile arguments"
++      default "-O1"
++      help
++        This option allows you enter additional compile options for
++        the whole kernel compile.  Each platform will have a default
++        that seems right for it.  For example on PPC "-ggdb -O1", and
++        for i386 "-O1".  Note that by configuring KGDB "-g" is already
++        turned on.  In addition, on i386 platforms
++        "-fomit-frame-pointer" is deleted from the standard compile
++        options.
++
++config NO_KGDB_CPUS
++      int "Number of CPUs"
++      depends on KGDB && SMP
++      default NR_CPUS
++      help
++
++        This option sets the number of cpus for kgdb ONLY.  It is used
++        to prune some internal structures so they look "nice" when
++        displayed with gdb.  This is to overcome possibly larger
++        numbers that may have been entered above.  Enter the real
++        number to get nice clean kgdb_info displays.
++
++config KGDB_TS
++      bool "Enable kgdb time stamp macros?"
++      depends on KGDB
++      default n
++      help
++        Kgdb event macros allow you to instrument your code with calls
++        to the kgdb event recording function.  The event log may be
++        examined with gdb at a break point.  Turning on this
++        capability also allows you to choose how many events to
++        keep. Kgdb always keeps the lastest events.
++
++choice
++      depends on KGDB_TS
++      prompt "Max number of time stamps to save?"
++      default KGDB_TS_128
++
++config KGDB_TS_64
++      bool "64"
++
++config KGDB_TS_128
++      bool "128"
++
++config KGDB_TS_256
++      bool "256"
++
++config KGDB_TS_512
++      bool "512"
++
++config KGDB_TS_1024
++      bool "1024"
++
++endchoice
++
++config STACK_OVERFLOW_TEST
++      bool "Turn on kernel stack overflow testing?"
++      depends on KGDB
++      default n
++      help
++        This option enables code in the front line interrupt handlers
++        to check for kernel stack overflow on interrupts and system
++        calls.  This is part of the kgdb code on x86 systems.
++
++config KGDB_CONSOLE
++      bool "Enable serial console thru kgdb port"
++      depends on KGDB
++      default n
++      help
++        This option enables the command line "console=kgdb" option.
++        When the system is booted with this option in the command line
++        all kernel printk output is sent to gdb (as well as to other
++        consoles).  For this to work gdb must be connected.  For this
++        reason, this command line option will generate a breakpoint if
++        gdb has not yet connected.  After the gdb continue command is
++        given all pent up console output will be printed by gdb on the
++        host machine.  Neither this option, nor KGDB require the
++        serial driver to be configured.
++
++config KGDB_SYSRQ
++      bool "Turn on SysRq 'G' command to do a break?"
++      depends on KGDB
++      default y
++      help
++        This option includes an option in the SysRq code that allows
++        you to enter SysRq G which generates a breakpoint to the KGDB
++        stub.  This will work if the keyboard is alive and can
++        interrupt the system.  Because of constraints on when the
++        serial port interrupt can be enabled, this code may allow you
++        to interrupt the system before the serial port control C is
++        available.  Just say yes here.
++
+ config FRAME_POINTER
+       bool "Compile the kernel with frame pointers"
++      default KGDB
+       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.
++config MAGIC_SYSRQ
++      bool
++      depends on KGDB_SYSRQ
++      default y
++
+ config X86_EXTRA_IRQS
+       bool
+       depends on X86_LOCAL_APIC || X86_VOYAGER
+@@ -1303,3 +1568,8 @@ config X86_TRAMPOLINE
+       bool
+       depends on SMP || X86_VISWS
+       default y
++
++config PC
++      bool
++      depends on X86 && !EMBEDDED
++      default y
+--- linux-2.6.0-test6/arch/i386/kernel/acpi/boot.c     2003-09-08 13:58:55.000000000 -0700
++++ 25/arch/i386/kernel/acpi/boot.c    2003-10-05 00:36:22.000000000 -0700
+@@ -26,6 +26,7 @@
+ #include <linux/init.h>
+ #include <linux/config.h>
+ #include <linux/acpi.h>
++#include <linux/efi.h>
+ #include <asm/pgalloc.h>
+ #include <asm/io_apic.h>
+ #include <asm/apic.h>
+@@ -183,8 +184,7 @@ acpi_parse_lapic_nmi (
+ #endif /*CONFIG_X86_LOCAL_APIC*/
+-#ifdef CONFIG_X86_IO_APIC
+-
++#if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_ACPI_INTERPRETER)
+ static int __init
+ acpi_parse_ioapic (
+@@ -297,6 +297,10 @@ acpi_find_rsdp (void)
+ {
+       unsigned long           rsdp_phys = 0;
++      if (efi.acpi20)
++              return __pa(efi.acpi20);
++      else if (efi.acpi)
++              return __pa(efi.acpi);
+       /*
+        * Scan memory looking for the RSDP signature. First search EBDA (low
+        * memory) paragraphs and then search upper memory (E0000-FFFFF).
+@@ -368,7 +372,6 @@ acpi_boot_init (void)
+       result = acpi_table_parse(ACPI_APIC, acpi_parse_madt);
+       if (!result) {
+-              printk(KERN_WARNING PREFIX "MADT not present\n");
+               return 0;
+       }
+       else if (result < 0) {
+@@ -416,7 +419,7 @@ acpi_boot_init (void)
+ #endif /*CONFIG_X86_LOCAL_APIC*/
+-#ifdef CONFIG_X86_IO_APIC
++#if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_ACPI_INTERPRETER)
+       /* 
+        * I/O APIC 
+@@ -472,7 +475,8 @@ acpi_boot_init (void)
+       acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC;
+       acpi_ioapic = 1;
+-#endif /*CONFIG_X86_IO_APIC*/
++
++#endif /* CONFIG_X86_IO_APIC && CONFIG_ACPI_INTERPRETER */
+ #ifdef CONFIG_X86_LOCAL_APIC
+       if (acpi_lapic && acpi_ioapic) {
+@@ -480,6 +484,7 @@ acpi_boot_init (void)
+               clustered_apic_check();
+       }
+ #endif
++
+ #ifdef CONFIG_HPET_TIMER
+       acpi_table_parse(ACPI_HPET, acpi_parse_hpet);
+ #endif
+--- linux-2.6.0-test6/arch/i386/kernel/asm-offsets.c   2003-06-14 12:18:07.000000000 -0700
++++ 25/arch/i386/kernel/asm-offsets.c  2003-10-05 00:36:48.000000000 -0700
+@@ -4,9 +4,11 @@
+  * to extract and format the required data.
+  */
++#include <linux/sched.h>
+ #include <linux/signal.h>
+ #include <asm/ucontext.h>
+ #include "sigframe.h"
++#include <asm/fixmap.h>
+ #define DEFINE(sym, val) \
+         asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+@@ -28,4 +30,17 @@ void foo(void)
+       DEFINE(RT_SIGFRAME_sigcontext,
+              offsetof (struct rt_sigframe, uc.uc_mcontext));
++      DEFINE(TI_task, offsetof (struct thread_info, task));
++      DEFINE(TI_exec_domain, offsetof (struct thread_info, exec_domain));
++      DEFINE(TI_flags, offsetof (struct thread_info, flags));
++      DEFINE(TI_preempt_count, offsetof (struct thread_info, preempt_count));
++      DEFINE(TI_addr_limit, offsetof (struct thread_info, addr_limit));
++      DEFINE(TI_real_stack, offsetof (struct thread_info, real_stack));
++      DEFINE(TI_virtual_stack, offsetof (struct thread_info, virtual_stack));
++      DEFINE(TI_user_pgd, offsetof (struct thread_info, user_pgd));
++
++      DEFINE(FIX_ENTRY_TRAMPOLINE_0_addr, __fix_to_virt(FIX_ENTRY_TRAMPOLINE_0));
++      DEFINE(FIX_VSYSCALL_addr, __fix_to_virt(FIX_VSYSCALL));
++      DEFINE(PAGE_SIZE_asm, PAGE_SIZE);
++      DEFINE(task_thread_db7, offsetof (struct task_struct, thread.debugreg[7]));
+ }
+--- linux-2.6.0-test6/arch/i386/kernel/cpu/common.c    2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/i386/kernel/cpu/common.c   2003-10-05 00:36:48.000000000 -0700
+@@ -510,16 +510,20 @@ void __init cpu_init (void)
+               BUG();
+       enter_lazy_tlb(&init_mm, current);
+-      load_esp0(t, thread->esp0);
+-      set_tss_desc(cpu,t);
++      t->esp0 = thread->esp0;
++      set_tss_desc(cpu, t);
+       cpu_gdt_table[cpu][GDT_ENTRY_TSS].b &= 0xfffffdff;
+       load_TR_desc();
+-      load_LDT(&init_mm.context);
++      if (cpu)
++              load_LDT(&init_mm.context);
+       /* Set up doublefault TSS pointer in the GDT */
+       __set_tss_desc(cpu, GDT_ENTRY_DOUBLEFAULT_TSS, &doublefault_tss);
+       cpu_gdt_table[cpu][GDT_ENTRY_DOUBLEFAULT_TSS].b &= 0xfffffdff;
++      if (cpu)
++              trap_init_virtual_GDT();
++
+       /* Clear %fs and %gs. */
+       asm volatile ("xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs");
+--- linux-2.6.0-test6/arch/i386/kernel/cpu/cpufreq/acpi.c      2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/i386/kernel/cpu/cpufreq/acpi.c     2003-10-05 00:33:23.000000000 -0700
+@@ -231,7 +231,7 @@ acpi_processor_set_performance (
+       int                     state)
+ {
+       u16                     port = 0;
+-      u8                      value = 0;
++      u16                     value = 0;
+       int                     i = 0;
+       struct cpufreq_freqs    cpufreq_freqs;
+@@ -282,9 +282,9 @@ acpi_processor_set_performance (
+       value = (u16) perf->states[state].control;
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
+-              "Writing 0x%02x to port 0x%04x\n", value, port));
++              "Writing 0x%04x to port 0x%04x\n", value, port));
+-      outb(value, port); 
++      outw(value, port); 
+       /*
+        * Then we read the 'status_register' and compare the value with the
+@@ -296,12 +296,12 @@ acpi_processor_set_performance (
+       port = perf->status_register;
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
+-              "Looking for 0x%02x from port 0x%04x\n",
+-              (u8) perf->states[state].status, port));
++              "Looking for 0x%04x from port 0x%04x\n",
++              (u16) perf->states[state].status, port));
+       for (i=0; i<100; i++) {
+-              value = inb(port);
+-              if (value == (u8) perf->states[state].status)
++              value = inw(port);
++              if (value == (u16) perf->states[state].status)
+                       break;
+               udelay(10);
+       }
+@@ -309,7 +309,7 @@ acpi_processor_set_performance (
+       /* notify cpufreq */
+       cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE);
+-      if (value != perf->states[state].status) {
++      if (value != (u16) perf->states[state].status) {
+               unsigned int tmp = cpufreq_freqs.new;
+               cpufreq_freqs.new = cpufreq_freqs.old;
+               cpufreq_freqs.old = tmp;
+--- linux-2.6.0-test6/arch/i386/kernel/cpu/cpufreq/Kconfig     2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/i386/kernel/cpu/cpufreq/Kconfig    2003-10-05 00:33:23.000000000 -0700
+@@ -88,6 +88,16 @@ config X86_POWERNOW_K7
+         If in doubt, say N.
++config X86_POWERNOW_K8
++      tristate "AMD Opteron/Athlon64 PowerNow!"
++      depends on CPU_FREQ_TABLE
++      help
++        This adds the CPUFreq driver for mobile AMD Opteron/Athlon64 processors.
++
++        For details, take a look at linux/Documentation/cpu-freq. 
++
++        If in doubt, say N.
++
+ config X86_GX_SUSPMOD
+       tristate "Cyrix MediaGX/NatSemi Geode Suspend Modulation"
+       depends on CPU_FREQ
+--- linux-2.6.0-test6/arch/i386/kernel/cpu/cpufreq/longhaul.c  2003-09-08 13:58:55.000000000 -0700
++++ 25/arch/i386/kernel/cpu/cpufreq/longhaul.c 2003-10-05 00:33:23.000000000 -0700
+@@ -70,21 +70,6 @@ static unsigned int calc_speed (int mult
+ }
+-static unsigned int longhaul_get_cpu_fsb (void)
+-{
+-      unsigned long lo, hi;
+-      unsigned int eblcr_fsb_table[] = { 66, 133, 100, -1 };
+-      unsigned int invalue=0;
+-
+-      if (fsb == 0) {
+-              rdmsr (MSR_IA32_EBL_CR_POWERON, lo, hi);
+-              invalue = (lo & (1<<18|1<<19)) >>18;
+-              fsb = eblcr_fsb_table[invalue];
+-      }
+-      return fsb;
+-}
+-
+-
+ static int longhaul_get_cpu_mult (void)
+ {
+       unsigned long invalue=0,lo, hi;
+@@ -168,7 +153,7 @@ static void longhaul_setstate (unsigned 
+               break;
+       /*
+-       * Longhaul v3. (Ezra-T [C5M], Nehemiag [C5N])
++       * Longhaul v3. (Ezra-T [C5M], Nehemiah [C5N])
+        * This can also do voltage scaling, but see above.
+        * Ezra-T was alleged to do FSB scaling too, but it never worked in practice.
+        */
+@@ -193,6 +178,39 @@ static void longhaul_setstate (unsigned 
+       cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ }
++/*
++ * Centaur decided to make life a little more tricky.
++ * Only longhaul v1 is allowed to read EBLCR BSEL[0:1].
++ * Samuel2 and above have to try and guess what the FSB is.
++ * We do this by assuming we booted at maximum multiplier, and interpolate
++ * between that value multiplied by possible FSBs and cpu_mhz which
++ * was calculated at boot time. Really ugly, but no other way to do this.
++ */
++static int _guess (int guess, int maxmult)
++{
++      int target;
++
++      target = ((maxmult/10)*guess);
++      if (maxmult%10 != 0)
++              target += (guess/2);
++      target &= ~0xf;
++      return target;
++}
++
++static int guess_fsb(int maxmult)
++{
++      int speed = (cpu_khz/1000) & ~0xf;
++      int i;
++      int speeds[3] = { 66, 100, 133 };
++
++      for (i=0; i<3; i++) {
++              if (_guess(speeds[i],maxmult) == speed)
++                      return speeds[i];
++      }
++      return 0;
++}
++
++
+ static int __init longhaul_get_ranges (void)
+ {
+@@ -203,8 +221,8 @@ static int __init longhaul_get_ranges (v
+               -1,110,120,-1,135,115,125,105,130,150,160,140,-1,155,-1,145 };
+       unsigned int j, k = 0;
+       union msr_longhaul longhaul;
+-
+-      fsb = longhaul_get_cpu_fsb();
++      unsigned long lo, hi;
++      unsigned int eblcr_fsb_table[] = { 66, 133, 100, -1 };
+       switch (longhaul_version) {
+       case 1:
+@@ -212,6 +230,9 @@ static int __init longhaul_get_ranges (v
+                  Assume min=3.0x & max = whatever we booted at. */
+               minmult = 30;
+               maxmult = longhaul_get_cpu_mult();
++              rdmsr (MSR_IA32_EBL_CR_POWERON, lo, hi);
++              invalue = (lo & (1<<18|1<<19)) >>18;
++              fsb = eblcr_fsb_table[invalue];
+               break;
+       case 2 ... 3:
+@@ -222,14 +243,13 @@ static int __init longhaul_get_ranges (v
+                       invalue += 16;
+               maxmult=multipliers[invalue];
+-#if 0
+               invalue = longhaul.bits.MinMHzBR;
+-              if (longhaul.bits.MinMHzBR4);
+-                      invalue += 16;
+-              minmult = multipliers[invalue];
+-#else
+-              minmult = 30; /* as per spec */
+-#endif
++              if (longhaul.bits.MinMHzBR4 == 1)
++                      minmult = 30;
++              else
++                      minmult = multipliers[invalue];
++
++              fsb = guess_fsb(maxmult);
+               break;
+       }
+--- linux-2.6.0-test6/arch/i386/kernel/cpu/cpufreq/Makefile    2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/i386/kernel/cpu/cpufreq/Makefile   2003-10-05 00:33:23.000000000 -0700
+@@ -1,5 +1,6 @@
+ obj-$(CONFIG_X86_POWERNOW_K6) += powernow-k6.o
+ obj-$(CONFIG_X86_POWERNOW_K7) += powernow-k7.o
++obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o
+ obj-$(CONFIG_X86_LONGHAUL)    += longhaul.o
+ obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o
+ obj-$(CONFIG_ELAN_CPUFREQ)    += elanfreq.o
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/arch/i386/kernel/cpu/cpufreq/powernow-k8.c      2003-10-05 00:33:23.000000000 -0700
+@@ -0,0 +1,1020 @@
++/*
++ *   (c) 2003 Advanced Micro Devices, Inc.
++ *  Your use of this code is subject to the terms and conditions of the
++ *  GNU general public license version 2. See "../../../COPYING" or
++ *  http://www.gnu.org/licenses/gpl.html
++ *
++ *  Support : paul.devriendt@amd.com
++ *
++ *  Based on the powernow-k7.c module written by Dave Jones.
++ *  (C) 2003 Dave Jones <davej@codemonkey.ork.uk> on behalf of SuSE Labs
++ *  Licensed under the terms of the GNU GPL License version 2.
++ *  Based upon datasheets & sample CPUs kindly provided by AMD.
++ *
++ *  Processor information obtained from Chapter 9 (Power and Thermal Management)
++ *  of the "BIOS and Kernel Developer's Guide for the AMD Athlon 64 and AMD
++ *  Opteron Processors", revision 3.03, available for download from www.amd.com
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/smp.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/cpufreq.h>
++#include <linux/slab.h>
++#include <linux/string.h>
++
++#include <asm/msr.h>
++#include <asm/io.h>
++#include <asm/delay.h>
++
++#define PFX "powernow-k8: "
++#define BFX PFX "BIOS error: "
++#define VERSION "version 1.00.08 - September 26, 2003"
++#include "powernow-k8.h"
++
++#ifdef CONFIG_PREEMPT
++#warning this driver has not been tested on a preempt system
++#endif
++
++static u32 vstable;   /* voltage stabalization time, from PSB, units 20 us */
++static u32 plllock;   /* pll lock time, from PSB, units 1 us */
++static u32 numps;     /* number of p-states, from PSB */
++static u32 rvo;               /* ramp voltage offset, from PSB */
++static u32 irt;               /* isochronous relief time, from PSB */
++static u32 vidmvs;    /* usable value calculated from mvs, from PSB */
++struct pst_s *ppst;   /* array of p states, valid for this part */
++static u32 currvid;   /* keep track of the current fid / vid */
++static u32 currfid;
++
++/*
++The PSB table supplied by BIOS allows for the definition of the number of
++p-states that can be used when running on a/c, and the number of p-states
++that can be used when running on battery. This allows laptop manufacturers
++to force the system to save power when running from battery. The relationship 
++is :
++   1 <= number_of_battery_p_states <= maximum_number_of_p_states
++
++This driver does NOT have the support in it to detect transitions from
++a/c power to battery power, and thus trigger the transition to a lower
++p-state if required. This is because I need ACPI and the 2.6 kernel to do 
++this, and this is a 2.4 kernel driver. Check back for a new improved driver
++for the 2.6 kernel soon.
++
++This code therefore assumes it is on battery at all times, and thus
++restricts performance to number_of_battery_p_states. For desktops, 
++  number_of_battery_p_states == maximum_number_of_pstates, 
++so this is not actually a restriction.
++*/
++
++static u32 batps;     /* limit on the number of p states when on battery */
++                      /* - set by BIOS in the PSB/PST                    */
++
++static struct cpufreq_driver cpufreq_amd64_driver = {
++      .verify = drv_verify,
++      .target = drv_target,
++      .init = drv_cpu_init,
++      .name = "cpufreq-amd64",
++      .owner = THIS_MODULE,
++};
++
++#define SEARCH_UP     1
++#define SEARCH_DOWN   0
++
++/* Return a frequency in MHz, given an input fid */
++u32
++find_freq_from_fid(u32 fid)
++{
++      return 800 + (fid * 100);
++}
++
++/* Return a fid matching an input frequency in MHz */
++u32
++find_fid_from_freq(u32 freq)
++{
++      return (freq - 800) / 100;
++}
++
++/* Return the vco fid for an input fid */
++static u32
++convert_fid_to_vco_fid(u32 fid)
++{
++      if (fid < HI_FID_TABLE_BOTTOM) {
++              return 8 + (2 * fid);
++      } else {
++              return fid;
++      }
++}
++
++/* Sort the fid/vid frequency table into ascending order by fid. The spec */
++/* implies that it will be sorted by BIOS, but, it only implies it, and I */
++/* prefer not to trust when I can check.                                  */
++/* Yes, it is a simple bubble sort, but the PST is really small, so the   */
++/* choice of algorithm is pretty irrelevant.                              */
++static inline void
++sort_pst(struct pst_s *ppst, u32 numpstates)
++{
++      u32 i;
++      u8 tempfid;
++      u8 tempvid;
++      int swaps = 1;
++
++      while (swaps) {
++              swaps = 0;
++              for (i = 0; i < (numpstates - 1); i++) {
++                      if (ppst[i].fid > ppst[i + 1].fid) {
++                              swaps = 1;
++                              tempfid = ppst[i].fid;
++                              tempvid = ppst[i].vid;
++                              ppst[i].fid = ppst[i + 1].fid;
++                              ppst[i].vid = ppst[i + 1].vid;
++                              ppst[i + 1].fid = tempfid;
++                              ppst[i + 1].vid = tempvid;
++                      }
++              }
++      }
++
++      return;
++}
++
++/* Return 1 if the pending bit is set. Unless we are actually just told the */
++/* processor to transition a state, seeing this bit set is really bad news. */
++static inline int
++pending_bit_stuck(void)
++{
++      u32 lo;
++      u32 hi;
++
++      rdmsr(MSR_FIDVID_STATUS, lo, hi);
++      return lo & MSR_S_LO_CHANGE_PENDING ? 1 : 0;
++}
++
++/* Update the global current fid / vid values from the status msr. Returns 1 */
++/* on error.                                                                 */
++static int
++query_current_values_with_pending_wait(void)
++{
++      u32 lo;
++      u32 hi;
++      u32 i = 0;
++
++      lo = MSR_S_LO_CHANGE_PENDING;
++      while (lo & MSR_S_LO_CHANGE_PENDING) {
++              if (i++ > 0x1000000) {
++                      printk(KERN_ERR PFX "detected change pending stuck\n");
++                      return 1;
++              }
++              rdmsr(MSR_FIDVID_STATUS, lo, hi);
++      }
++
++      currvid = hi & MSR_S_HI_CURRENT_VID;
++      currfid = lo & MSR_S_LO_CURRENT_FID;
++
++      return 0;
++}
++
++/* the isochronous relief time */
++static inline void
++count_off_irt(void)
++{
++      udelay((1 << irt) * 10);
++      return;
++}
++
++/* the voltage stabalization time */
++static inline void
++count_off_vst(void)
++{
++      udelay(vstable * VST_UNITS_20US);
++      return;
++}
++
++/* write the new fid value along with the other control fields to the msr */
++static int
++write_new_fid(u32 fid)
++{
++      u32 lo;
++      u32 savevid = currvid;
++
++      if ((fid & INVALID_FID_MASK) || (currvid & INVALID_VID_MASK)) {
++              printk(KERN_ERR PFX "internal error - overflow on fid write\n");
++              return 1;
++      }
++
++      lo = fid | (currvid << MSR_C_LO_VID_SHIFT) | MSR_C_LO_INIT_FID_VID;
++
++      dprintk(KERN_DEBUG PFX "writing fid %x, lo %x, hi %x\n",
++              fid, lo, plllock * PLL_LOCK_CONVERSION);
++
++      wrmsr(MSR_FIDVID_CTL, lo, plllock * PLL_LOCK_CONVERSION);
++
++      if (query_current_values_with_pending_wait())
++              return 1;
++
++      count_off_irt();
++
++      if (savevid != currvid) {
++              printk(KERN_ERR PFX
++                     "vid changed on fid transition, save %x, currvid %x\n",
++                     savevid, currvid);
++              return 1;
++      }
++
++      if (fid != currfid) {
++              printk(KERN_ERR PFX
++                     "fid transition failed, fid %x, currfid %x\n",
++                      fid, currfid);
++              return 1;
++      }
++
++      return 0;
++}
++
++/* Write a new vid to the hardware */
++static int
++write_new_vid(u32 vid)
++{
++      u32 lo;
++      u32 savefid = currfid;
++
++      if ((currfid & INVALID_FID_MASK) || (vid & INVALID_VID_MASK)) {
++              printk(KERN_ERR PFX "internal error - overflow on vid write\n");
++              return 1;
++      }
++
++      lo = currfid | (vid << MSR_C_LO_VID_SHIFT) | MSR_C_LO_INIT_FID_VID;
++
++      dprintk(KERN_DEBUG PFX "writing vid %x, lo %x, hi %x\n",
++              vid, lo, STOP_GRANT_5NS);
++
++      wrmsr(MSR_FIDVID_CTL, lo, STOP_GRANT_5NS);
++
++      if (query_current_values_with_pending_wait()) {
++              return 1;
++      }
++
++      if (savefid != currfid) {
++              printk(KERN_ERR PFX
++                     "fid changed on vid transition, save %x currfid %x\n",
++                     savefid, currfid);
++              return 1;
++      }
++
++      if (vid != currvid) {
++              printk(KERN_ERR PFX
++                     "vid transition failed, vid %x, currvid %x\n",
++                     vid, currvid);
++              return 1;
++      }
++
++      return 0;
++}
++
++/* Reduce the vid by the max of step or reqvid.                   */
++/* Decreasing vid codes represent increasing voltages :           */
++/* vid of 0 is 1.550V, vid of 0x1e is 0.800V, vid of 0x1f is off. */
++static int
++decrease_vid_code_by_step(u32 reqvid, u32 step)
++{
++      if ((currvid - reqvid) > step)
++              reqvid = currvid - step;
++
++      if (write_new_vid(reqvid))
++              return 1;
++
++      count_off_vst();
++
++      return 0;
++}
++
++/* Change the fid and vid, by the 3 phases. */
++static inline int
++transition_fid_vid(u32 reqfid, u32 reqvid)
++{
++      if (core_voltage_pre_transition(reqvid))
++              return 1;
++
++      if (core_frequency_transition(reqfid))
++              return 1;
++
++      if (core_voltage_post_transition(reqvid))
++              return 1;
++
++      if (query_current_values_with_pending_wait())
++              return 1;
++
++      if ((reqfid != currfid) || (reqvid != currvid)) {
++              printk(KERN_ERR PFX "failed: req 0x%x 0x%x, curr 0x%x 0x%x\n",
++                     reqfid, reqvid, currfid, currvid);
++              return 1;
++      }
++
++      dprintk(KERN_INFO PFX
++              "transitioned: new fid 0x%x, vid 0x%x\n", currfid, currvid);
++
++      return 0;
++}
++
++/* Phase 1 - core voltage transition ... setup appropriate voltage for the */
++/* fid transition.                                                         */
++static inline int
++core_voltage_pre_transition(u32 reqvid)
++{
++      u32 rvosteps = rvo;
++      u32 savefid = currfid;
++
++      dprintk(KERN_DEBUG PFX
++              "ph1: start, currfid 0x%x, currvid 0x%x, reqvid 0x%x, rvo %x\n",
++              currfid, currvid, reqvid, rvo);
++
++      while (currvid > reqvid) {
++              dprintk(KERN_DEBUG PFX "ph1: curr 0x%x, requesting vid 0x%x\n",
++                      currvid, reqvid);
++              if (decrease_vid_code_by_step(reqvid, vidmvs))
++                      return 1;
++      }
++
++      while (rvosteps > 0) {
++              if (currvid == 0) {
++                      rvosteps = 0;
++              } else {
++                      dprintk(KERN_DEBUG PFX
++                              "ph1: changing vid for rvo, requesting 0x%x\n",
++                              currvid - 1);
++                      if (decrease_vid_code_by_step(currvid - 1, 1))
++                              return 1;
++                      rvosteps--;
++              }
++      }
++
++      if (query_current_values_with_pending_wait())
++              return 1;
++
++      if (savefid != currfid) {
++              printk(KERN_ERR PFX "ph1 err, currfid changed 0x%x\n", currfid);
++              return 1;
++      }
++
++      dprintk(KERN_DEBUG PFX "ph1 complete, currfid 0x%x, currvid 0x%x\n",
++              currfid, currvid);
++
++      return 0;
++}
++
++/* Phase 2 - core frequency transition */
++static inline int
++core_frequency_transition(u32 reqfid)
++{
++      u32 vcoreqfid;
++      u32 vcocurrfid;
++      u32 vcofiddiff;
++      u32 savevid = currvid;
++
++      if ((reqfid < HI_FID_TABLE_BOTTOM) && (currfid < HI_FID_TABLE_BOTTOM)) {
++              printk(KERN_ERR PFX "ph2 illegal lo-lo transition 0x%x 0x%x\n",
++                     reqfid, currfid);
++              return 1;
++      }
++
++      if (currfid == reqfid) {
++              printk(KERN_ERR PFX "ph2 null fid transition 0x%x\n", currfid);
++              return 0;
++      }
++
++      dprintk(KERN_DEBUG PFX
++              "ph2 starting, currfid 0x%x, currvid 0x%x, reqfid 0x%x\n",
++              currfid, currvid, reqfid);
++
++      vcoreqfid = convert_fid_to_vco_fid(reqfid);
++      vcocurrfid = convert_fid_to_vco_fid(currfid);
++      vcofiddiff = vcocurrfid > vcoreqfid ? vcocurrfid - vcoreqfid
++          : vcoreqfid - vcocurrfid;
++
++      while (vcofiddiff > 2) {
++              if (reqfid > currfid) {
++                      if (currfid > LO_FID_TABLE_TOP) {
++                              if (write_new_fid(currfid + 2)) {
++                                      return 1;
++                              }
++                      } else {
++                              if (write_new_fid
++                                  (2 + convert_fid_to_vco_fid(currfid))) {
++                                      return 1;
++                              }
++                      }
++              } else {
++                      if (write_new_fid(currfid - 2))
++                              return 1;
++              }
++
++              vcocurrfid = convert_fid_to_vco_fid(currfid);
++              vcofiddiff = vcocurrfid > vcoreqfid ? vcocurrfid - vcoreqfid
++                  : vcoreqfid - vcocurrfid;
++      }
++
++      if (write_new_fid(reqfid))
++              return 1;
++
++      if (query_current_values_with_pending_wait())
++              return 1;
++
++      if (currfid != reqfid) {
++              printk(KERN_ERR PFX
++                     "ph2 mismatch, failed fid transition, curr %x, req %x\n",
++                     currfid, reqfid);
++              return 1;
++      }
++
++      if (savevid != currvid) {
++              printk(KERN_ERR PFX
++                     "ph2 vid changed, save %x, curr %x\n", savevid,
++                     currvid);
++              return 1;
++      }
++
++      dprintk(KERN_DEBUG PFX "ph2 complete, currfid 0x%x, currvid 0x%x\n",
++              currfid, currvid);
++
++      return 0;
++}
++
++/* Phase 3 - core voltage transition flow ... jump to the final vid. */
++static inline int
++core_voltage_post_transition(u32 reqvid)
++{
++      u32 savefid = currfid;
++      u32 savereqvid = reqvid;
++
++      dprintk(KERN_DEBUG PFX "ph3 starting, currfid 0x%x, currvid 0x%x\n",
++              currfid, currvid);
++
++      if (reqvid != currvid) {
++              if (write_new_vid(reqvid))
++                      return 1;
++
++              if (savefid != currfid) {
++                      printk(KERN_ERR PFX
++                             "ph3: bad fid change, save %x, curr %x\n",
++                             savefid, currfid);
++                      return 1;
++              }
++
++              if (currvid != reqvid) {
++                      printk(KERN_ERR PFX
++                             "ph3: failed vid transition\n, req %x, curr %x",
++                             reqvid, currvid);
++                      return 1;
++              }
++      }
++
++      if (query_current_values_with_pending_wait())
++              return 1;
++
++      if (savereqvid != currvid) {
++              dprintk(KERN_ERR PFX "ph3 failed, currvid 0x%x\n", currvid);
++              return 1;
++      }
++
++      if (savefid != currfid) {
++              dprintk(KERN_ERR PFX "ph3 failed, currfid changed 0x%x\n",
++                      currfid);
++              return 1;
++      }
++
++      dprintk(KERN_DEBUG PFX "ph3 complete, currfid 0x%x, currvid 0x%x\n",
++              currfid, currvid);
++
++      return 0;
++}
++
++static inline int
++check_supported_cpu(void)
++{
++      struct cpuinfo_x86 *c = cpu_data;
++      u32 eax, ebx, ecx, edx;
++
++      if (num_online_cpus() != 1) {
++              printk(KERN_INFO PFX "multiprocessor systems not supported\n");
++              return 0;
++      }
++
++      if (c->x86_vendor != X86_VENDOR_AMD) {
++              printk(KERN_INFO PFX "Not an AMD processor\n");
++              return 0;
++      }
++
++      eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
++      if ((eax & CPUID_XFAM_MOD) == ATHLON64_XFAM_MOD) {
++              dprintk(KERN_DEBUG PFX "AMD Althon 64 Processor found\n");
++              if ((eax & CPUID_F1_STEP) < ATHLON64_REV_C0) {
++                      printk(KERN_INFO PFX "Revision C0 or better "
++                             "AMD Athlon 64 processor required\n");
++                      return 0;
++              }
++      } else if ((eax & CPUID_XFAM_MOD) == OPTERON_XFAM_MOD) {
++              dprintk(KERN_DEBUG PFX "AMD Opteron Processor found\n");
++      } else {
++              printk(KERN_INFO PFX
++                     "AMD Athlon 64 or AMD Opteron processor required\n");
++              return 0;
++      }
++
++      eax = cpuid_eax(CPUID_GET_MAX_CAPABILITIES);
++      if (eax < CPUID_FREQ_VOLT_CAPABILITIES) {
++              printk(KERN_INFO PFX
++                     "No frequency change capabilities detected\n");
++              return 0;
++      }
++
++      cpuid(CPUID_FREQ_VOLT_CAPABILITIES, &eax, &ebx, &ecx, &edx);
++      if ((edx & P_STATE_TRANSITION_CAPABLE) != P_STATE_TRANSITION_CAPABLE) {
++              printk(KERN_INFO PFX "Power state transitions not supported\n");
++              return 0;
++      }
++
++      printk(KERN_INFO PFX "Found AMD Athlon 64 / Opteron processor "
++             "supporting p-state transitions\n");
++
++      return 1;
++}
++
++/* Find and validate the PSB/PST table in BIOS. */
++static inline int
++find_psb_table(void)
++{
++      struct psb_s *psb;
++      struct pst_s *pst;
++      unsigned i, j;
++      u32 lastfid;
++      u32 mvs;
++      u8 maxvid;
++
++      for (i = 0xc0000; i < 0xffff0; i += 0x10) {
++              /* Scan BIOS looking for the signature. */
++              /* It can not be at ffff0 - it is too big. */
++
++              psb = phys_to_virt(i);
++              if (memcmp(psb, PSB_ID_STRING, PSB_ID_STRING_LEN) != 0)
++                      continue;
++
++              dprintk(KERN_DEBUG PFX "found PSB header at 0x%p\n", psb);
++
++              dprintk(KERN_DEBUG PFX "table vers: 0x%x\n", psb->tableversion);
++              if (psb->tableversion != PSB_VERSION_1_4) {
++                      printk(KERN_INFO BFX "PSB table is not v1.4\n");
++                      return -ENODEV;
++              }
++
++              dprintk(KERN_DEBUG PFX "flags: 0x%x\n", psb->flags1);
++              if (psb->flags1) {
++                      printk(KERN_ERR BFX "unknown flags\n");
++                      return -ENODEV;
++              }
++
++              vstable = psb->voltagestabilizationtime;
++              printk(KERN_INFO PFX "voltage stable time: %d (units 20us)\n",
++                     vstable);
++
++              dprintk(KERN_DEBUG PFX "flags2: 0x%x\n", psb->flags2);
++              rvo = psb->flags2 & 3;
++              irt = ((psb->flags2) >> 2) & 3;
++              mvs = ((psb->flags2) >> 4) & 3;
++              vidmvs = 1 << mvs;
++              batps = ((psb->flags2) >> 6) & 3;
++              printk(KERN_INFO PFX "p states on battery: %d ", batps);
++              switch (batps) {
++              case 0:
++                      printk("- all available\n");
++                      break;
++              case 1:
++                      printk("- only the minimum\n");
++                      break;
++              case 2:
++                      printk("- only the 2 lowest\n");
++                      break;
++              case 3:
++                      printk("- only the 3 lowest\n");
++                      break;
++              }
++              printk(KERN_INFO PFX "ramp voltage offset: %d\n", rvo);
++              printk(KERN_INFO PFX "isochronous relief time: %d\n", irt);
++              printk(KERN_INFO PFX "maximum voltage step: %d\n", mvs);
++
++              dprintk(KERN_DEBUG PFX "numpst: 0x%x\n", psb->numpst);
++              if (psb->numpst != 1) {
++                      printk(KERN_ERR BFX "numpst must be 1\n");
++                      return -ENODEV;
++              }
++
++              dprintk(KERN_DEBUG PFX "cpuid: 0x%x\n", psb->cpuid);
++
++              plllock = psb->plllocktime;
++              printk(KERN_INFO PFX "pll lock time: 0x%x\n", plllock);
++
++              maxvid = psb->maxvid;
++              printk(KERN_INFO PFX "maxfid: 0x%x\n", psb->maxfid);
++              printk(KERN_INFO PFX "maxvid: 0x%x\n", maxvid);
++
++              numps = psb->numpstates;
++              printk(KERN_INFO PFX "numpstates: 0x%x\n", numps);
++              if (numps < 2) {
++                      printk(KERN_ERR BFX "no p states to transition\n");
++                      return -ENODEV;
++              }
++
++              if (batps == 0) {
++                      batps = numps;
++              } else if (batps > numps) {
++                      printk(KERN_ERR BFX "batterypstates > numpstates\n");
++                      batps = numps;
++              } else {
++                      printk(KERN_ERR PFX
++                             "Restricting operation to %d p-states\n", batps);
++                      printk(KERN_ERR PFX
++                             "Check for an updated driver to access all "
++                             "%d p-states\n", numps);
++              }
++
++              if ((numps <= 1) || (batps <= 1)) {
++                      printk(KERN_ERR PFX "only 1 p-state to transition\n");
++                      return -ENODEV;
++              }
++
++              ppst = kmalloc(sizeof (struct pst_s) * numps, GFP_KERNEL);
++              if (!ppst) {
++                      printk(KERN_ERR PFX "ppst memory alloc failure\n");
++                      return -ENOMEM;
++              }
++
++              pst = (struct pst_s *) (psb + 1);
++              for (j = 0; j < numps; j++) {
++                      ppst[j].fid = pst[j].fid;
++                      ppst[j].vid = pst[j].vid;
++                      printk(KERN_INFO PFX
++                             "   %d : fid 0x%x, vid 0x%x\n", j,
++                             ppst[j].fid, ppst[j].vid);
++              }
++              sort_pst(ppst, numps);
++
++              lastfid = ppst[0].fid;
++              if (lastfid > LO_FID_TABLE_TOP)
++                      printk(KERN_INFO BFX "first fid not in lo freq tbl\n");
++
++              if ((lastfid > MAX_FID) || (lastfid & 1) || (ppst[0].vid > LEAST_VID)) {
++                      printk(KERN_ERR BFX "first fid/vid bad (0x%x - 0x%x)\n",
++                             lastfid, ppst[0].vid);
++                      kfree(ppst);
++                      return -ENODEV;
++              }
++
++              for (j = 1; j < numps; j++) {
++                      if ((lastfid >= ppst[j].fid)
++                          || (ppst[j].fid & 1)
++                          || (ppst[j].fid < HI_FID_TABLE_BOTTOM)
++                          || (ppst[j].fid > MAX_FID)
++                          || (ppst[j].vid > LEAST_VID)) {
++                              printk(KERN_ERR BFX
++                                     "invalid fid/vid in pst(%x %x)\n",
++                                     ppst[j].fid, ppst[j].vid);
++                              kfree(ppst);
++                              return -ENODEV;
++                      }
++                      lastfid = ppst[j].fid;
++              }
++
++              for (j = 0; j < numps; j++) {
++                      if (ppst[j].vid < rvo) {        /* vid+rvo >= 0 */
++                              printk(KERN_ERR BFX
++                                     "0 vid exceeded with pstate %d\n", j);
++                              return -ENODEV;
++                      }
++                      if (ppst[j].vid < maxvid+rvo) { /* vid+rvo >= maxvid */
++                              printk(KERN_ERR BFX
++                                     "maxvid exceeded with pstate %d\n", j);
++                              return -ENODEV;
++                      }
++              }
++
++              if (query_current_values_with_pending_wait()) {
++                      kfree(ppst);
++                      return -EIO;
++              }
++
++              printk(KERN_INFO PFX "currfid 0x%x, currvid 0x%x\n",
++                     currfid, currvid);
++
++              for (j = 0; j < numps; j++)
++                      if ((ppst[j].fid==currfid) && (ppst[j].vid==currvid))
++                              return (0);
++
++              printk(KERN_ERR BFX "currfid/vid do not match PST, ignoring\n");
++              return 0;
++      }
++
++      printk(KERN_ERR BFX "no PSB\n");
++      return -ENODEV;
++}
++
++/* Converts a frequency (that might not necessarily be a multiple of 200) */
++/* to a fid.                                                              */
++u32
++find_closest_fid(u32 freq, int searchup)
++{
++      if (searchup == SEARCH_UP)
++              freq += MIN_FREQ_RESOLUTION - 1;
++
++      freq = (freq / MIN_FREQ_RESOLUTION) * MIN_FREQ_RESOLUTION;
++
++      if (freq < MIN_FREQ)
++              freq = MIN_FREQ;
++      else if (freq > MAX_FREQ)
++              freq = MAX_FREQ;
++
++      return find_fid_from_freq(freq);
++}
++
++static int
++find_match(u32 * ptargfreq, u32 * pmin, u32 * pmax, int searchup, u32 * pfid,
++         u32 * pvid)
++{
++      u32 availpstates = batps;
++      u32 targfid = find_closest_fid(*ptargfreq, searchup);
++      u32 minfid = find_closest_fid(*pmin, SEARCH_DOWN);
++      u32 maxfid = find_closest_fid(*pmax, SEARCH_UP);
++      u32 minidx = 0;
++      u32 maxidx = availpstates - 1;
++      u32 targidx = 0xffffffff;
++      int i;
++
++      dprintk(KERN_DEBUG PFX "find match: freq %d MHz, min %d, max %d\n",
++              *ptargfreq, *pmin, *pmax);
++
++      /* Restrict values to the frequency choices in the PST */
++      if (minfid < ppst[0].fid)
++              minfid = ppst[0].fid;
++      if (maxfid > ppst[maxidx].fid)
++              maxfid = ppst[maxidx].fid;
++
++      /* Find appropriate PST index for the minimim fid */
++      for (i = 0; i < (int) availpstates; i++) {
++              if (minfid >= ppst[i].fid)
++                      minidx = i;
++      }
++
++      /* Find appropriate PST index for the maximum fid */
++      for (i = availpstates - 1; i >= 0; i--) {
++              if (maxfid <= ppst[i].fid)
++                      maxidx = i;
++      }
++
++      if (minidx > maxidx)
++              maxidx = minidx;
++
++      /* Frequency ids are now constrained by limits matching PST entries */
++      minfid = ppst[minidx].fid;
++      maxfid = ppst[maxidx].fid;
++
++      /* Limit the target frequency to these limits */
++      if (targfid < minfid)
++              targfid = minfid;
++      else if (targfid > maxfid)
++              targfid = maxfid;
++
++      /* Find the best target index into the PST, contrained by the range */
++      if (searchup == SEARCH_UP) {
++              for (i = maxidx; i >= (int) minidx; i--) {
++                      if (targfid <= ppst[i].fid)
++                              targidx = i;
++              }
++      } else {
++              for (i = minidx; i <= (int) maxidx; i++) {
++                      if (targfid >= ppst[i].fid)
++                              targidx = i;
++              }
++      }
++
++      if (targidx == 0xffffffff) {
++              printk(KERN_ERR PFX "could not find target\n");
++              return 1;
++      }
++
++      *pmin = find_freq_from_fid(minfid);
++      *pmax = find_freq_from_fid(maxfid);
++      *ptargfreq = find_freq_from_fid(ppst[targidx].fid);
++
++      if (pfid)
++              *pfid = ppst[targidx].fid;
++      if (pvid)
++              *pvid = ppst[targidx].vid;
++
++      return 0;
++}
++
++/* Take a frequency, and issue the fid/vid transition command */
++static inline int
++transition_frequency(u32 * preq, u32 * pmin, u32 * pmax, u32 searchup)
++{
++      u32 fid;
++      u32 vid;
++      int res;
++      struct cpufreq_freqs freqs;
++
++      if (find_match(preq, pmin, pmax, searchup, &fid, &vid))
++              return 1;
++
++      dprintk(KERN_DEBUG PFX "table matched fid 0x%x, giving vid 0x%x\n",
++              fid, vid);
++
++      if (query_current_values_with_pending_wait())
++              return 1;
++
++      if ((currvid == vid) && (currfid == fid)) {
++              dprintk(KERN_DEBUG PFX
++                      "target matches current values (fid 0x%x, vid 0x%x)\n",
++                      fid, vid);
++              return 0;
++      }
++
++      if ((fid < HI_FID_TABLE_BOTTOM) && (currfid < HI_FID_TABLE_BOTTOM)) {
++              printk(KERN_ERR PFX
++                     "ignoring illegal change in lo freq table-%x to %x\n",
++                     currfid, fid);
++              return 1;
++      }
++
++      dprintk(KERN_DEBUG PFX "changing to fid 0x%x, vid 0x%x\n", fid, vid);
++
++      freqs.cpu = 0;  /* only true because SMP not supported */
++
++      freqs.old = find_freq_from_fid(currfid);
++      freqs.new = find_freq_from_fid(fid);
++      cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
++
++      res = transition_fid_vid(fid, vid);
++
++      freqs.new = find_freq_from_fid(currfid);
++      cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
++
++      return res;
++}
++
++/* Driver entry point to switch to the target frequency */
++static int
++drv_target(struct cpufreq_policy *pol, unsigned targfreq, unsigned relation)
++{
++      u32 checkfid = currfid;
++      u32 checkvid = currvid;
++      u32 reqfreq = targfreq / 1000;
++      u32 minfreq = pol->min / 1000;
++      u32 maxfreq = pol->max / 1000;
++
++      if (ppst == 0) {
++              printk(KERN_ERR PFX "targ: ppst 0\n");
++              return -ENODEV;
++      }
++
++      if (pending_bit_stuck()) {
++              printk(KERN_ERR PFX "drv targ fail: change pending bit set\n");
++              return -EIO;
++      }
++
++      dprintk(KERN_DEBUG PFX "targ: %d kHz, min %d, max %d, relation %d\n",
++              targfreq, pol->min, pol->max, relation);
++
++      if (query_current_values_with_pending_wait())
++              return -EIO;
++
++      dprintk(KERN_DEBUG PFX "targ: curr fid 0x%x, vid 0x%x\n",
++              currfid, currvid);
++
++      if ((checkvid != currvid) || (checkfid != currfid)) {
++              printk(KERN_ERR PFX
++                     "error - out of sync, fid 0x%x 0x%x, vid 0x%x 0x%x\n",
++                     checkfid, currfid, checkvid, currvid);
++      }
++
++      if (transition_frequency(&reqfreq, &minfreq, &maxfreq,
++                               relation ==
++                               CPUFREQ_RELATION_H ? SEARCH_UP : SEARCH_DOWN))
++      {
++              printk(KERN_ERR PFX "transition frequency failed\n");
++              return 1;
++      }
++
++      pol->cur = 1000 * find_freq_from_fid(currfid);
++
++      return 0;
++}
++
++/* Driver entry point to verify the policy and range of frequencies */
++static int
++drv_verify(struct cpufreq_policy *pol)
++{
++      u32 min = pol->min / 1000;
++      u32 max = pol->max / 1000;
++      u32 targ = min;
++      int res;
++
++      if (ppst == 0) {
++              printk(KERN_ERR PFX "verify - ppst 0\n");
++              return -ENODEV;
++      }
++
++      if (pending_bit_stuck()) {
++              printk(KERN_ERR PFX "failing verify, change pending bit set\n");
++              return -EIO;
++      }
++
++      dprintk(KERN_DEBUG PFX
++              "ver: cpu%d, min %d, max %d, cur %d, pol %d\n", pol->cpu,
++              pol->min, pol->max, pol->cur, pol->policy);
++
++      if (pol->cpu != 0) {
++              printk(KERN_ERR PFX "verify - cpu not 0\n");
++              return -ENODEV;
++      }
++
++      res = find_match(&targ, &min, &max,
++                       pol->policy == CPUFREQ_POLICY_POWERSAVE ?
++                       SEARCH_DOWN : SEARCH_UP, 0, 0);
++      if (!res) {
++              pol->min = min * 1000;
++              pol->max = max * 1000;
++      }
++      return res;
++}
++
++/* per CPU init entry point to the driver */
++static int __init
++drv_cpu_init(struct cpufreq_policy *pol)
++{
++      if (pol->cpu != 0) {
++              printk(KERN_ERR PFX "init not cpu 0\n");
++              return -ENODEV;
++      }
++
++      pol->policy = CPUFREQ_POLICY_PERFORMANCE; /* boot as fast as we can */
++
++      /* Take a crude guess here. */
++      pol->cpuinfo.transition_latency = ((rvo + 8) * vstable * VST_UNITS_20US)
++          + (3 * (1 << irt) * 10);
++
++      if (query_current_values_with_pending_wait())
++              return -EIO;
++
++      pol->cur = 1000 * find_freq_from_fid(currfid);
++      dprintk(KERN_DEBUG PFX "policy current frequency %d kHz\n", pol->cur);
++
++      /* min/max the cpu is capable of */
++      pol->cpuinfo.min_freq = 1000 * find_freq_from_fid(ppst[0].fid);
++      pol->cpuinfo.max_freq = 1000 * find_freq_from_fid(ppst[numps-1].fid);
++      pol->min = 1000 * find_freq_from_fid(ppst[0].fid);
++      pol->max = 1000 * find_freq_from_fid(ppst[batps - 1].fid);
++
++      printk(KERN_INFO PFX "cpu_init done, current fid 0x%x, vid 0x%x\n",
++             currfid, currvid);
++
++      return 0;
++}
++
++/* driver entry point for init */
++static int __init
++drv_init(void)
++{
++      int rc;
++
++      printk(KERN_INFO PFX VERSION "\n");
++
++      if (check_supported_cpu() == 0)
++              return -ENODEV;
++
++      rc = find_psb_table();
++      if (rc)
++              return rc;
++
++      if (pending_bit_stuck()) {
++              printk(KERN_ERR PFX "drv_init fail, change pending bit set\n");
++              kfree(ppst);
++              return -EIO;
++      }
++
++      return cpufreq_register_driver(&cpufreq_amd64_driver);
++}
++
++/* driver entry point for term */
++static void __exit
++drv_exit(void)
++{
++      dprintk(KERN_INFO PFX "drv_exit\n");
++
++      cpufreq_unregister_driver(&cpufreq_amd64_driver);
++      kfree(ppst);
++}
++
++MODULE_AUTHOR("Paul Devriendt <paul.devriendt@amd.com>");
++MODULE_DESCRIPTION("AMD Athlon 64 and Opteron processor frequency driver.");
++MODULE_LICENSE("GPL");
++
++module_init(drv_init);
++module_exit(drv_exit);
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/arch/i386/kernel/cpu/cpufreq/powernow-k8.h      2003-10-05 00:33:23.000000000 -0700
+@@ -0,0 +1,126 @@
++/*
++ *   (c) 2003 Advanced Micro Devices, Inc.
++ *  Your use of this code is subject to the terms and conditions of the
++ *  GNU general public license version 2. See "../../../COPYING" or
++ *  http://www.gnu.org/licenses/gpl.html
++ */
++
++/* processor's cpuid instruction support */
++#define CPUID_PROCESSOR_SIGNATURE             1       /* function 1               */
++#define CPUID_F1_FAM                 0x00000f00       /* family mask              */
++#define CPUID_F1_XFAM                0x0ff00000       /* extended family mask     */
++#define CPUID_F1_MOD                 0x000000f0       /* model mask               */
++#define CPUID_F1_STEP                0x0000000f       /* stepping level mask      */
++#define CPUID_XFAM_MOD               0x0ff00ff0       /* xtended fam, fam + model */
++#define ATHLON64_XFAM_MOD            0x00000f40       /* xtended fam, fam + model */
++#define OPTERON_XFAM_MOD             0x00000f50       /* xtended fam, fam + model */
++#define ATHLON64_REV_C0                       8
++#define CPUID_GET_MAX_CAPABILITIES   0x80000000
++#define CPUID_FREQ_VOLT_CAPABILITIES 0x80000007
++#define P_STATE_TRANSITION_CAPABLE            6
++
++/* Model Specific Registers for p-state transitions. MSRs are 64-bit. For     */
++/* writes (wrmsr - opcode 0f 30), the register number is placed in ecx, and   */
++/* the value to write is placed in edx:eax. For reads (rdmsr - opcode 0f 32), */
++/* the register number is placed in ecx, and the data is returned in edx:eax. */
++
++#define MSR_FIDVID_CTL      0xc0010041
++#define MSR_FIDVID_STATUS   0xc0010042
++
++/* Field definitions within the FID VID Low Control MSR : */
++#define MSR_C_LO_INIT_FID_VID     0x00010000
++#define MSR_C_LO_NEW_VID          0x00001f00
++#define MSR_C_LO_NEW_FID          0x0000002f
++#define MSR_C_LO_VID_SHIFT        8
++
++/* Field definitions within the FID VID High Control MSR : */
++#define MSR_C_HI_STP_GNT_TO       0x000fffff
++
++/* Field definitions within the FID VID Low Status MSR : */
++#define MSR_S_LO_CHANGE_PENDING   0x80000000  /* cleared when completed */
++#define MSR_S_LO_MAX_RAMP_VID     0x1f000000
++#define MSR_S_LO_MAX_FID          0x003f0000
++#define MSR_S_LO_START_FID        0x00003f00
++#define MSR_S_LO_CURRENT_FID      0x0000003f
++
++/* Field definitions within the FID VID High Status MSR : */
++#define MSR_S_HI_MAX_WORKING_VID  0x001f0000
++#define MSR_S_HI_START_VID        0x00001f00
++#define MSR_S_HI_CURRENT_VID      0x0000001f
++
++/* fids (frequency identifiers) are arranged in 2 tables - lo and hi */
++#define LO_FID_TABLE_TOP     6
++#define HI_FID_TABLE_BOTTOM  8
++
++#define LO_VCOFREQ_TABLE_TOP    1400  /* corresponding vco frequency values */
++#define HI_VCOFREQ_TABLE_BOTTOM 1600
++
++#define MIN_FREQ_RESOLUTION  200 /* fids jump by 2 matching freq jumps by 200 */
++
++#define MAX_FID 0x2a  /* Spec only gives FID values as far as 5 GHz */
++
++#define LEAST_VID 0x1e        /* Lowest (numerically highest) useful vid value */
++
++#define MIN_FREQ 800  /* Min and max freqs, per spec */
++#define MAX_FREQ 5000
++
++#define INVALID_FID_MASK 0xffffffc1  /* not a valid fid if these bits are set */
++
++#define INVALID_VID_MASK 0xffffffe0  /* not a valid vid if these bits are set */
++
++#define STOP_GRANT_5NS 1 /* min poss memory access latency for voltage change */
++
++#define PLL_LOCK_CONVERSION (1000/5) /* ms to ns, then divide by clock period */
++
++#define MAXIMUM_VID_STEPS 1  /* Current cpus only allow a single step of 25mV */
++
++#define VST_UNITS_20US 20   /* Voltage Stabalization Time is in units of 20us */
++
++/*
++Version 1.4 of the PSB table. This table is constructed by BIOS and is
++to tell the OS's power management driver which VIDs and FIDs are
++supported by this particular processor. This information is obtained from
++the data sheets for each processor model by the system vendor and
++incorporated into the BIOS.
++If the data in the PSB / PST is wrong, then this driver will program the
++wrong values into hardware, which is very likely to lead to a crash.
++*/
++
++#define PSB_ID_STRING      "AMDK7PNOW!"
++#define PSB_ID_STRING_LEN  10
++
++#define PSB_VERSION_1_4  0x14
++
++struct psb_s {
++      u8 signature[10];
++      u8 tableversion;
++      u8 flags1;
++      u16 voltagestabilizationtime;
++      u8 flags2;
++      u8 numpst;
++      u32 cpuid;
++      u8 plllocktime;
++      u8 maxfid;
++      u8 maxvid;
++      u8 numpstates;
++};
++
++/* Pairs of fid/vid values are appended to the version 1.4 PSB table. */
++struct pst_s {
++      u8 fid;
++      u8 vid;
++};
++
++#ifdef DEBUG
++#define dprintk(msg...) printk(msg)
++#else
++#define dprintk(msg...) do { } while(0)
++#endif
++
++static inline int core_voltage_pre_transition(u32 reqvid);
++static inline int core_voltage_post_transition(u32 reqvid);
++static inline int core_frequency_transition(u32 reqfid);
++static int drv_verify(struct cpufreq_policy *pol);
++static int drv_target(struct cpufreq_policy *pol, unsigned targfreq,
++                    unsigned relation);
++static int __init drv_cpu_init(struct cpufreq_policy *pol);
+--- linux-2.6.0-test6/arch/i386/kernel/cpu/intel.c     2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/i386/kernel/cpu/intel.c    2003-10-05 00:36:48.000000000 -0700
+@@ -8,11 +8,10 @@
+ #include <asm/processor.h>
+ #include <asm/msr.h>
+ #include <asm/uaccess.h>
++#include <asm/desc.h>
+ #include "cpu.h"
+-extern int trap_init_f00f_bug(void);
+-
+ #ifdef CONFIG_X86_INTEL_USERCOPY
+ /*
+  * Alignment at which movsl is preferred for bulk memory copies.
+@@ -157,7 +156,7 @@ static void __init init_intel(struct cpu
+               c->f00f_bug = 1;
+               if ( !f00f_workaround_enabled ) {
+-                      trap_init_f00f_bug();
++                      trap_init_virtual_IDT();
+                       printk(KERN_NOTICE "Intel Pentium with F0 0F bug - workaround enabled.\n");
+                       f00f_workaround_enabled = 1;
+               }
+@@ -238,12 +237,9 @@ static void __init init_intel(struct cpu
+       }
+       /* SEP CPUID bug: Pentium Pro reports SEP but doesn't have it until model 3 mask 3 */
+-      if ( c->x86 == 6) {
+-              unsigned model_mask = (c->x86_model << 8) + c->x86_mask;
+-              if (model_mask < 0x0303)
+-                      clear_bit(X86_FEATURE_SEP, c->x86_capability);
+-      }
+-      
++      if ((c->x86<<8 | c->x86_model<<4 | c->x86_mask) < 0x633)
++              clear_bit(X86_FEATURE_SEP, c->x86_capability);
++
+       /* Names for the Pentium II/Celeron processors 
+          detectable only by also checking the cache size.
+          Dixon is NOT a Celeron. */
+--- linux-2.6.0-test6/arch/i386/kernel/cpu/mcheck/k7.c 2003-08-08 22:55:10.000000000 -0700
++++ 25/arch/i386/kernel/cpu/mcheck/k7.c        2003-10-05 00:33:23.000000000 -0700
+@@ -17,7 +17,7 @@
+ #include "mce.h"
+ /* Machine Check Handler For AMD Athlon/Duron */
+-static void k7_machine_check(struct pt_regs * regs, long error_code)
++static asmlinkage void k7_machine_check(struct pt_regs * regs, long error_code)
+ {
+       int recover=1;
+       u32 alow, ahigh, high, low;
+@@ -31,7 +31,7 @@ static void k7_machine_check(struct pt_r
+       printk (KERN_EMERG "CPU %d: Machine Check Exception: %08x%08x\n",
+               smp_processor_id(), mcgsth, mcgstl);
+-      for (i=0; i<nr_mce_banks; i++) {
++      for (i=1; i<nr_mce_banks; i++) {
+               rdmsr (MSR_IA32_MC0_STATUS+i*4,low, high);
+               if (high&(1<<31)) {
+                       if (high & (1<<29))
+@@ -81,6 +81,9 @@ void __init amd_mcheck_init(struct cpuin
+               wrmsr (MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
+       nr_mce_banks = l & 0xff;
++      /* Clear status for MC index 0 separately, we don't touch CTL,
++       * as some Athlons cause spurious MCEs when its enabled. */
++      wrmsr (MSR_IA32_MC0_STATUS, 0x0, 0x0);
+       for (i=1; i<nr_mce_banks; i++) {
+               wrmsr (MSR_IA32_MC0_CTL+4*i, 0xffffffff, 0xffffffff);
+               wrmsr (MSR_IA32_MC0_STATUS+4*i, 0x0, 0x0);
+--- linux-2.6.0-test6/arch/i386/kernel/cpu/mcheck/mce.c        2003-06-14 12:18:29.000000000 -0700
++++ 25/arch/i386/kernel/cpu/mcheck/mce.c       2003-10-05 00:33:23.000000000 -0700
+@@ -18,18 +18,13 @@ int mce_disabled __initdata = 0;
+ int nr_mce_banks;
+ /* Handle unconfigured int18 (should never happen) */
+-static void unexpected_machine_check(struct pt_regs * regs, long error_code)
++static asmlinkage void unexpected_machine_check(struct pt_regs * regs, long error_code)
+ {     
+       printk(KERN_ERR "CPU#%d: Unexpected int18 (Machine Check).\n", smp_processor_id());
+ }
+ /* Call the installed machine check handler for this CPU setup. */
+-void (*machine_check_vector)(struct pt_regs *, long error_code) = unexpected_machine_check;
+-
+-asmlinkage void do_machine_check(struct pt_regs * regs, long error_code)
+-{
+-      machine_check_vector(regs, error_code);
+-}
++void asmlinkage (*machine_check_vector)(struct pt_regs *, long error_code) = unexpected_machine_check;
+ /* This has to be run for each processor */
+ void __init mcheck_init(struct cpuinfo_x86 *c)
+--- linux-2.6.0-test6/arch/i386/kernel/cpu/mcheck/mce.h        2003-06-14 12:17:58.000000000 -0700
++++ 25/arch/i386/kernel/cpu/mcheck/mce.h       2003-10-05 00:33:23.000000000 -0700
+@@ -7,7 +7,7 @@ void intel_p6_mcheck_init(struct cpuinfo
+ void winchip_mcheck_init(struct cpuinfo_x86 *c);
+ /* Call the installed machine check handler for this CPU setup. */
+-extern void (*machine_check_vector)(struct pt_regs *, long error_code);
++extern asmlinkage void (*machine_check_vector)(struct pt_regs *, long error_code);
+ extern int mce_disabled __initdata;
+ extern int nr_mce_banks;
+--- linux-2.6.0-test6/arch/i386/kernel/cpu/mcheck/p4.c 2003-06-14 12:18:24.000000000 -0700
++++ 25/arch/i386/kernel/cpu/mcheck/p4.c        2003-10-05 00:33:23.000000000 -0700
+@@ -148,7 +148,7 @@ done:
+       return mce_num_extended_msrs;
+ }
+-static void intel_machine_check(struct pt_regs * regs, long error_code)
++static asmlinkage void intel_machine_check(struct pt_regs * regs, long error_code)
+ {
+       int recover=1;
+       u32 alow, ahigh, high, low;
+--- linux-2.6.0-test6/arch/i386/kernel/cpu/mcheck/p5.c 2003-06-14 12:18:23.000000000 -0700
++++ 25/arch/i386/kernel/cpu/mcheck/p5.c        2003-10-05 00:33:23.000000000 -0700
+@@ -16,7 +16,7 @@
+ #include "mce.h"
+ /* Machine check handler for Pentium class Intel */
+-static void pentium_machine_check(struct pt_regs * regs, long error_code)
++static asmlinkage void pentium_machine_check(struct pt_regs * regs, long error_code)
+ {
+       u32 loaddr, hi, lotype;
+       rdmsr(MSR_IA32_P5_MC_ADDR, loaddr, hi);
+--- linux-2.6.0-test6/arch/i386/kernel/cpu/mcheck/p6.c 2003-06-14 12:18:24.000000000 -0700
++++ 25/arch/i386/kernel/cpu/mcheck/p6.c        2003-10-05 00:33:23.000000000 -0700
+@@ -16,7 +16,7 @@
+ #include "mce.h"
+ /* Machine Check Handler For PII/PIII */
+-static void intel_machine_check(struct pt_regs * regs, long error_code)
++static asmlinkage void intel_machine_check(struct pt_regs * regs, long error_code)
+ {
+       int recover=1;
+       u32 alow, ahigh, high, low;
+--- linux-2.6.0-test6/arch/i386/kernel/cpu/mcheck/winchip.c    2003-06-14 12:18:22.000000000 -0700
++++ 25/arch/i386/kernel/cpu/mcheck/winchip.c   2003-10-05 00:33:23.000000000 -0700
+@@ -15,7 +15,7 @@
+ #include "mce.h"
+ /* Machine check handler for WinChip C6 */
+-static void winchip_machine_check(struct pt_regs * regs, long error_code)
++static asmlinkage void winchip_machine_check(struct pt_regs * regs, long error_code)
+ {
+       printk(KERN_EMERG "CPU0: Machine Check Exception.\n");
+ }
+--- linux-2.6.0-test6/arch/i386/kernel/dmi_scan.c      2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/i386/kernel/dmi_scan.c     2003-10-05 00:33:23.000000000 -0700
+@@ -939,11 +939,6 @@ static __initdata struct dmi_blacklist d
+                       MATCH(DMI_BOARD_NAME, "CUR-DLS"),
+                       NO_MATCH, NO_MATCH }},
+-      { force_acpi_ht, "ASUS A7V", {
+-                      MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC"),
+-                      MATCH(DMI_BOARD_NAME, "<A7V>"),
+-                      MATCH(DMI_BIOS_VERSION, "ASUS A7V ACPI BIOS Revision 1011"), NO_MATCH }},
+-
+       { force_acpi_ht, "ABIT i440BX-W83977", {
+                       MATCH(DMI_BOARD_VENDOR, "ABIT <http://www.abit.com>"),
+                       MATCH(DMI_BOARD_NAME, "i440BX-W83977 (BP6)"),
+@@ -978,7 +973,10 @@ static __initdata struct dmi_blacklist d
+       { disable_acpi_pci, "ASUS A7V", {
+                       MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC"),
+                       MATCH(DMI_BOARD_NAME, "<A7V>"),
+-                      MATCH(DMI_BIOS_VERSION, "ASUS A7V ACPI BIOS Revision 1007"), NO_MATCH }},
++                      /* newer BIOS, Revision 1011, does work */
++                      MATCH(DMI_BIOS_VERSION, "ASUS A7V ACPI BIOS Revision 1007"),
++                      NO_MATCH }},
++
+ #endif
+       { NULL, }
+--- linux-2.6.0-test6/arch/i386/kernel/doublefault.c   2003-08-22 19:23:40.000000000 -0700
++++ 25/arch/i386/kernel/doublefault.c  2003-10-05 00:36:48.000000000 -0700
+@@ -7,12 +7,13 @@
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+ #include <asm/desc.h>
++#include <asm/fixmap.h>
+ #define DOUBLEFAULT_STACKSIZE (1024)
+ static unsigned long doublefault_stack[DOUBLEFAULT_STACKSIZE];
+ #define STACK_START (unsigned long)(doublefault_stack+DOUBLEFAULT_STACKSIZE)
+-#define ptr_ok(x) ((x) > 0xc0000000 && (x) < 0xc1000000)
++#define ptr_ok(x) (((x) > __PAGE_OFFSET && (x) < (__PAGE_OFFSET + 0x01000000)) || ((x) >= FIXADDR_START))
+ static void doublefault_fn(void)
+ {
+@@ -38,8 +39,8 @@ static void doublefault_fn(void)
+                       printk("eax = %08lx, ebx = %08lx, ecx = %08lx, edx = %08lx\n",
+                               t->eax, t->ebx, t->ecx, t->edx);
+-                      printk("esi = %08lx, edi = %08lx\n",
+-                              t->esi, t->edi);
++                      printk("esi = %08lx, edi = %08lx, ebp = %08lx\n",
++                              t->esi, t->edi, t->ebp);
+               }
+       }
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/arch/i386/kernel/efi.c  2003-10-05 00:36:25.000000000 -0700
+@@ -0,0 +1,611 @@
++/*
++ * Extensible Firmware Interface
++ *
++ * Based on Extensible Firmware Interface Specification version 1.0
++ *
++ * Copyright (C) 1999 VA Linux Systems
++ * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
++ * Copyright (C) 1999-2002 Hewlett-Packard Co.
++ *    David Mosberger-Tang <davidm@hpl.hp.com>
++ *    Stephane Eranian <eranian@hpl.hp.com>
++ *
++ * All EFI Runtime Services are not implemented yet as EFI only
++ * supports physical mode addressing on SoftSDV. This is to be fixed
++ * in a future version.  --drummond 1999-07-20
++ *
++ * Implemented EFI runtime services and virtual mode calls.  --davidm
++ *
++ * Goutham Rao: <goutham.rao@intel.com>
++ *    Skip non-WB memory and ignore empty memory ranges.
++ */
++
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/mm.h>
++#include <linux/types.h>
++#include <linux/time.h>
++#include <linux/spinlock.h>
++#include <linux/bootmem.h>
++#include <linux/ioport.h>
++#include <linux/proc_fs.h>
++#include <linux/efi.h>
++
++#include <asm/setup.h>
++#include <asm/io.h>
++#include <asm/page.h>
++#include <asm/pgtable.h>
++#include <asm/processor.h>
++#include <asm/desc.h>
++#include <asm/pgalloc.h>
++#include <asm/tlbflush.h>
++
++#define EFI_DEBUG     0
++#define PFX           "EFI: "
++
++extern efi_status_t asmlinkage efi_call_phys(void *, ...);
++
++struct efi efi;
++struct efi efi_phys __initdata;
++struct efi_memory_map memmap __initdata;
++
++/*
++ * We require an early boot_ioremap mapping mechanism initially
++ */
++extern void * boot_ioremap(unsigned long, unsigned long);
++
++/*
++ * efi_dir is allocated here, but the directory isn't created
++ * here, as proc_mkdir() doesn't work this early in the bootup
++ * process.  Therefore, each module, like efivars, must test for
++ *    if (!efi_dir) efi_dir = proc_mkdir("efi", NULL);
++ * prior to creating their own entries under /proc/efi.
++ */
++#ifdef CONFIG_PROC_FS
++struct proc_dir_entry *efi_dir;
++#endif
++
++
++/*
++ * To make EFI call EFI runtime service in physical addressing mode we need
++ * prelog/epilog before/after the invocation to disable interrupt, to
++ * claim EFI runtime service handler exclusively and to duplicate a memory in
++ * low memory space say 0 - 3G.
++ */
++
++static unsigned long efi_rt_eflags;
++static spinlock_t efi_rt_lock = SPIN_LOCK_UNLOCKED;
++static pgd_t efi_bak_pg_dir_pointer[2];
++
++static void efi_call_phys_prelog(void)
++{
++      unsigned long cr4;
++      unsigned long temp;
++
++      spin_lock(&efi_rt_lock);
++      local_irq_save(efi_rt_eflags);
++
++      /*
++       * If I don't have PSE, I should just duplicate two entries in page
++       * directory. If I have PSE, I just need to duplicate one entry in
++       * page directory.
++       */
++      __asm__ __volatile__("movl %%cr4, %0":"=r"(cr4));
++
++      if (cr4 & X86_CR4_PSE) {
++              efi_bak_pg_dir_pointer[0].pgd =
++                  swapper_pg_dir[pgd_index(0)].pgd;
++              swapper_pg_dir[0].pgd =
++                  swapper_pg_dir[pgd_index(PAGE_OFFSET)].pgd;
++      } else {
++              efi_bak_pg_dir_pointer[0].pgd =
++                  swapper_pg_dir[pgd_index(0)].pgd;
++              efi_bak_pg_dir_pointer[1].pgd =
++                  swapper_pg_dir[pgd_index(0x400000)].pgd;
++              swapper_pg_dir[pgd_index(0)].pgd =
++                  swapper_pg_dir[pgd_index(PAGE_OFFSET)].pgd;
++              temp = PAGE_OFFSET + 0x400000;
++              swapper_pg_dir[pgd_index(0x400000)].pgd =
++                  swapper_pg_dir[pgd_index(temp)].pgd;
++      }
++
++      /*
++       * After the lock is released, the original page table is restored.
++       */
++      local_flush_tlb();
++
++      cpu_gdt_descr[0].address = __pa(cpu_gdt_descr[0].address);
++      __asm__ __volatile__("lgdt %0":"=m"
++                          (*(struct Xgt_desc_struct *) __pa(&cpu_gdt_descr[0])));
++}
++
++static void efi_call_phys_epilog(void)
++{
++      unsigned long cr4;
++
++      cpu_gdt_descr[0].address =
++              (unsigned long) __va(cpu_gdt_descr[0].address);
++      __asm__ __volatile__("lgdt %0":"=m"(cpu_gdt_descr));
++      __asm__ __volatile__("movl %%cr4, %0":"=r"(cr4));
++
++      if (cr4 & X86_CR4_PSE) {
++              swapper_pg_dir[pgd_index(0)].pgd =
++                  efi_bak_pg_dir_pointer[0].pgd;
++      } else {
++              swapper_pg_dir[pgd_index(0)].pgd =
++                  efi_bak_pg_dir_pointer[0].pgd;
++              swapper_pg_dir[pgd_index(0x400000)].pgd =
++                  efi_bak_pg_dir_pointer[1].pgd;
++      }
++
++      /*
++       * After the lock is released, the original page table is restored.
++       */
++      local_flush_tlb();
++
++      local_irq_restore(efi_rt_eflags);
++      spin_unlock(&efi_rt_lock);
++}
++
++static efi_status_t
++phys_efi_set_virtual_address_map(unsigned long memory_map_size,
++                               unsigned long descriptor_size,
++                               u32 descriptor_version,
++                               efi_memory_desc_t *virtual_map)
++{
++      efi_status_t status;
++
++      efi_call_phys_prelog();
++      status = efi_call_phys(efi_phys.set_virtual_address_map,
++                                   memory_map_size, descriptor_size,
++                                   descriptor_version, virtual_map);
++      efi_call_phys_epilog();
++      return status;
++}
++
++efi_status_t
++phys_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
++{
++      efi_status_t status;
++
++      efi_call_phys_prelog();
++      status = efi_call_phys(efi_phys.get_time, tm, tc);
++      efi_call_phys_epilog();
++      return status;
++}
++
++void efi_gettimeofday(struct timespec *tv)
++{
++      efi_time_t tm;
++
++      memset(tv, 0, sizeof(*tv));
++      if ((*efi.get_time) (&tm, 0) != EFI_SUCCESS)
++              return;
++
++      tv->tv_sec = mktime(tm.year, tm.month, tm.day, tm.hour, tm.minute,
++                          tm.second);
++      tv->tv_nsec = tm.nanosecond;
++}
++
++int is_available_memory(efi_memory_desc_t * md)
++{
++      if (!(md->attribute & EFI_MEMORY_WB))
++              return 0;
++
++      switch (md->type) {
++              case EFI_LOADER_CODE:
++              case EFI_LOADER_DATA:
++              case EFI_BOOT_SERVICES_CODE:
++              case EFI_BOOT_SERVICES_DATA:
++              case EFI_CONVENTIONAL_MEMORY:
++                      return 1;
++      }
++      return 0;
++}
++
++/*
++ * We need to map the EFI memory map again after paging_init().
++ */
++void __init efi_map_memmap(void)
++{
++      memmap.map = NULL;
++
++      memmap.map = (efi_memory_desc_t *)
++              bt_ioremap((unsigned long) memmap.phys_map,
++                      (memmap.nr_map * sizeof(efi_memory_desc_t)));
++
++      if (memmap.map == NULL)
++              printk(KERN_ERR PFX "Could not remap the EFI memmap!\n");
++}
++
++void __init print_efi_memmap(void)
++{
++      efi_memory_desc_t *md;
++      int i;
++
++      for (i = 0; i < memmap.nr_map; i++) {
++              md = &memmap.map[i];
++              printk(KERN_INFO "mem%02u: type=%u, attr=0x%llx, "
++                      "range=[0x%016llx-0x%016llx) (%lluMB)\n",
++                      i, md->type, md->attribute, md->phys_addr,
++                      md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT),
++                      (md->num_pages >> (20 - EFI_PAGE_SHIFT)));
++      }
++}
++
++/*
++ * Walks the EFI memory map and calls CALLBACK once for each EFI
++ * memory descriptor that has memory that is available for kernel use.
++ */
++void efi_memmap_walk(efi_freemem_callback_t callback, void *arg)
++{
++      int prev_valid = 0;
++      struct range {
++              unsigned long start;
++              unsigned long end;
++      } prev, curr;
++      efi_memory_desc_t *md;
++      unsigned long start, end;
++      int i;
++
++      for (i = 0; i < memmap.nr_map; i++) {
++              md = &memmap.map[i];
++
++              if ((md->num_pages == 0) || (!is_available_memory(md)))
++                      continue;
++
++              curr.start = md->phys_addr;
++              curr.end = curr.start + (md->num_pages << EFI_PAGE_SHIFT);
++
++              if (!prev_valid) {
++                      prev = curr;
++                      prev_valid = 1;
++              } else {
++                      if (curr.start < prev.start)
++                              printk(KERN_INFO PFX "Unordered memory map\n");
++                      if (prev.end == curr.start)
++                              prev.end = curr.end;
++                      else {
++                              start =
++                                  (unsigned long) (PAGE_ALIGN(prev.start));
++                              end = (unsigned long) (prev.end & PAGE_MASK);
++                              if ((end > start)
++                                  && (*callback) (start, end, arg) < 0)
++                                      return;
++                              prev = curr;
++                      }
++              }
++      }
++      if (prev_valid) {
++              start = (unsigned long) PAGE_ALIGN(prev.start);
++              end = (unsigned long) (prev.end & PAGE_MASK);
++              if (end > start)
++                      (*callback) (start, end, arg);
++      }
++}
++
++void __init efi_init(void)
++{
++      efi_config_table_t *config_tables;
++      efi_runtime_services_t *runtime;
++      efi_char16_t *c16;
++      char vendor[100] = "unknown";
++      unsigned long num_config_tables;
++      int i = 0;
++
++      memset(&efi, 0, sizeof(efi) );
++      memset(&efi_phys, 0, sizeof(efi_phys));
++
++      efi_phys.systab = EFI_SYSTAB;
++      memmap.phys_map = EFI_MEMMAP;
++      memmap.nr_map = EFI_MEMMAP_SIZE/EFI_MEMDESC_SIZE;
++      memmap.desc_version = EFI_MEMDESC_VERSION;
++
++      efi.systab = (efi_system_table_t *)
++              boot_ioremap((unsigned long) efi_phys.systab,
++                      sizeof(efi_system_table_t));
++      /*
++       * Verify the EFI Table
++       */
++      if (efi.systab == NULL)
++              printk(KERN_ERR PFX "Woah! Couldn't map the EFI system table.\n");
++      if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
++              printk(KERN_ERR PFX "Woah! EFI system table signature incorrect\n");
++      if ((efi.systab->hdr.revision ^ EFI_SYSTEM_TABLE_REVISION) >> 16 != 0)
++              printk(KERN_ERR PFX
++                     "Warning: EFI system table major version mismatch: "
++                     "got %d.%02d, expected %d.%02d\n",
++                     efi.systab->hdr.revision >> 16,
++                     efi.systab->hdr.revision & 0xffff,
++                     EFI_SYSTEM_TABLE_REVISION >> 16,
++                     EFI_SYSTEM_TABLE_REVISION & 0xffff);
++      /*
++       * Grab some details from the system table
++       */
++      num_config_tables = efi.systab->nr_tables;
++      config_tables = (efi_config_table_t *)efi.systab->tables;
++      runtime = efi.systab->runtime;
++
++      /*
++       * Show what we know for posterity
++       */
++      c16 = (efi_char16_t *) boot_ioremap(efi.systab->fw_vendor, 2);
++      if (c16) {
++              for (i = 0; i < sizeof(vendor) && *c16; ++i)
++                      vendor[i] = *c16++;
++              vendor[i] = '\0';
++      } else
++              printk(KERN_ERR PFX "Could not map the firmware vendor!\n");
++
++      printk(KERN_INFO PFX "EFI v%u.%.02u by %s \n",
++             efi.systab->hdr.revision >> 16,
++             efi.systab->hdr.revision & 0xffff, vendor);
++
++      /*
++       * Let's see what config tables the firmware passed to us.
++       */
++      config_tables = (efi_config_table_t *)
++                              boot_ioremap((unsigned long) config_tables,
++                              num_config_tables * sizeof(efi_config_table_t));
++
++      if (config_tables == NULL)
++              printk(KERN_ERR PFX "Could not map EFI Configuration Table!\n");
++
++      for (i = 0; i < num_config_tables; i++) {
++              if (efi_guidcmp(config_tables[i].guid, MPS_TABLE_GUID) == 0) {
++                      efi.mps = (void *)config_tables[i].table;
++                      printk(KERN_INFO " MPS=0x%lx ", config_tables[i].table);
++              } else
++                  if (efi_guidcmp(config_tables[i].guid, ACPI_20_TABLE_GUID) == 0) {
++                      efi.acpi20 = __va(config_tables[i].table);
++                      printk(KERN_INFO " ACPI 2.0=0x%lx ", config_tables[i].table);
++              } else
++                  if (efi_guidcmp(config_tables[i].guid, ACPI_TABLE_GUID) == 0) {
++                      efi.acpi = __va(config_tables[i].table);
++                      printk(KERN_INFO " ACPI=0x%lx ", config_tables[i].table);
++              } else
++                  if (efi_guidcmp(config_tables[i].guid, SMBIOS_TABLE_GUID) == 0) {
++                      efi.smbios = (void *) config_tables[i].table;
++                      printk(KERN_INFO " SMBIOS=0x%lx ", config_tables[i].table);
++              } else
++                  if (efi_guidcmp(config_tables[i].guid, HCDP_TABLE_GUID) == 0) {
++                      efi.hcdp = (void *)config_tables[i].table;
++                      printk(KERN_INFO " HCDP=0x%lx ", config_tables[i].table);
++              } else
++                  if (efi_guidcmp(config_tables[i].guid, UGA_IO_PROTOCOL_GUID) == 0) {
++                      efi.uga = (void *)config_tables[i].table;
++                      printk(KERN_INFO " UGA=0x%lx ", config_tables[i].table);
++              }
++      }
++      printk("\n");
++
++      /*
++       * Check out the runtime services table. We need to map
++       * the runtime services table so that we can grab the physical
++       * address of several of the EFI runtime functions, needed to
++       * set the firmware into virtual mode.
++       */
++
++      runtime = (efi_runtime_services_t *) boot_ioremap((unsigned long)
++                                              runtime,
++                                              sizeof(efi_runtime_services_t));
++      if (runtime != NULL) {
++              /*
++               * We will only need *early* access to the following
++               * two EFI runtime services before set_virtual_address_map
++               * is invoked.
++               */
++              efi_phys.get_time = (efi_get_time_t *) runtime->get_time;
++              efi_phys.set_virtual_address_map =
++                      (efi_set_virtual_address_map_t *)
++                              runtime->set_virtual_address_map;
++      } else
++              printk(KERN_ERR PFX "Could not map the runtime service table!\n");
++
++      /* Map the EFI memory map for use until paging_init() */
++
++      memmap.map = (efi_memory_desc_t *)
++              boot_ioremap((unsigned long) EFI_MEMMAP, EFI_MEMMAP_SIZE);
++
++      if (memmap.map == NULL)
++              printk(KERN_ERR PFX "Could not map the EFI memory map!\n");
++
++      if (EFI_MEMDESC_SIZE != sizeof(efi_memory_desc_t)) {
++              printk(KERN_WARNING PFX "Warning! Kernel-defined memdesc doesn't "
++                         "match the one from EFI!\n");
++      }
++#if EFI_DEBUG
++      print_efi_memmap();
++#endif
++}
++
++/*
++ * This function will switch the EFI runtime services to virtual mode.
++ * Essentially, look through the EFI memmap and map every region that
++ * has the runtime attribute bit set in its memory descriptor and update
++ * that memory descriptor with the virtual address obtained from ioremap().
++ * This enables the runtime services to be called without having to
++ * thunk back into physical mode for every invocation.
++ */
++
++void __init efi_enter_virtual_mode(void)
++{
++      efi_memory_desc_t *md;
++      efi_status_t status;
++      int i;
++
++      efi.systab = NULL;
++
++      for (i = 0; i < memmap.nr_map; i++) {
++              md = &memmap.map[i];
++
++              if (md->attribute & EFI_MEMORY_RUNTIME) {
++                      md->virt_addr =
++                              (unsigned long)ioremap(md->phys_addr,
++                                      md->num_pages << EFI_PAGE_SHIFT);
++                      if (!(unsigned long)md->virt_addr) {
++                              printk(KERN_ERR PFX "ioremap of 0x%lX failed\n",
++                                      (unsigned long)md->phys_addr);
++                      }
++
++                      if (((unsigned long)md->phys_addr <=
++                                      (unsigned long)efi_phys.systab) &&
++                              ((unsigned long)efi_phys.systab <
++                                      md->phys_addr +
++                                      ((unsigned long)md->num_pages <<
++                                              EFI_PAGE_SHIFT))) {
++                              unsigned long addr;
++
++                              addr = md->virt_addr - md->phys_addr +
++                                              (unsigned long)efi_phys.systab;
++                              efi.systab = (efi_system_table_t *)addr;
++                      }
++              }
++      }
++
++      if (!efi.systab)
++              BUG();
++
++      status = phys_efi_set_virtual_address_map(
++                      sizeof(efi_memory_desc_t) * memmap.nr_map,
++                      sizeof(efi_memory_desc_t),
++                      memmap.desc_version,
++                      memmap.phys_map);
++
++      if (status != EFI_SUCCESS) {
++              printk (KERN_ALERT "You are screwed! "
++                      "Unable to switch EFI into virtual mode "
++                      "(status=%lx)\n", status);
++              panic("EFI call to SetVirtualAddressMap() failed!");
++      }
++
++      /*
++       * Now that EFI is in virtual mode, update the function
++       * pointers in the runtime service table to the new virtual addresses.
++       */
++
++      efi.get_time = (efi_get_time_t *) efi.systab->runtime->get_time;
++      efi.set_time = (efi_set_time_t *) efi.systab->runtime->set_time;
++      efi.get_wakeup_time = (efi_get_wakeup_time_t *)
++                                      efi.systab->runtime->get_wakeup_time;
++      efi.set_wakeup_time = (efi_set_wakeup_time_t *)
++                                      efi.systab->runtime->set_wakeup_time;
++      efi.get_variable = (efi_get_variable_t *)
++                                      efi.systab->runtime->get_variable;
++      efi.get_next_variable = (efi_get_next_variable_t *)
++                                      efi.systab->runtime->get_next_variable;
++      efi.set_variable = (efi_set_variable_t *)
++                                      efi.systab->runtime->set_variable;
++      efi.get_next_high_mono_count = (efi_get_next_high_mono_count_t *)
++                                      efi.systab->runtime->get_next_high_mono_count;
++      efi.reset_system = (efi_reset_system_t *)
++                                      efi.systab->runtime->reset_system;
++}
++
++void __init
++efi_initialize_iomem_resources(struct resource *code_resource,
++                             struct resource *data_resource)
++{
++      struct resource *res;
++      efi_memory_desc_t *md;
++      int i;
++
++      for (i = 0; i < memmap.nr_map; i++) {
++              md = &memmap.map[i];
++
++              if ((md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT)) >
++                  0x100000000ULL)
++                      continue;
++              res = alloc_bootmem_low(sizeof(struct resource));
++              switch (md->type) {
++              case EFI_RESERVED_TYPE:
++                      res->name = "Reserved Memory";
++                      break;
++              case EFI_LOADER_CODE:
++                      res->name = "Loader Code";
++                      break;
++              case EFI_LOADER_DATA:
++                      res->name = "Loader Data";
++                      break;
++              case EFI_BOOT_SERVICES_DATA:
++                      res->name = "BootServices Data";
++                      break;
++              case EFI_BOOT_SERVICES_CODE:
++                      res->name = "BootServices Code";
++                      break;
++              case EFI_RUNTIME_SERVICES_CODE:
++                      res->name = "Runtime Service Code";
++                      break;
++              case EFI_RUNTIME_SERVICES_DATA:
++                      res->name = "Runtime Service Data";
++                      break;
++              case EFI_CONVENTIONAL_MEMORY:
++                      res->name = "Conventional Memory";
++                      break;
++              case EFI_UNUSABLE_MEMORY:
++                      res->name = "Unusable Memory";
++                      break;
++              case EFI_ACPI_RECLAIM_MEMORY:
++                      res->name = "ACPI Reclaim";
++                      break;
++              case EFI_ACPI_MEMORY_NVS:
++                      res->name = "ACPI NVS";
++                      break;
++              case EFI_MEMORY_MAPPED_IO:
++                      res->name = "Memory Mapped IO";
++                      break;
++              case EFI_MEMORY_MAPPED_IO_PORT_SPACE:
++                      res->name = "Memory Mapped IO Port Space";
++                      break;
++              default:
++                      res->name = "Reserved";
++                      break;
++              }
++              res->start = md->phys_addr;
++              res->end = res->start + ((md->num_pages << EFI_PAGE_SHIFT) - 1);
++              res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
++              if (request_resource(&iomem_resource, res) < 0)
++                      printk(KERN_ERR PFX "Failed to allocate res %s : 0x%lx-0x%lx\n",
++                              res->name, res->start, res->end);
++              /*
++               * We don't know which region contains kernel data so we try
++               * it repeatedly and let the resource manager test it.
++               */
++              if (md->type == EFI_CONVENTIONAL_MEMORY) {
++                      request_resource(res, code_resource);
++                      request_resource(res, data_resource);
++              }
++      }
++}
++
++/*
++ * Convenience functions to obtain memory types and attributes
++ */
++
++u32 efi_mem_type(unsigned long phys_addr)
++{
++      efi_memory_desc_t *md;
++      int i;
++
++      for (i = 0; i < memmap.nr_map; i++) {
++              md = &memmap.map[i];
++              if ((md->phys_addr <= phys_addr) && (phys_addr <
++                      (md->phys_addr + (md-> num_pages << EFI_PAGE_SHIFT)) ))
++                      return md->type;
++      }
++      return 0;
++}
++
++u64 efi_mem_attributes(unsigned long phys_addr)
++{
++      efi_memory_desc_t *md;
++      int i;
++
++      for (i = 0; i < memmap.nr_map; i++) {
++              md = &memmap.map[i];
++              if ((md->phys_addr <= phys_addr) && (phys_addr <
++                      (md->phys_addr + (md-> num_pages << EFI_PAGE_SHIFT)) ))
++                      return md->attribute;
++      }
++      return 0;
++}
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/arch/i386/kernel/efi_stub.S     2003-10-05 00:36:22.000000000 -0700
+@@ -0,0 +1,125 @@
++/*
++ * EFI call stub for IA32.
++ *
++ * This stub allows us to make EFI calls in physical mode with interrupts
++ * turned off.
++ */
++
++#include <linux/config.h>
++#include <linux/linkage.h>
++#include <asm/page.h>
++#include <asm/pgtable.h>
++
++/*
++ * efi_call_phys(void *, ...) is a function with variable parameters.
++ * All the callers of this function assure that all the parameters are 4-bytes.
++ */
++
++/*
++ * In gcc calling convention, EBX, ESP, EBP, ESI and EDI are all callee save.
++ * So we'd better save all of them at the beginning of this function and restore
++ * at the end no matter how many we use, because we can not assure EFI runtime
++ * service functions will comply with gcc calling convention, too.
++ */
++
++.text
++.section .text, "a"
++ENTRY(efi_call_phys)
++      /*
++       * 0. The function can only be called in Linux kernel. So CS has been
++       * set to 0x0010, DS and SS have been set to 0x0018. In EFI, I found
++       * the values of these registers are the same. And, the corresponding
++       * GDT entries are identical. So I will do nothing about segment reg
++       * and GDT, but change GDT base register in prelog and epilog.
++       */
++
++      /*
++       * 1. Now I am running with EIP = <physical address> + PAGE_OFFSET.
++       * But to make it smoothly switch from virtual mode to flat mode.
++       * The mapping of lower virtual memory has been created in prelog and
++       * epilog.
++       */
++      movl    $1f, %edx
++      subl    $__PAGE_OFFSET, %edx
++      jmp     *%edx
++1:
++
++      /*
++       * 2. Now on the top of stack is the return
++       * address in the caller of efi_call_phys(), then parameter 1,
++       * parameter 2, ..., param n. To make things easy, we save the return
++       * address of efi_call_phys in a global variable.
++       */
++      popl    %edx
++      movl    %edx, saved_return_addr
++      /* get the function pointer into ECX*/
++      popl    %ecx
++      movl    %ecx, efi_rt_function_ptr
++      movl    $2f, %edx
++      subl    $__PAGE_OFFSET, %edx
++      pushl   %edx
++
++      /*
++       * 3. Clear PG bit in %CR0.
++       */
++      movl    %cr0, %edx
++      andl    $0x7fffffff, %edx
++      movl    %edx, %cr0
++      jmp     1f
++1:
++
++      /*
++       * 4. Adjust stack pointer.
++       */
++      subl    $__PAGE_OFFSET, %esp
++
++      /*
++       * 5. Call the physical function.
++       */
++      jmp     *%ecx
++
++2:
++      /*
++       * 6. After EFI runtime service returns, control will return to
++       * following instruction. We'd better readjust stack pointer first.
++       */
++      addl    $__PAGE_OFFSET, %esp
++
++      /*
++       * 7. Restore PG bit
++       */
++      movl    %cr0, %edx
++      orl     $0x80000000, %edx
++      movl    %edx, %cr0
++      jmp     1f
++1:
++      /*
++       * 8. Now restore the virtual mode from flat mode by
++       * adding EIP with PAGE_OFFSET.
++       */
++      movl    $1f, %edx
++      jmp     *%edx
++1:
++
++      /*
++       * 9. Balance the stack. And because EAX contain the return value,
++       * we'd better not clobber it.
++       */
++      leal    efi_rt_function_ptr, %edx
++      movl    (%edx), %ecx
++      pushl   %ecx
++
++      /*
++       * 10. Push the saved return address onto the stack and return.
++       */
++      leal    saved_return_addr, %edx
++      movl    (%edx), %ecx
++      pushl   %ecx
++      ret
++.previous
++
++.data
++saved_return_addr:
++      .long 0
++efi_rt_function_ptr:
++      .long 0
+--- linux-2.6.0-test6/arch/i386/kernel/entry.S 2003-08-22 19:23:40.000000000 -0700
++++ 25/arch/i386/kernel/entry.S        2003-10-05 00:36:48.000000000 -0700
+@@ -43,11 +43,25 @@
+ #include <linux/config.h>
+ #include <linux/linkage.h>
+ #include <asm/thread_info.h>
++#include <asm/asm_offsets.h>
+ #include <asm/errno.h>
+ #include <asm/segment.h>
++#include <asm/page.h>
+ #include <asm/smp.h>
+ #include <asm/page.h>
+ #include "irq_vectors.h"
++        /* We do not recover from a stack overflow, but at least
++         * we know it happened and should be able to track it down.
++         */
++#ifdef CONFIG_STACK_OVERFLOW_TEST
++#define STACK_OVERFLOW_TEST \
++        testl $7680,%esp;    \
++        jnz   10f;            \
++        call  stack_overflow; \
++10:
++#else
++#define STACK_OVERFLOW_TEST
++#endif
+ EBX           = 0x00
+ ECX           = 0x04
+@@ -85,7 +99,102 @@ TSS_ESP0_OFFSET = (4 - 0x200)
+ #define resume_kernel         restore_all
+ #endif
+-#define SAVE_ALL \
++#ifdef CONFIG_X86_HIGH_ENTRY
++
++#ifdef CONFIG_X86_SWITCH_PAGETABLES
++
++#if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP)
++/*
++ * If task is preempted in __SWITCH_KERNELSPACE, and moved to another cpu,
++ * __switch_to repoints %esp to the appropriate virtual stack; but %ebp is
++ * left stale, so we must check whether to repeat the real stack calculation.
++ */
++#define repeat_if_esp_changed                         \
++      xorl %esp, %ebp;                                \
++      testl $0xffffe000, %ebp;                        \
++      jnz 0b
++#else
++#define repeat_if_esp_changed
++#endif
++
++/* clobbers ebx, edx and ebp */
++
++#define __SWITCH_KERNELSPACE                          \
++      cmpl $0xff000000, %esp;                         \
++      jb 1f;                                          \
++                                                      \
++      /*                                              \
++       * switch pagetables and load the real stack,   \
++       * keep the stack offset:                       \
++       */                                             \
++                                                      \
++      movl $swapper_pg_dir-__PAGE_OFFSET, %edx;       \
++                                                      \
++      /* GET_THREAD_INFO(%ebp) intermixed */          \
++0:                                                    \
++      movl %esp, %ebp;                                \
++      movl %esp, %ebx;                                \
++      andl $0xffffe000, %ebp;                         \
++      andl $0x00001fff, %ebx;                         \
++      orl TI_real_stack(%ebp), %ebx;                  \
++      repeat_if_esp_changed;                          \
++                                                      \
++      movl %edx, %cr3;                                \
++      movl %ebx, %esp;                                \
++1:
++
++#endif
++
++
++#define __SWITCH_USERSPACE \
++      /* interrupted any of the user return paths? */ \
++                                                      \
++      movl EIP(%esp), %eax;                           \
++                                                      \
++      cmpl $int80_ret_start_marker, %eax;             \
++      jb 33f; /* nope - continue with sysexit check */\
++      cmpl $int80_ret_end_marker, %eax;               \
++      jb 22f; /* yes - switch to virtual stack */     \
++33:                                                   \
++      cmpl $sysexit_ret_start_marker, %eax;           \
++      jb 44f; /* nope - continue with user check */   \
++      cmpl $sysexit_ret_end_marker, %eax;             \
++      jb 22f; /* yes - switch to virtual stack */     \
++      /* return to userspace? */                      \
++44:                                                   \
++      movl EFLAGS(%esp),%ecx;                         \
++      movb CS(%esp),%cl;                              \
++      testl $(VM_MASK | 3),%ecx;                      \
++      jz 2f;                                          \
++22:                                                   \
++      /*                                              \
++       * switch to the virtual stack, then switch to  \
++       * the userspace pagetables.                    \
++       */                                             \
++                                                      \
++      GET_THREAD_INFO(%ebp);                          \
++      movl TI_virtual_stack(%ebp), %edx;              \
++      movl TI_user_pgd(%ebp), %ecx;                   \
++                                                      \
++      movl %esp, %ebx;                                \
++      andl $0x1fff, %ebx;                             \
++      orl %ebx, %edx;                                 \
++int80_ret_start_marker:                                       \
++      movl %edx, %esp;                                \
++      movl %ecx, %cr3;                                \
++                                                      \
++      __RESTORE_ALL;                                  \
++int80_ret_end_marker:                                 \
++2:
++
++#else /* !CONFIG_X86_HIGH_ENTRY */
++
++#define __SWITCH_KERNELSPACE
++#define __SWITCH_USERSPACE
++
++#endif
++
++#define __SAVE_ALL \
+       cld; \
+       pushl %es; \
+       pushl %ds; \
+@@ -100,7 +209,7 @@ TSS_ESP0_OFFSET = (4 - 0x200)
+       movl %edx, %ds; \
+       movl %edx, %es;
+-#define RESTORE_INT_REGS \
++#define __RESTORE_INT_REGS \
+       popl %ebx;      \
+       popl %ecx;      \
+       popl %edx;      \
+@@ -109,29 +218,28 @@ TSS_ESP0_OFFSET = (4 - 0x200)
+       popl %ebp;      \
+       popl %eax
+-#define RESTORE_REGS  \
+-      RESTORE_INT_REGS; \
+-1:    popl %ds;       \
+-2:    popl %es;       \
++#define __RESTORE_REGS        \
++      __RESTORE_INT_REGS; \
++111:  popl %ds;       \
++222:  popl %es;       \
+ .section .fixup,"ax"; \
+-3:    movl $0,(%esp); \
+-      jmp 1b;         \
+-4:    movl $0,(%esp); \
+-      jmp 2b;         \
++444:  movl $0,(%esp); \
++      jmp 111b;       \
++555:  movl $0,(%esp); \
++      jmp 222b;       \
+ .previous;            \
+ .section __ex_table,"a";\
+       .align 4;       \
+-      .long 1b,3b;    \
+-      .long 2b,4b;    \
++      .long 111b,444b;\
++      .long 222b,555b;\
+ .previous
+-
+-#define RESTORE_ALL   \
+-      RESTORE_REGS    \
++#define __RESTORE_ALL \
++      __RESTORE_REGS  \
+       addl $4, %esp;  \
+-1:    iret;           \
++333:  iret;           \
+ .section .fixup,"ax";   \
+-2:    sti;            \
++666:  sti;            \
+       movl $(__USER_DS), %edx; \
+       movl %edx, %ds; \
+       movl %edx, %es; \
+@@ -140,10 +248,19 @@ TSS_ESP0_OFFSET = (4 - 0x200)
+ .previous;            \
+ .section __ex_table,"a";\
+       .align 4;       \
+-      .long 1b,2b;    \
++      .long 333b,666b;\
+ .previous
++#define SAVE_ALL \
++      __SAVE_ALL;                                     \
++      __SWITCH_KERNELSPACE;                           \
++        STACK_OVERFLOW_TEST;
++
++#define RESTORE_ALL                                   \
++      __SWITCH_USERSPACE;                             \
++      __RESTORE_ALL;
++.section .entry.text,"ax"
+ ENTRY(lcall7)
+       pushfl                  # We get a different stack layout with call
+@@ -161,7 +278,7 @@ do_lcall:
+       movl %edx,EIP(%ebp)     # Now we move them to their "normal" places
+       movl %ecx,CS(%ebp)      #
+       andl $-8192, %ebp       # GET_THREAD_INFO
+-      movl TI_EXEC_DOMAIN(%ebp), %edx # Get the execution domain
++      movl TI_exec_domain(%ebp), %edx # Get the execution domain
+       call *4(%edx)           # Call the lcall7 handler for the domain
+       addl $4, %esp
+       popl %eax
+@@ -206,7 +323,7 @@ ENTRY(resume_userspace)
+       cli                             # make sure we don't miss an interrupt
+                                       # setting need_resched or sigpending
+                                       # between sampling and the iret
+-      movl TI_FLAGS(%ebp), %ecx
++      movl TI_flags(%ebp), %ecx
+       andl $_TIF_WORK_MASK, %ecx      # is there any work to be done on
+                                       # int/exception return?
+       jne work_pending
+@@ -214,18 +331,18 @@ ENTRY(resume_userspace)
+ #ifdef CONFIG_PREEMPT
+ ENTRY(resume_kernel)
+-      cmpl $0,TI_PRE_COUNT(%ebp)      # non-zero preempt_count ?
++      cmpl $0,TI_preempt_count(%ebp)  # non-zero preempt_count ?
+       jnz restore_all
+ need_resched:
+-      movl TI_FLAGS(%ebp), %ecx       # need_resched set ?
++      movl TI_flags(%ebp), %ecx       # need_resched set ?
+       testb $_TIF_NEED_RESCHED, %cl
+       jz restore_all
+       testl $IF_MASK,EFLAGS(%esp)     # interrupts off (exception path) ?
+       jz restore_all
+-      movl $PREEMPT_ACTIVE,TI_PRE_COUNT(%ebp)
++      movl $PREEMPT_ACTIVE,TI_preempt_count(%ebp)
+       sti
+       call schedule
+-      movl $0,TI_PRE_COUNT(%ebp)
++      movl $0,TI_preempt_count(%ebp)
+       cli
+       jmp need_resched
+ #endif
+@@ -244,37 +361,50 @@ sysenter_past_esp:
+       pushl $(__USER_CS)
+       pushl $SYSENTER_RETURN
+-/*
+- * Load the potential sixth argument from user stack.
+- * Careful about security.
+- */
+-      cmpl $__PAGE_OFFSET-3,%ebp
+-      jae syscall_fault
+-1:    movl (%ebp),%ebp
+-.section __ex_table,"a"
+-      .align 4
+-      .long 1b,syscall_fault
+-.previous
+-
+       pushl %eax
+       SAVE_ALL
+       GET_THREAD_INFO(%ebp)
+       cmpl $(nr_syscalls), %eax
+       jae syscall_badsys
+-      testb $_TIF_SYSCALL_TRACE,TI_FLAGS(%ebp)
++      testb $_TIF_SYSCALL_TRACE,TI_flags(%ebp)
+       jnz syscall_trace_entry
+       call *sys_call_table(,%eax,4)
+       movl %eax,EAX(%esp)
+       cli
+-      movl TI_FLAGS(%ebp), %ecx
++      movl TI_flags(%ebp), %ecx
+       testw $_TIF_ALLWORK_MASK, %cx
+       jne syscall_exit_work
++
++#ifdef CONFIG_X86_SWITCH_PAGETABLES
++
++      GET_THREAD_INFO(%ebp)
++      movl TI_virtual_stack(%ebp), %edx
++      movl TI_user_pgd(%ebp), %ecx
++      movl %esp, %ebx
++      andl $0x1fff, %ebx
++      orl %ebx, %edx
++sysexit_ret_start_marker:
++      movl %edx, %esp
++      movl %ecx, %cr3
++#endif
++      /*
++       * only ebx is not restored by the userspace sysenter vsyscall
++       * code, it assumes it to be callee-saved.
++       */
++      movl EBX(%esp), %ebx
++
+ /* if something modifies registers it must also disable sysexit */
++
+       movl EIP(%esp), %edx
+       movl OLDESP(%esp), %ecx
++
+       sti
+       sysexit
++#ifdef CONFIG_X86_SWITCH_PAGETABLES
++sysexit_ret_end_marker:
++      nop
++#endif
+       # system call handler stub
+@@ -285,7 +415,7 @@ ENTRY(system_call)
+       cmpl $(nr_syscalls), %eax
+       jae syscall_badsys
+                                       # system call tracing in operation
+-      testb $_TIF_SYSCALL_TRACE,TI_FLAGS(%ebp)
++      testb $_TIF_SYSCALL_TRACE,TI_flags(%ebp)
+       jnz syscall_trace_entry
+ syscall_call:
+       call *sys_call_table(,%eax,4)
+@@ -294,10 +424,23 @@ syscall_exit:
+       cli                             # make sure we don't miss an interrupt
+                                       # setting need_resched or sigpending
+                                       # between sampling and the iret
+-      movl TI_FLAGS(%ebp), %ecx
++      movl TI_flags(%ebp), %ecx
+       testw $_TIF_ALLWORK_MASK, %cx   # current->work
+       jne syscall_exit_work
+ restore_all:
++#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS
++      movl EFLAGS(%esp), %eax         # mix EFLAGS and CS
++      movb CS(%esp), %al
++      testl $(VM_MASK | 3), %eax
++      jz resume_kernelX               # returning to kernel or vm86-space
++
++      cmpl $0,TI_preempt_count(%ebp)  # non-zero preempt_count ?
++      jz resume_kernelX
++
++        int $3
++
++resume_kernelX:
++#endif
+       RESTORE_ALL
+       # perform work that needs to be done immediately before resumption
+@@ -310,7 +453,7 @@ work_resched:
+       cli                             # make sure we don't miss an interrupt
+                                       # setting need_resched or sigpending
+                                       # between sampling and the iret
+-      movl TI_FLAGS(%ebp), %ecx
++      movl TI_flags(%ebp), %ecx
+       andl $_TIF_WORK_MASK, %ecx      # is there any work to be done other
+                                       # than syscall tracing?
+       jz restore_all
+@@ -325,6 +468,22 @@ work_notifysig:                           # deal with pending s
+                                       # vm86-space
+       xorl %edx, %edx
+       call do_notify_resume
++
++#if CONFIG_X86_HIGH_ENTRY
++      /*
++       * Reload db7 if necessary:
++       */
++      movl TI_flags(%ebp), %ecx
++      testb $_TIF_DB7, %cl
++      jnz work_db7
++
++      jmp restore_all
++
++work_db7:
++      movl TI_task(%ebp), %edx;
++      movl task_thread_db7(%edx), %edx;
++      movl %edx, %db7;
++#endif
+       jmp restore_all
+       ALIGN
+@@ -380,7 +539,7 @@ syscall_badsys:
+  */
+ .data
+ ENTRY(interrupt)
+-.text
++.previous
+ vector=0
+ ENTRY(irq_entries_start)
+@@ -390,7 +549,7 @@ ENTRY(irq_entries_start)
+       jmp common_interrupt
+ .data
+       .long 1b
+-.text
++.previous
+ vector=vector+1
+ .endr
+@@ -431,12 +590,17 @@ error_code:
+       movl ES(%esp), %edi             # get the function address
+       movl %eax, ORIG_EAX(%esp)
+       movl %ecx, ES(%esp)
+-      movl %esp, %edx
+       pushl %esi                      # push the error code
+-      pushl %edx                      # push the pt_regs pointer
+       movl $(__USER_DS), %edx
+       movl %edx, %ds
+       movl %edx, %es
++
++/* clobbers edx, ebx and ebp */
++      __SWITCH_KERNELSPACE
++
++      leal 4(%esp), %edx              # prepare pt_regs
++      pushl %edx                      # push pt_regs
++
+       call *%edi
+       addl $8, %esp
+       jmp ret_from_exception
+@@ -527,7 +691,7 @@ nmi_stack_correct:
+       pushl %edx
+       call do_nmi
+       addl $8, %esp
+-      RESTORE_ALL
++      jmp restore_all
+ nmi_stack_fixup:
+       FIX_STACK(12,nmi_stack_correct, 1)
+@@ -595,7 +759,7 @@ ENTRY(page_fault)
+ #ifdef CONFIG_X86_MCE
+ ENTRY(machine_check)
+       pushl $0
+-      pushl $do_machine_check
++      pushl machine_check_vector
+       jmp error_code
+ #endif
+@@ -604,6 +768,8 @@ ENTRY(spurious_interrupt_bug)
+       pushl $do_spurious_interrupt_bug
+       jmp error_code
++.previous
++
+ .data
+ ENTRY(sys_call_table)
+       .long sys_restart_syscall       /* 0 - old "setup()" system call, used for restarting */
+@@ -879,5 +1045,60 @@ ENTRY(sys_call_table)
+       .long sys_tgkill        /* 270 */
+       .long sys_utimes
+       .long sys_fadvise64_64
++      .long sys_ni_syscall    /* sys_vserver */
+ nr_syscalls=(.-sys_call_table)/4
++
++
++#     Here we do call frames.  We cheat a bit as we only really need
++#     correct frames at locations we can actually look at from a
++#     debugger.  Since the break instruction trap actually goes thru
++#     some of this code, we don't really need info on those areas, but
++#     only after the fact.  I.e. if we can not step or break in a
++#     location or end up with a return address pointing at the
++#     location, we don't need a correct call frame for it.
++
++#if 0
++
++#include <linux/dwarf2-lang.h>
++/*
++ * The register numbers as known by gdb
++ */
++#define _EAX 0
++#define _ECX 1
++#define _EDX 2
++#define _EBX 3
++#define _ESP 4
++#define _EBP 5
++#define _ESI 6
++#define _EDI 7
++#define _PC  8
++#define _EIP 8
++#define _PS  9
++#define _EFLAGS  9
++#define _CS 10
++#define _SS 11
++#define _DS 12
++#define _ES 13
++#define _FS 14
++#define _GS 15
++
++      CFI_preamble(c1,_PC,1,1)
++      CFA_define_reference(_ESP,OLDESP)
++      CFA_define_offset(_EIP,EIP)
++      CFA_define_offset(_EBX,EBX)
++      CFA_define_offset(_ECX,ECX)
++      CFA_define_offset(_EDX,EDX)
++      CFA_define_offset(_ESI,ESI)
++      CFA_define_offset(_EDI,EDI)
++      CFA_define_offset(_EBP,EBP)
++      CFA_define_offset(_EAX,EAX)
++      CFA_define_offset(_EFLAGS,EFLAGS)
++      CFA_define_offset(_CS,CS)
++      CFA_define_offset(_DS,DS)
++      CFA_define_offset(_ES,ES)
++      CFI_postamble(c1)
++
++      FDE_preamble(c1,f1,ret_from_intr,(divide_error - ret_from_intr))
++      FDE_postamble(f1)
++#endif
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/arch/i386/kernel/entry_trampoline.c     2003-10-05 00:36:48.000000000 -0700
+@@ -0,0 +1,75 @@
++/*
++ * linux/arch/i386/kernel/entry_trampoline.c
++ *
++ * (C) Copyright 2003 Ingo Molnar
++ *
++ * This file contains the needed support code for 4GB userspace
++ */
++
++#include <linux/init.h>
++#include <linux/smp.h>
++#include <linux/mm.h>
++#include <linux/sched.h>
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/highmem.h>
++#include <asm/desc.h>
++#include <asm/atomic_kmap.h>
++
++extern char __entry_tramp_start, __entry_tramp_end, __start___entry_text;
++
++void __init init_entry_mappings(void)
++{
++#ifdef CONFIG_X86_HIGH_ENTRY
++      void *tramp;
++
++      /*
++       * We need a high IDT and GDT for the 4G/4G split:
++       */
++      trap_init_virtual_IDT();
++
++      __set_fixmap(FIX_ENTRY_TRAMPOLINE_0, __pa((unsigned long)&__entry_tramp_start), PAGE_KERNEL);
++      __set_fixmap(FIX_ENTRY_TRAMPOLINE_1, __pa((unsigned long)&__entry_tramp_start) + PAGE_SIZE, PAGE_KERNEL);
++      tramp = (void *)fix_to_virt(FIX_ENTRY_TRAMPOLINE_0);
++
++      printk("mapped 4G/4G trampoline to %p.\n", tramp);
++      BUG_ON((void *)&__start___entry_text != tramp);
++      /*
++       * Virtual kernel stack:
++       */
++      BUG_ON(__kmap_atomic_vaddr(KM_VSTACK0) & 8191);
++      BUG_ON(sizeof(struct desc_struct)*NR_CPUS*GDT_ENTRIES > 2*PAGE_SIZE);
++      BUG_ON((unsigned int)&__entry_tramp_end - (unsigned int)&__entry_tramp_start > 2*PAGE_SIZE);
++
++      /*
++       * set up the initial thread's virtual stack related
++       * fields:
++       */
++      current->thread.stack_page0 = virt_to_page((char *)current->thread_info);
++      current->thread.stack_page1 = virt_to_page((char *)current->thread_info + PAGE_SIZE);
++      current->thread_info->virtual_stack = (void *)__kmap_atomic_vaddr(KM_VSTACK0);
++
++      __kunmap_atomic_type(KM_VSTACK0);
++      __kunmap_atomic_type(KM_VSTACK1);
++        __kmap_atomic(current->thread.stack_page0, KM_VSTACK0);
++        __kmap_atomic(current->thread.stack_page1, KM_VSTACK1);
++
++#endif
++      printk("current: %p\n", current);
++      printk("current->thread_info: %p\n", current->thread_info);
++      current->thread_info->real_stack = (void *)current->thread_info;
++      current->thread_info->user_pgd = NULL;
++      current->thread.esp0 = (unsigned long)current->thread_info->real_stack + THREAD_SIZE;
++}
++
++
++
++void __init entry_trampoline_setup(void)
++{
++      /*
++       * old IRQ entries set up by the boot code will still hang
++       * around - they are a sign of hw trouble anyway, now they'll
++       * produce a double fault message.
++       */
++      trap_init_virtual_GDT();
++}
+--- linux-2.6.0-test6/arch/i386/kernel/head.S  2003-08-22 19:23:40.000000000 -0700
++++ 25/arch/i386/kernel/head.S 2003-10-05 00:36:48.000000000 -0700
+@@ -16,6 +16,7 @@
+ #include <asm/pgtable.h>
+ #include <asm/desc.h>
+ #include <asm/cache.h>
++#include <asm/asm_offsets.h>
+ #define OLD_CL_MAGIC_ADDR     0x90020
+ #define OLD_CL_MAGIC          0xA33F
+@@ -330,7 +331,7 @@ ENTRY(stack_start)
+ /* This is the default interrupt "handler" :-) */
+ int_msg:
+-      .asciz "Unknown interrupt\n"
++      .asciz "Unknown interrupt or fault at EIP %p %p %p\n"
+       ALIGN
+ ignore_int:
+       cld
+@@ -342,9 +343,17 @@ ignore_int:
+       movl $(__KERNEL_DS),%eax
+       movl %eax,%ds
+       movl %eax,%es
++      pushl 16(%esp)
++      pushl 24(%esp)
++      pushl 32(%esp)
++      pushl 40(%esp)
+       pushl $int_msg
+       call printk
+       popl %eax
++      popl %eax
++      popl %eax
++      popl %eax
++      popl %eax
+       popl %ds
+       popl %es
+       popl %edx
+@@ -377,23 +386,27 @@ cpu_gdt_descr:
+       .fill NR_CPUS-1,8,0             # space for the other GDT descriptors
+ /*
+- * This is initialized to create an identity-mapping at 0-8M (for bootup
+- * purposes) and another mapping of the 0-8M area at virtual address
++ * This is initialized to create an identity-mapping at 0-16M (for bootup
++ * purposes) and another mapping of the 0-16M area at virtual address
+  * PAGE_OFFSET.
+  */
+ .org 0x1000
+ ENTRY(swapper_pg_dir)
+       .long 0x00102007
+       .long 0x00103007
+-      .fill BOOT_USER_PGD_PTRS-2,4,0
+-      /* default: 766 entries */
++      .long 0x00104007
++      .long 0x00105007
++      .fill BOOT_USER_PGD_PTRS-4,4,0
++      /* default: 764 entries */
+       .long 0x00102007
+       .long 0x00103007
+-      /* default: 254 entries */
+-      .fill BOOT_KERNEL_PGD_PTRS-2,4,0
++      .long 0x00104007
++      .long 0x00105007
++      /* default: 252 entries */
++      .fill BOOT_KERNEL_PGD_PTRS-4,4,0
+ /*
+- * The page tables are initialized to only 8MB here - the final page
++ * The page tables are initialized to only 16MB here - the final page
+  * tables are set up later depending on memory size.
+  */
+ .org 0x2000
+@@ -402,15 +415,21 @@ ENTRY(pg0)
+ .org 0x3000
+ ENTRY(pg1)
++.org 0x4000
++ENTRY(pg2)
++
++.org 0x5000
++ENTRY(pg3)
++
+ /*
+  * empty_zero_page must immediately follow the page tables ! (The
+  * initialization loop counts until empty_zero_page)
+  */
+-.org 0x4000
++.org 0x6000
+ ENTRY(empty_zero_page)
+-.org 0x5000
++.org 0x7000
+ /*
+  * Real beginning of normal "text" segment
+@@ -419,12 +438,12 @@ ENTRY(stext)
+ ENTRY(_stext)
+ /*
+- * This starts the data section. Note that the above is all
+- * in the text section because it has alignment requirements
+- * that we cannot fulfill any other way.
++ * This starts the data section.
+  */
+ .data
++.align PAGE_SIZE_asm
++
+ /*
+  * The Global Descriptor Table contains 28 quadwords, per-CPU.
+  */
+@@ -439,7 +458,9 @@ ENTRY(boot_gdt_table)
+       .quad 0x00cf9a000000ffff        /* kernel 4GB code at 0x00000000 */
+       .quad 0x00cf92000000ffff        /* kernel 4GB data at 0x00000000 */
+ #endif
+-      .align L1_CACHE_BYTES
++
++.align PAGE_SIZE_asm
++
+ ENTRY(cpu_gdt_table)
+       .quad 0x0000000000000000        /* NULL descriptor */
+       .quad 0x0000000000000000        /* 0x0b reserved */
+--- linux-2.6.0-test6/arch/i386/kernel/i386_ksyms.c    2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/i386/kernel/i386_ksyms.c   2003-10-05 00:36:48.000000000 -0700
+@@ -98,7 +98,6 @@ EXPORT_SYMBOL_NOVERS(__down_failed_inter
+ EXPORT_SYMBOL_NOVERS(__down_failed_trylock);
+ EXPORT_SYMBOL_NOVERS(__up_wakeup);
+ /* Networking helper routines. */
+-EXPORT_SYMBOL(csum_partial_copy_generic);
+ /* Delay loops */
+ EXPORT_SYMBOL(__ndelay);
+ EXPORT_SYMBOL(__udelay);
+@@ -112,13 +111,17 @@ EXPORT_SYMBOL_NOVERS(__get_user_4);
+ EXPORT_SYMBOL(strpbrk);
+ EXPORT_SYMBOL(strstr);
++#if !defined(CONFIG_X86_UACCESS_INDIRECT)
+ EXPORT_SYMBOL(strncpy_from_user);
+-EXPORT_SYMBOL(__strncpy_from_user);
++EXPORT_SYMBOL(__direct_strncpy_from_user);
+ EXPORT_SYMBOL(clear_user);
+ EXPORT_SYMBOL(__clear_user);
+ EXPORT_SYMBOL(__copy_from_user_ll);
+ EXPORT_SYMBOL(__copy_to_user_ll);
+ EXPORT_SYMBOL(strnlen_user);
++#else /* CONFIG_X86_UACCESS_INDIRECT */
++EXPORT_SYMBOL(direct_csum_partial_copy_generic);
++#endif
+ EXPORT_SYMBOL(dma_alloc_coherent);
+ EXPORT_SYMBOL(dma_free_coherent);
+--- linux-2.6.0-test6/arch/i386/kernel/i387.c  2003-06-14 12:18:51.000000000 -0700
++++ 25/arch/i386/kernel/i387.c 2003-10-05 00:36:48.000000000 -0700
+@@ -219,6 +219,7 @@ void set_fpu_mxcsr( struct task_struct *
+ static int convert_fxsr_to_user( struct _fpstate __user *buf,
+                                       struct i387_fxsave_struct *fxsave )
+ {
++      struct _fpreg tmp[8]; /* 80 bytes scratch area */
+       unsigned long env[7];
+       struct _fpreg __user *to;
+       struct _fpxreg *from;
+@@ -235,23 +236,25 @@ static int convert_fxsr_to_user( struct 
+       if ( __copy_to_user( buf, env, 7 * sizeof(unsigned long) ) )
+               return 1;
+-      to = &buf->_st[0];
++      to = tmp;
+       from = (struct _fpxreg *) &fxsave->st_space[0];
+       for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
+               unsigned long *t = (unsigned long *)to;
+               unsigned long *f = (unsigned long *)from;
+-              if (__put_user(*f, t) ||
+-                              __put_user(*(f + 1), t + 1) ||
+-                              __put_user(from->exponent, &to->exponent))
+-                      return 1;
++              *t = *f;
++              *(t + 1) = *(f+1);
++              to->exponent = from->exponent;
+       }
++      if (copy_to_user(buf->_st, tmp, sizeof(struct _fpreg [8])))
++              return 1;
+       return 0;
+ }
+ static int convert_fxsr_from_user( struct i387_fxsave_struct *fxsave,
+                                         struct _fpstate __user *buf )
+ {
++      struct _fpreg tmp[8]; /* 80 bytes scratch area */
+       unsigned long env[7];
+       struct _fpxreg *to;
+       struct _fpreg __user *from;
+@@ -259,6 +262,8 @@ static int convert_fxsr_from_user( struc
+       if ( __copy_from_user( env, buf, 7 * sizeof(long) ) )
+               return 1;
++      if (copy_from_user(tmp, buf->_st, sizeof(struct _fpreg [8])))
++              return 1;
+       fxsave->cwd = (unsigned short)(env[0] & 0xffff);
+       fxsave->swd = (unsigned short)(env[1] & 0xffff);
+@@ -270,15 +275,14 @@ static int convert_fxsr_from_user( struc
+       fxsave->fos = env[6];
+       to = (struct _fpxreg *) &fxsave->st_space[0];
+-      from = &buf->_st[0];
++      from = tmp;
+       for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
+               unsigned long *t = (unsigned long *)to;
+               unsigned long *f = (unsigned long *)from;
+-              if (__get_user(*t, f) ||
+-                              __get_user(*(t + 1), f + 1) ||
+-                              __get_user(to->exponent, &from->exponent))
+-                      return 1;
++              *t = *f;
++              *(t + 1) = *(f + 1);
++              to->exponent = from->exponent;
+       }
+       return 0;
+ }
+@@ -549,13 +553,3 @@ int dump_task_extended_fpu(struct task_s
+       }
+       return fpvalid;
+ }
+-
+-
+-#ifdef CONFIG_SMP
+-void dump_smp_unlazy_fpu(void)
+-{
+-      unlazy_fpu(current);
+-      return;
+-}
+-#endif
+-
+--- linux-2.6.0-test6/arch/i386/kernel/i8259.c 2003-06-14 12:18:34.000000000 -0700
++++ 25/arch/i386/kernel/i8259.c        2003-10-05 00:36:20.000000000 -0700
+@@ -419,8 +419,10 @@ void __init init_IRQ(void)
+        * us. (some of these will be overridden and become
+        * 'special' SMP interrupts)
+        */
+-      for (i = 0; i < NR_IRQS; i++) {
++      for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) {
+               int vector = FIRST_EXTERNAL_VECTOR + i;
++              if (i >= NR_IRQS)
++                      break;
+               if (vector != SYSCALL_VECTOR) 
+                       set_intr_gate(vector, interrupt[i]);
+       }
+--- linux-2.6.0-test6/arch/i386/kernel/init_task.c     2003-06-14 12:18:35.000000000 -0700
++++ 25/arch/i386/kernel/init_task.c    2003-10-05 00:36:48.000000000 -0700
+@@ -23,7 +23,7 @@ struct mm_struct init_mm = INIT_MM(init_
+  */
+ union thread_union init_thread_union 
+       __attribute__((__section__(".data.init_task"))) =
+-              { INIT_THREAD_INFO(init_task) };
++              { INIT_THREAD_INFO(init_task, init_thread_union) };
+ /*
+  * Initial task structure.
+@@ -39,5 +39,5 @@ struct task_struct init_task = INIT_TASK
+  * section. Since TSS's are completely CPU-local, we want them
+  * on exact cacheline boundaries, to eliminate cacheline ping-pong.
+  */ 
+-struct tss_struct init_tss[NR_CPUS] __cacheline_aligned = { [0 ... NR_CPUS-1] = INIT_TSS };
++struct tss_struct init_tss[NR_CPUS] __attribute__((__section__(".data.tss"))) = { [0 ... NR_CPUS-1] = INIT_TSS };
+--- linux-2.6.0-test6/arch/i386/kernel/io_apic.c       2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/i386/kernel/io_apic.c      2003-10-05 00:36:27.000000000 -0700
+@@ -76,6 +76,14 @@ static struct irq_pin_list {
+       int apic, pin, next;
+ } irq_2_pin[PIN_MAP_SIZE];
++#ifdef CONFIG_PCI_USE_VECTOR
++int vector_irq[NR_IRQS] = { [0 ... NR_IRQS -1] = -1};
++#define vector_to_irq(vector)         \
++      (platform_legacy_irq(vector) ? vector : vector_irq[vector])
++#else
++#define vector_to_irq(vector) (vector)
++#endif
++
+ /*
+  * The common case is 1:1 IRQ<->pin mappings. Sometimes there are
+  * shared ISA-space IRQs, so we have to support them. We are super
+@@ -249,7 +257,7 @@ static void clear_IO_APIC (void)
+                       clear_IO_APIC_pin(apic, pin);
+ }
+-static void set_ioapic_affinity(unsigned int irq, cpumask_t cpumask)
++static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask)
+ {
+       unsigned long flags;
+       int pin;
+@@ -288,7 +296,7 @@ static void set_ioapic_affinity(unsigned
+ extern cpumask_t irq_affinity[NR_IRQS];
+-static cpumask_t __cacheline_aligned pending_irq_balance_cpumask[NR_IRQS];
++cpumask_t __cacheline_aligned pending_irq_balance_cpumask[NR_IRQS];
+ #define IRQBALANCE_CHECK_ARCH -999
+ static int irqbalance_disabled = IRQBALANCE_CHECK_ARCH;
+@@ -670,13 +678,11 @@ static int __init irqbalance_disable(cha
+ __setup("noirqbalance", irqbalance_disable);
+-static void set_ioapic_affinity(unsigned int irq, cpumask_t mask);
+-
+ static inline void move_irq(int irq)
+ {
+       /* note - we hold the desc->lock */
+       if (unlikely(!cpus_empty(pending_irq_balance_cpumask[irq]))) {
+-              set_ioapic_affinity(irq, pending_irq_balance_cpumask[irq]);
++              set_ioapic_affinity_irq(irq, pending_irq_balance_cpumask[irq]);
+               cpus_clear(pending_irq_balance_cpumask[irq]);
+       }
+ }
+@@ -853,7 +859,7 @@ void __init setup_ioapic_dest(cpumask_t 
+                       if (irq_entry == -1)
+                               continue;
+                       irq = pin_2_irq(irq_entry, ioapic, pin);
+-                      set_ioapic_affinity(irq, mask);
++                      set_ioapic_affinity_irq(irq, mask);
+               }
+       }
+@@ -1138,12 +1144,14 @@ static inline int IO_APIC_irq_trigger(in
+       return 0;
+ }
+-int irq_vector[NR_IRQS] = { FIRST_DEVICE_VECTOR , 0 };
++u8 *irq_vector;
++int nr_irqs;
+-static int __init assign_irq_vector(int irq)
++#ifndef CONFIG_PCI_USE_VECTOR
++int __init assign_irq_vector(int irq)
+ {
+       static int current_vector = FIRST_DEVICE_VECTOR, offset = 0;
+-      BUG_ON(irq >= NR_IRQS);
++      BUG_ON(irq >= nr_irqs);
+       if (IO_APIC_VECTOR(irq) > 0)
+               return IO_APIC_VECTOR(irq);
+ next:
+@@ -1157,11 +1165,36 @@ next:
+       }
+       IO_APIC_VECTOR(irq) = current_vector;
++
+       return current_vector;
+ }
++#endif
+-static struct hw_interrupt_type ioapic_level_irq_type;
+-static struct hw_interrupt_type ioapic_edge_irq_type;
++static struct hw_interrupt_type ioapic_level_type;
++static struct hw_interrupt_type ioapic_edge_type;
++
++#define IOAPIC_AUTO   -1
++#define IOAPIC_EDGE   0
++#define IOAPIC_LEVEL  1
++
++static inline void ioapic_register_intr(int irq, int vector, unsigned long trigger)
++{
++      if (use_pci_vector() && !platform_legacy_irq(irq)) {
++              if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
++                              trigger == IOAPIC_LEVEL)
++                      irq_desc[vector].handler = &ioapic_level_type;
++              else
++                      irq_desc[vector].handler = &ioapic_edge_type;
++              set_intr_gate(vector, interrupt[vector]);
++      } else  {
++              if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
++                              trigger == IOAPIC_LEVEL)
++                      irq_desc[irq].handler = &ioapic_level_type;
++              else
++                      irq_desc[irq].handler = &ioapic_edge_type;
++              set_intr_gate(vector, interrupt[irq]);
++      }
++}
+ void __init setup_IO_APIC_irqs(void)
+ {
+@@ -1219,13 +1252,7 @@ void __init setup_IO_APIC_irqs(void)
+               if (IO_APIC_IRQ(irq)) {
+                       vector = assign_irq_vector(irq);
+                       entry.vector = vector;
+-
+-                      if (IO_APIC_irq_trigger(irq))
+-                              irq_desc[irq].handler = &ioapic_level_irq_type;
+-                      else
+-                              irq_desc[irq].handler = &ioapic_edge_irq_type;
+-
+-                      set_intr_gate(vector, interrupt[irq]);
++                      ioapic_register_intr(irq, vector, IOAPIC_AUTO);
+               
+                       if (!apic && (irq < 16))
+                               disable_8259A_irq(irq);
+@@ -1272,7 +1299,7 @@ void __init setup_ExtINT_IRQ0_pin(unsign
+        * The timer IRQ doesn't have to know that behind the
+        * scene we have a 8259A-master in AEOI mode ...
+        */
+-      irq_desc[0].handler = &ioapic_edge_irq_type;
++      irq_desc[0].handler = &ioapic_edge_type;
+       /*
+        * Add it to the IO-APIC irq-routing table:
+@@ -1762,9 +1789,6 @@ static int __init timer_irq_works(void)
+  * that was delayed but this is now handled in the device
+  * independent code.
+  */
+-#define enable_edge_ioapic_irq unmask_IO_APIC_irq
+-
+-static void disable_edge_ioapic_irq (unsigned int irq) { /* nothing */ }
+ /*
+  * Starting up a edge-triggered IO-APIC interrupt is
+@@ -1775,7 +1799,6 @@ static void disable_edge_ioapic_irq (uns
+  * This is not complete - we should be able to fake
+  * an edge even if it isn't on the 8259A...
+  */
+-
+ static unsigned int startup_edge_ioapic_irq(unsigned int irq)
+ {
+       int was_pending = 0;
+@@ -1793,8 +1816,6 @@ static unsigned int startup_edge_ioapic_
+       return was_pending;
+ }
+-#define shutdown_edge_ioapic_irq      disable_edge_ioapic_irq
+-
+ /*
+  * Once we have recorded IRQ_PENDING already, we can mask the
+  * interrupt for real. This prevents IRQ storms from unhandled
+@@ -1809,9 +1830,6 @@ static void ack_edge_ioapic_irq(unsigned
+       ack_APIC_irq();
+ }
+-static void end_edge_ioapic_irq (unsigned int i) { /* nothing */ }
+-
+-
+ /*
+  * Level triggered interrupts can just be masked,
+  * and shutting down and starting up the interrupt
+@@ -1833,10 +1851,6 @@ static unsigned int startup_level_ioapic
+       return 0; /* don't check for pending */
+ }
+-#define shutdown_level_ioapic_irq     mask_IO_APIC_irq
+-#define enable_level_ioapic_irq               unmask_IO_APIC_irq
+-#define disable_level_ioapic_irq      mask_IO_APIC_irq
+-
+ static void end_level_ioapic_irq (unsigned int irq)
+ {
+       unsigned long v;
+@@ -1863,6 +1877,7 @@ static void end_level_ioapic_irq (unsign
+  * The idea is from Manfred Spraul.  --macro
+  */
+       i = IO_APIC_VECTOR(irq);
++
+       v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1));
+       ack_APIC_irq();
+@@ -1897,7 +1912,57 @@ static void end_level_ioapic_irq (unsign
+       }
+ }
+-static void mask_and_ack_level_ioapic_irq (unsigned int irq) { /* nothing */ }
++#ifdef CONFIG_PCI_USE_VECTOR
++static unsigned int startup_edge_ioapic_vector(unsigned int vector)
++{
++      int irq = vector_to_irq(vector);
++
++      return startup_edge_ioapic_irq(irq);
++}
++
++static void ack_edge_ioapic_vector(unsigned int vector)
++{
++      int irq = vector_to_irq(vector);
++
++      ack_edge_ioapic_irq(irq);
++}
++
++static unsigned int startup_level_ioapic_vector (unsigned int vector)
++{
++      int irq = vector_to_irq(vector);
++
++      return startup_level_ioapic_irq (irq);
++}
++
++static void end_level_ioapic_vector (unsigned int vector)
++{
++      int irq = vector_to_irq(vector);
++
++      end_level_ioapic_irq(irq);
++}
++
++static void mask_IO_APIC_vector (unsigned int vector)
++{
++      int irq = vector_to_irq(vector);
++
++      mask_IO_APIC_irq(irq);
++}
++
++static void unmask_IO_APIC_vector (unsigned int vector)
++{
++      int irq = vector_to_irq(vector);
++
++      unmask_IO_APIC_irq(irq);
++}
++
++static void set_ioapic_affinity_vector (unsigned int vector,
++                                      unsigned long cpu_mask)
++{
++      int irq = vector_to_irq(vector);
++
++      set_ioapic_affinity_irq(irq, cpu_mask);
++}
++#endif
+ /*
+  * Level and edge triggered IO-APIC interrupts need different handling,
+@@ -1907,26 +1972,25 @@ static void mask_and_ack_level_ioapic_ir
+  * edge-triggered handler, without risking IRQ storms and other ugly
+  * races.
+  */
+-
+-static struct hw_interrupt_type ioapic_edge_irq_type = {
++static struct hw_interrupt_type ioapic_edge_type = {
+       .typename       = "IO-APIC-edge",
+-      .startup        = startup_edge_ioapic_irq,
+-      .shutdown       = shutdown_edge_ioapic_irq,
+-      .enable         = enable_edge_ioapic_irq,
+-      .disable        = disable_edge_ioapic_irq,
+-      .ack            = ack_edge_ioapic_irq,
+-      .end            = end_edge_ioapic_irq,
++      .startup        = startup_edge_ioapic,
++      .shutdown       = shutdown_edge_ioapic,
++      .enable         = enable_edge_ioapic,
++      .disable        = disable_edge_ioapic,
++      .ack            = ack_edge_ioapic,
++      .end            = end_edge_ioapic,
+       .set_affinity   = set_ioapic_affinity,
+ };
+-static struct hw_interrupt_type ioapic_level_irq_type = {
++static struct hw_interrupt_type ioapic_level_type = {
+       .typename       = "IO-APIC-level",
+-      .startup        = startup_level_ioapic_irq,
+-      .shutdown       = shutdown_level_ioapic_irq,
+-      .enable         = enable_level_ioapic_irq,
+-      .disable        = disable_level_ioapic_irq,
+-      .ack            = mask_and_ack_level_ioapic_irq,
+-      .end            = end_level_ioapic_irq,
++      .startup        = startup_level_ioapic,
++      .shutdown       = shutdown_level_ioapic,
++      .enable         = enable_level_ioapic,
++      .disable        = disable_level_ioapic,
++      .ack            = mask_and_ack_level_ioapic,
++      .end            = end_level_ioapic,
+       .set_affinity   = set_ioapic_affinity,
+ };
+@@ -1946,7 +2010,13 @@ static inline void init_IO_APIC_traps(vo
+        * 0x80, because int 0x80 is hm, kind of importantish. ;)
+        */
+       for (irq = 0; irq < NR_IRQS ; irq++) {
+-              if (IO_APIC_IRQ(irq) && !IO_APIC_VECTOR(irq)) {
++              int tmp = irq;
++              if (use_pci_vector()) {
++                      if (!platform_legacy_irq(tmp))
++                              if ((tmp = vector_to_irq(tmp)) == -1)
++                                      continue;
++              }
++              if (IO_APIC_IRQ(tmp) && !IO_APIC_VECTOR(tmp)) {
+                       /*
+                        * Hmm.. We don't have an entry for this,
+                        * so default to an old-fashioned 8259
+@@ -2378,10 +2448,12 @@ int io_apic_set_pci_routing (int ioapic,
+               "IRQ %d Mode:%i Active:%i)\n", ioapic, 
+               mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq, edge_level, active_high_low);
++      if (use_pci_vector() && !platform_legacy_irq(irq))
++              irq = IO_APIC_VECTOR(irq);
+       if (edge_level) {
+-      irq_desc[irq].handler = &ioapic_level_irq_type;
++              irq_desc[irq].handler = &ioapic_level_type;
+       } else {
+-              irq_desc[irq].handler = &ioapic_edge_irq_type;
++              irq_desc[irq].handler = &ioapic_edge_type;
+       }
+       set_intr_gate(entry.vector, interrupt[irq]);
+--- linux-2.6.0-test6/arch/i386/kernel/irq.c   2003-08-22 19:23:40.000000000 -0700
++++ 25/arch/i386/kernel/irq.c  2003-10-05 00:33:50.000000000 -0700
+@@ -44,6 +44,7 @@
+ #include <asm/delay.h>
+ #include <asm/desc.h>
+ #include <asm/irq.h>
++#include <asm/kgdb.h>
+ /*
+  * Linux has a controller-independent x86 interrupt architecture.
+@@ -499,6 +500,17 @@ out:
+       irq_exit();
++#ifdef CONFIG_KGDB
++      /*
++       * We need to do this after clearing out of all the interrupt
++       * machinery because kgdb will reenter the NIC driver and the IRQ
++       * system.  synchronize_irq() (at least) will deadlock.
++       */
++      if (kgdb_eth_need_breakpoint[smp_processor_id()]) {
++              kgdb_eth_need_breakpoint[smp_processor_id()] = 0;
++              BREAKPOINT;
++      }
++#endif
+       return 1;
+ }
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/arch/i386/kernel/kgdb_stub.c    2003-10-05 00:33:51.000000000 -0700
+@@ -0,0 +1,2492 @@
++/*
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2, or (at your option) any
++ * later version.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.        See the GNU
++ * General Public License for more details.
++ *
++ */
++
++/*
++ * Copyright (c) 2000 VERITAS Software Corporation.
++ *
++ */
++/****************************************************************************
++ *  Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
++ *
++ *  Module name: remcom.c $
++ *  Revision: 1.34 $
++ *  Date: 91/03/09 12:29:49 $
++ *  Contributor:     Lake Stevens Instrument Division$
++ *
++ *  Description:     low level support for gdb debugger. $
++ *
++ *  Considerations:  only works on target hardware $
++ *
++ *  Written by:            Glenn Engel $
++ *  Updated by:            David Grothe <dave@gcom.com>
++ *  Updated by:            Robert Walsh <rjwalsh@durables.org>
++ *  Updated by:            wangdi <wangdi@clusterfs.com>
++ *  ModuleState:     Experimental $
++ *
++ *  NOTES:         See Below $
++ *
++ *  Modified for 386 by Jim Kingdon, Cygnus Support.
++ *  Compatibility with 2.1.xx kernel by David Grothe <dave@gcom.com>
++ *
++ *  Changes to allow auto initilization.  All that is needed is that it
++ *  be linked with the kernel and a break point (int 3) be executed.
++ *  The header file <asm/kgdb.h> defines BREAKPOINT to allow one to do
++ *  this. It should also be possible, once the interrupt system is up, to
++ *  call putDebugChar("+").  Once this is done, the remote debugger should
++ *  get our attention by sending a ^C in a packet. George Anzinger
++ *  <george@mvista.com>
++ *  Integrated into 2.2.5 kernel by Tigran Aivazian <tigran@sco.com>
++ *  Added thread support, support for multiple processors,
++ *    support for ia-32(x86) hardware debugging.
++ *    Amit S. Kale ( akale@veritas.com )
++ *
++ *  Modified to support debugging over ethernet by Robert Walsh
++ *  <rjwalsh@durables.org> and wangdi <wangdi@clusterfs.com>, based on
++ *  code by San Mehat.
++ *
++ *
++ *  To enable debugger support, two things need to happen.  One, a
++ *  call to set_debug_traps() is necessary in order to allow any breakpoints
++ *  or error conditions to be properly intercepted and reported to gdb.
++ *  Two, a breakpoint needs to be generated to begin communication.  This
++ *  is most easily accomplished by a call to breakpoint().  Breakpoint()
++ *  simulates a breakpoint by executing an int 3.
++ *
++ *************
++ *
++ *    The following gdb commands are supported:
++ *
++ * command        function                               Return value
++ *
++ *    g                   return the value of the CPU registers  hex data or ENN
++ *    G                   set the value of the CPU registers     OK or ENN
++ *
++ *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA    hex data or ENN
++ *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA    OK or ENN
++ *
++ *    c                   Resume at current address              SNN   ( signal NN)
++ *    cAA..AA     Continue at address AA..AA             SNN
++ *
++ *    s                   Step one instruction                   SNN
++ *    sAA..AA     Step one instruction from AA..AA       SNN
++ *
++ *    k                   kill
++ *
++ *    ?                   What was the last sigval ?             SNN   (signal NN)
++ *
++ * All commands and responses are sent with a packet which includes a
++ * checksum.  A packet consists of
++ *
++ * $<packet info>#<checksum>.
++ *
++ * where
++ * <packet info> :: <characters representing the command or response>
++ * <checksum>  :: < two hex digits computed as modulo 256 sum of <packetinfo>>
++ *
++ * When a packet is received, it is first acknowledged with either '+' or '-'.
++ * '+' indicates a successful transfer.        '-' indicates a failed transfer.
++ *
++ * Example:
++ *
++ * Host:                Reply:
++ * $m0,10#2a             +$00010203040506070809101112131415#42
++ *
++ ****************************************************************************/
++#define KGDB_VERSION "<20030915.1651.33>"
++#include <linux/config.h>
++#include <linux/types.h>
++#include <asm/string.h>               /* for strcpy */
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <asm/vm86.h>
++#include <asm/system.h>
++#include <asm/ptrace.h>               /* for linux pt_regs struct */
++#include <asm/kgdb_local.h>
++#include <linux/list.h>
++#include <asm/atomic.h>
++#include <asm/processor.h>
++#include <linux/irq.h>
++#include <asm/desc.h>
++#include <linux/inet.h>
++#include <linux/kallsyms.h>
++
++/************************************************************************
++ *
++ * external low-level support routines
++ */
++typedef void (*Function) (void);      /* pointer to a function */
++
++/* Thread reference */
++typedef unsigned char threadref[8];
++
++extern int tty_putDebugChar(int);     /* write a single character      */
++extern int tty_getDebugChar(void);    /* read and return a single char */
++extern void tty_flushDebugChar(void); /* flush pending characters      */
++extern int eth_putDebugChar(int);     /* write a single character      */
++extern int eth_getDebugChar(void);    /* read and return a single char */
++extern void eth_flushDebugChar(void); /* flush pending characters      */
++extern void kgdb_eth_set_trapmode(int);
++extern void kgdb_eth_reply_arp(void);   /*send arp request */
++extern volatile int kgdb_eth_is_initializing;
++
++
++/************************************************************************/
++/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
++/* at least NUMREGBYTES*2 are needed for register packets */
++/* Longer buffer is needed to list all threads */
++#define BUFMAX 400
++
++char *kgdb_version = KGDB_VERSION;
++
++/*  debug >  0 prints ill-formed commands in valid packets & checksum errors */
++int debug_regs = 0;           /* set to non-zero to print registers */
++
++/* filled in by an external module */
++char *gdb_module_offsets;
++
++static const char hexchars[] = "0123456789abcdef";
++
++/* Number of bytes of registers.  */
++#define NUMREGBYTES 64
++/*
++ * Note that this register image is in a different order than
++ * the register image that Linux produces at interrupt time.
++ *
++ * Linux's register image is defined by struct pt_regs in ptrace.h.
++ * Just why GDB uses a different order is a historical mystery.
++ */
++enum regnames { _EAX,         /* 0 */
++      _ECX,                   /* 1 */
++      _EDX,                   /* 2 */
++      _EBX,                   /* 3 */
++      _ESP,                   /* 4 */
++      _EBP,                   /* 5 */
++      _ESI,                   /* 6 */
++      _EDI,                   /* 7 */
++      _PC /* 8 also known as eip */ ,
++      _PS /* 9 also known as eflags */ ,
++      _CS,                    /* 10 */
++      _SS,                    /* 11 */
++      _DS,                    /* 12 */
++      _ES,                    /* 13 */
++      _FS,                    /* 14 */
++      _GS                     /* 15 */
++};
++
++/***************************  ASSEMBLY CODE MACROS *************************/
++/*
++ * Put the error code here just in case the user cares.
++ * Likewise, the vector number here (since GDB only gets the signal
++ * number through the usual means, and that's not very specific).
++ * The called_from is the return address so he can tell how we entered kgdb.
++ * This will allow him to seperate out the various possible entries.
++ */
++#define REMOTE_DEBUG 0                /* set != to turn on printing (also available in info) */
++
++#define PID_MAX PID_MAX_DEFAULT
++
++#ifdef CONFIG_SMP
++void smp_send_nmi_allbutself(void);
++#define IF_SMP(x) x
++#undef MAX_NO_CPUS
++#ifndef CONFIG_NO_KGDB_CPUS
++#define CONFIG_NO_KGDB_CPUS 2
++#endif
++#if CONFIG_NO_KGDB_CPUS > NR_CPUS
++#define MAX_NO_CPUS NR_CPUS
++#else
++#define MAX_NO_CPUS CONFIG_NO_KGDB_CPUS
++#endif
++#define hold_init hold_on_sstep: 1,
++#define MAX_CPU_MASK (unsigned long)((1LL << MAX_NO_CPUS) - 1LL)
++#define NUM_CPUS num_online_cpus()
++#else
++#define IF_SMP(x)
++#define hold_init
++#undef MAX_NO_CPUS
++#define MAX_NO_CPUS 1
++#define NUM_CPUS 1
++#endif
++#define NOCPU (struct task_struct *)0xbad1fbad
++/* *INDENT-OFF*        */
++struct kgdb_info {
++      int used_malloc;
++      void *called_from;
++      long long entry_tsc;
++      int errcode;
++      int vector;
++      int print_debug_info;
++#ifdef CONFIG_SMP
++      int hold_on_sstep;
++      struct {
++              volatile struct task_struct *task;
++              int pid;
++              int hold;
++              struct pt_regs *regs;
++      } cpus_waiting[MAX_NO_CPUS];
++#endif
++} kgdb_info = {hold_init print_debug_info:REMOTE_DEBUG, vector:-1};
++
++/* *INDENT-ON*        */
++
++#define used_m kgdb_info.used_malloc
++/*
++ * This is little area we set aside to contain the stack we
++ * need to build to allow gdb to call functions.  We use one
++ * per cpu to avoid locking issues.  We will do all this work
++ * with interrupts off so that should take care of the protection
++ * issues.
++ */
++#define LOOKASIDE_SIZE 200    /* should be more than enough */
++#define MALLOC_MAX   200      /* Max malloc size */
++struct {
++      unsigned int esp;
++      int array[LOOKASIDE_SIZE];
++} fn_call_lookaside[MAX_NO_CPUS];
++
++static int trap_cpu;
++static unsigned int OLD_esp;
++
++#define END_OF_LOOKASIDE  &fn_call_lookaside[trap_cpu].array[LOOKASIDE_SIZE]
++#define IF_BIT 0x200
++#define TF_BIT 0x100
++
++#define MALLOC_ROUND 8-1
++
++static char malloc_array[MALLOC_MAX];
++IF_SMP(static void to_gdb(const char *mess));
++void *
++malloc(int size)
++{
++
++      if (size <= (MALLOC_MAX - used_m)) {
++              int old_used = used_m;
++              used_m += ((size + MALLOC_ROUND) & (~MALLOC_ROUND));
++              return &malloc_array[old_used];
++      } else {
++              return NULL;
++      }
++}
++
++/*
++ * I/O dispatch functions...
++ * Based upon kgdb_eth, either call the ethernet
++ * handler or the serial one..
++ */
++void
++putDebugChar(int c)
++{
++      if (kgdb_eth == -1) {
++              tty_putDebugChar(c);
++      } else {
++              eth_putDebugChar(c);
++      }
++}
++
++int
++getDebugChar(void)
++{
++      if (kgdb_eth == -1) {
++              return tty_getDebugChar();
++      } else {
++              return eth_getDebugChar();
++      }
++}
++
++void
++flushDebugChar(void)
++{
++      if (kgdb_eth == -1) {
++              tty_flushDebugChar();
++      } else {
++              eth_flushDebugChar();
++      }
++}
++
++/*
++ * Gdb calls functions by pushing agruments, including a return address
++ * on the stack and the adjusting EIP to point to the function.        The
++ * whole assumption in GDB is that we are on a different stack than the
++ * one the "user" i.e. code that hit the break point, is on.  This, of
++ * course is not true in the kernel.  Thus various dodges are needed to
++ * do the call without directly messing with EIP (which we can not change
++ * as it is just a location and not a register.        To adjust it would then
++ * require that we move every thing below EIP up or down as needed.  This
++ * will not work as we may well have stack relative pointer on the stack
++ * (such as the pointer to regs, for example).
++
++ * So here is what we do:
++ * We detect gdb attempting to store into the stack area and instead, store
++ * into the fn_call_lookaside.array at the same relative location as if it
++ * were the area ESP pointed at.  We also trap ESP modifications
++ * and uses these to adjust fn_call_lookaside.esp.  On entry
++ * fn_call_lookaside.esp will be set to point at the last entry in
++ * fn_call_lookaside.array.  This allows us to check if it has changed, and
++ * if so, on exit, we add the registers we will use to do the move and a
++ * trap/ interrupt return exit sequence.  We then adjust the eflags in the
++ * regs array (remember we now have a copy in the fn_call_lookaside.array) to
++ * kill the interrupt bit, AND we change EIP to point at our set up stub.
++ * As part of the register set up we preset the registers to point at the
++ * begining and end of the fn_call_lookaside.array, so all the stub needs to
++ * do is move words from the array to the stack until ESP= the desired value
++ * then do the rti.  This will then transfer to the desired function with
++ * all the correct registers.  Nifty huh?
++ */
++extern asmlinkage void fn_call_stub(void);
++extern asmlinkage void fn_rtn_stub(void);
++/*                                       *INDENT-OFF*  */
++__asm__("fn_rtn_stub:\n\t"
++      "movl %eax,%esp\n\t"
++      "fn_call_stub:\n\t"
++      "1:\n\t"
++      "addl $-4,%ebx\n\t"
++      "movl (%ebx), %eax\n\t"
++      "pushl %eax\n\t"
++      "cmpl %esp,%ecx\n\t"
++      "jne  1b\n\t"
++      "popl %eax\n\t"
++      "popl %ebx\n\t"
++      "popl %ecx\n\t"
++      "iret \n\t");
++/*                                         *INDENT-ON*  */
++#define gdb_i386vector        kgdb_info.vector
++#define gdb_i386errcode kgdb_info.errcode
++#define waiting_cpus  kgdb_info.cpus_waiting
++#define remote_debug  kgdb_info.print_debug_info
++#define hold_cpu(cpu) kgdb_info.cpus_waiting[cpu].hold
++/* gdb locks */
++
++#ifdef CONFIG_SMP
++static int in_kgdb_called;
++static spinlock_t waitlocks[MAX_NO_CPUS] =
++    {[0 ... MAX_NO_CPUS - 1] = SPIN_LOCK_UNLOCKED };
++/*
++ * The following array has the thread pointer of each of the "other"
++ * cpus.  We make it global so it can be seen by gdb.
++ */
++volatile int in_kgdb_entry_log[MAX_NO_CPUS];
++volatile struct pt_regs *in_kgdb_here_log[MAX_NO_CPUS];
++/*
++static spinlock_t continuelocks[MAX_NO_CPUS];
++*/
++spinlock_t kgdb_spinlock = SPIN_LOCK_UNLOCKED;
++/* waiters on our spinlock plus us */
++static atomic_t spinlock_waiters = ATOMIC_INIT(1);
++static int spinlock_count = 0;
++static int spinlock_cpu = 0;
++/*
++ * Note we use nested spin locks to account for the case where a break
++ * point is encountered when calling a function by user direction from
++ * kgdb. Also there is the memory exception recursion to account for.
++ * Well, yes, but this lets other cpus thru too.  Lets add a
++ * cpu id to the lock.
++ */
++#define KGDB_SPIN_LOCK(x) if( spinlock_count == 0 || \
++                            spinlock_cpu != smp_processor_id()){\
++                                    atomic_inc(&spinlock_waiters); \
++                                    while (! spin_trylock(x)) {\
++                                          in_kgdb(&regs);\
++                                    }\
++                                    atomic_dec(&spinlock_waiters); \
++                                    spinlock_count = 1; \
++                                    spinlock_cpu = smp_processor_id(); \
++                        }else{  \
++                                    spinlock_count++; \
++                        }
++#define KGDB_SPIN_UNLOCK(x) if( --spinlock_count == 0) spin_unlock(x)
++#else
++unsigned kgdb_spinlock = 0;
++#define KGDB_SPIN_LOCK(x) --*x
++#define KGDB_SPIN_UNLOCK(x) ++*x
++#endif
++
++int
++hex(char ch)
++{
++      if ((ch >= 'a') && (ch <= 'f'))
++              return (ch - 'a' + 10);
++      if ((ch >= '0') && (ch <= '9'))
++              return (ch - '0');
++      if ((ch >= 'A') && (ch <= 'F'))
++              return (ch - 'A' + 10);
++      return (-1);
++}
++
++/* scan for the sequence $<data>#<checksum>   */
++void
++getpacket(char *buffer)
++{
++      unsigned char checksum;
++      unsigned char xmitcsum;
++      int i;
++      int count;
++      char ch;
++
++      do {
++              /* wait around for the start character, ignore all other characters */
++              while ((ch = (getDebugChar() & 0x7f)) != '$') ;
++              checksum = 0;
++              xmitcsum = -1;
++
++              count = 0;
++
++              /* now, read until a # or end of buffer is found */
++              while (count < BUFMAX) {
++                      ch = getDebugChar() & 0x7f;
++                      if (ch == '#')
++                              break;
++                      checksum = checksum + ch;
++                      buffer[count] = ch;
++                      count = count + 1;
++              }
++              buffer[count] = 0;
++
++              if (ch == '#') {
++                      xmitcsum = hex(getDebugChar() & 0x7f) << 4;
++                      xmitcsum += hex(getDebugChar() & 0x7f);
++                      if ((remote_debug) && (checksum != xmitcsum)) {
++                              printk
++                                  ("bad checksum.     My count = 0x%x, sent=0x%x. buf=%s\n",
++                                   checksum, xmitcsum, buffer);
++                      }
++
++                      if (checksum != xmitcsum)
++                              putDebugChar('-');      /* failed checksum */
++                      else {
++                              putDebugChar('+');      /* successful transfer */
++                              /* if a sequence char is present, reply the sequence ID */
++                              if (buffer[2] == ':') {
++                                      putDebugChar(buffer[0]);
++                                      putDebugChar(buffer[1]);
++                                      /* remove sequence chars from buffer */
++                                      count = strlen(buffer);
++                                      for (i = 3; i <= count; i++)
++                                              buffer[i - 3] = buffer[i];
++                              }
++                      }
++              }
++      } while (checksum != xmitcsum);
++
++      if (remote_debug)
++              printk("R:%s\n", buffer);
++      flushDebugChar();
++}
++
++/* send the packet in buffer.  */
++
++void
++putpacket(char *buffer)
++{
++      unsigned char checksum;
++      int count;
++      char ch;
++
++      /*  $<packet info>#<checksum>. */
++
++      if (kgdb_eth == -1) {
++              do {
++                      if (remote_debug)
++                              printk("T:%s\n", buffer);
++                      putDebugChar('$');
++                      checksum = 0;
++                      count = 0;
++
++                      while ((ch = buffer[count])) {
++                              putDebugChar(ch);
++                              checksum += ch;
++                              count += 1;
++                      }
++
++                      putDebugChar('#');
++                      putDebugChar(hexchars[checksum >> 4]);
++                      putDebugChar(hexchars[checksum % 16]);
++                      flushDebugChar();
++
++              } while ((getDebugChar() & 0x7f) != '+');
++      } else {
++              /*
++               * For udp, we can not transfer too much bytes once.
++               * We only transfer MAX_SEND_COUNT size bytes each time
++               */
++
++#define MAX_SEND_COUNT 30
++
++              int send_count = 0, i = 0;
++              char send_buf[MAX_SEND_COUNT];
++
++              do {
++                      if (remote_debug)
++                              printk("T:%s\n", buffer);
++                      putDebugChar('$');
++                      checksum = 0;
++                      count = 0;
++                      send_count = 0;
++                      while ((ch = buffer[count])) {
++                              if (send_count >= MAX_SEND_COUNT) {
++                                      for(i = 0; i < MAX_SEND_COUNT; i++) {
++                                              putDebugChar(send_buf[i]);
++                                      }
++                                      flushDebugChar();
++                                      send_count = 0;
++                              } else {
++                                      send_buf[send_count] = ch;
++                                      checksum += ch;
++                                      count ++;
++                                      send_count++;
++                              }
++                      }
++                      for(i = 0; i < send_count; i++)
++                              putDebugChar(send_buf[i]);
++                      putDebugChar('#');
++                      putDebugChar(hexchars[checksum >> 4]);
++                      putDebugChar(hexchars[checksum % 16]);
++                      flushDebugChar();
++              } while ((getDebugChar() & 0x7f) != '+');
++      }
++}
++
++static char remcomInBuffer[BUFMAX];
++static char remcomOutBuffer[BUFMAX];
++static short error;
++
++void
++debug_error(char *format, char *parm)
++{
++      if (remote_debug)
++              printk(format, parm);
++}
++
++static void
++print_regs(struct pt_regs *regs)
++{
++      printk("EAX=%08lx ", regs->eax);
++      printk("EBX=%08lx ", regs->ebx);
++      printk("ECX=%08lx ", regs->ecx);
++      printk("EDX=%08lx ", regs->edx);
++      printk("\n");
++      printk("ESI=%08lx ", regs->esi);
++      printk("EDI=%08lx ", regs->edi);
++      printk("EBP=%08lx ", regs->ebp);
++      printk("ESP=%08lx ", (long) &regs->esp);
++      printk("\n");
++      printk(" DS=%08x ", regs->xds);
++      printk(" ES=%08x ", regs->xes);
++      printk(" SS=%08x ", __KERNEL_DS);
++      printk(" FL=%08lx ", regs->eflags);
++      printk("\n");
++      printk(" CS=%08x ", regs->xcs);
++      printk(" IP=%08lx ", regs->eip);
++#if 0
++      printk(" FS=%08x ", regs->fs);
++      printk(" GS=%08x ", regs->gs);
++#endif
++      printk("\n");
++
++}                             /* print_regs */
++
++#define NEW_esp fn_call_lookaside[trap_cpu].esp
++
++static void
++regs_to_gdb_regs(int *gdb_regs, struct pt_regs *regs)
++{
++      gdb_regs[_EAX] = regs->eax;
++      gdb_regs[_EBX] = regs->ebx;
++      gdb_regs[_ECX] = regs->ecx;
++      gdb_regs[_EDX] = regs->edx;
++      gdb_regs[_ESI] = regs->esi;
++      gdb_regs[_EDI] = regs->edi;
++      gdb_regs[_EBP] = regs->ebp;
++      gdb_regs[_DS] = regs->xds;
++      gdb_regs[_ES] = regs->xes;
++      gdb_regs[_PS] = regs->eflags;
++      gdb_regs[_CS] = regs->xcs;
++      gdb_regs[_PC] = regs->eip;
++      /* Note, as we are a debugging the kernel, we will always
++       * trap in kernel code, this means no priviledge change,
++       * and so the pt_regs structure is not completely valid.  In a non
++       * privilege change trap, only EFLAGS, CS and EIP are put on the stack,
++       * SS and ESP are not stacked, this means that the last 2 elements of
++       * pt_regs is not valid (they would normally refer to the user stack)
++       * also, using regs+1 is no good because you end up will a value that is
++       * 2 longs (8) too high.  This used to cause stepping over functions
++       * to fail, so my fix is to use the address of regs->esp, which
++       * should point at the end of the stack frame.  Note I have ignored
++       * completely exceptions that cause an error code to be stacked, such
++       * as double fault.  Stuart Hughes, Zentropix.
++       * original code: gdb_regs[_ESP] =  (int) (regs + 1) ;
++
++       * this is now done on entry and moved to OLD_esp (as well as NEW_esp).
++       */
++      gdb_regs[_ESP] = NEW_esp;
++      gdb_regs[_SS] = __KERNEL_DS;
++      gdb_regs[_FS] = 0xFFFF;
++      gdb_regs[_GS] = 0xFFFF;
++}                             /* regs_to_gdb_regs */
++
++static void
++gdb_regs_to_regs(int *gdb_regs, struct pt_regs *regs)
++{
++      regs->eax = gdb_regs[_EAX];
++      regs->ebx = gdb_regs[_EBX];
++      regs->ecx = gdb_regs[_ECX];
++      regs->edx = gdb_regs[_EDX];
++      regs->esi = gdb_regs[_ESI];
++      regs->edi = gdb_regs[_EDI];
++      regs->ebp = gdb_regs[_EBP];
++      regs->xds = gdb_regs[_DS];
++      regs->xes = gdb_regs[_ES];
++      regs->eflags = gdb_regs[_PS];
++      regs->xcs = gdb_regs[_CS];
++      regs->eip = gdb_regs[_PC];
++      NEW_esp = gdb_regs[_ESP];       /* keep the value */
++#if 0                         /* can't change these */
++      regs->esp = gdb_regs[_ESP];
++      regs->xss = gdb_regs[_SS];
++      regs->fs = gdb_regs[_FS];
++      regs->gs = gdb_regs[_GS];
++#endif
++
++}                             /* gdb_regs_to_regs */
++extern void scheduling_functions_start_here(void);
++extern void scheduling_functions_end_here(void);
++#define first_sched   ((unsigned long) scheduling_functions_start_here)
++#define last_sched    ((unsigned long) scheduling_functions_end_here)
++
++int thread_list = 0;
++
++void
++get_gdb_regs(struct task_struct *p, struct pt_regs *regs, int *gdb_regs)
++{
++      unsigned long stack_page;
++      int count = 0;
++      IF_SMP(int i);
++      if (!p || p == current) {
++              regs_to_gdb_regs(gdb_regs, regs);
++              return;
++      }
++#ifdef CONFIG_SMP
++      for (i = 0; i < MAX_NO_CPUS; i++) {
++              if (p == kgdb_info.cpus_waiting[i].task) {
++                      regs_to_gdb_regs(gdb_regs,
++                                       kgdb_info.cpus_waiting[i].regs);
++                      gdb_regs[_ESP] =
++                          (int) &kgdb_info.cpus_waiting[i].regs->esp;
++
++                      return;
++              }
++      }
++#endif
++      memset(gdb_regs, 0, NUMREGBYTES);
++      gdb_regs[_ESP] = p->thread.esp;
++      gdb_regs[_PC] = p->thread.eip;
++      gdb_regs[_EBP] = *(int *) gdb_regs[_ESP];
++      gdb_regs[_EDI] = *(int *) (gdb_regs[_ESP] + 4);
++      gdb_regs[_ESI] = *(int *) (gdb_regs[_ESP] + 8);
++
++/*
++ * This code is to give a more informative notion of where a process
++ * is waiting.        It is used only when the user asks for a thread info
++ * list.  If he then switches to the thread, s/he will find the task
++ * is in schedule, but a back trace should show the same info we come
++ * up with.  This code was shamelessly purloined from process.c.  It was
++ * then enhanced to provide more registers than simply the program
++ * counter.
++ */
++
++      if (!thread_list) {
++              return;
++      }
++
++      if (p->state == TASK_RUNNING)
++              return;
++      stack_page = (unsigned long) p->thread_info;
++      if (gdb_regs[_ESP] < stack_page || gdb_regs[_ESP] > 8188 + stack_page)
++              return;
++      /* include/asm-i386/system.h:switch_to() pushes ebp last. */
++      do {
++              if (gdb_regs[_EBP] < stack_page ||
++                  gdb_regs[_EBP] > 8184 + stack_page)
++                      return;
++              gdb_regs[_PC] = *(unsigned long *) (gdb_regs[_EBP] + 4);
++              gdb_regs[_ESP] = gdb_regs[_EBP] + 8;
++              gdb_regs[_EBP] = *(unsigned long *) gdb_regs[_EBP];
++              if (gdb_regs[_PC] < first_sched || gdb_regs[_PC] >= last_sched)
++                      return;
++      } while (count++ < 16);
++      return;
++}
++
++/* Indicate to caller of mem2hex or hex2mem that there has been an
++   error.  */
++static volatile int mem_err = 0;
++static volatile int mem_err_expected = 0;
++static volatile int mem_err_cnt = 0;
++static int garbage_loc = -1;
++
++int
++get_char(char *addr)
++{
++      return *addr;
++}
++
++void
++set_char(char *addr, int val, int may_fault)
++{
++      /*
++       * This code traps references to the area mapped to the kernel
++       * stack as given by the regs and, instead, stores to the
++       * fn_call_lookaside[cpu].array
++       */
++      if (may_fault &&
++          (unsigned int) addr < OLD_esp &&
++          ((unsigned int) addr > (OLD_esp - (unsigned int) LOOKASIDE_SIZE))) {
++              addr = (char *) END_OF_LOOKASIDE - ((char *) OLD_esp - addr);
++      }
++      *addr = val;
++}
++
++/* convert the memory pointed to by mem into hex, placing result in buf */
++/* return a pointer to the last char put in buf (null) */
++/* If MAY_FAULT is non-zero, then we should set mem_err in response to
++   a fault; if zero treat a fault like any other fault in the stub.  */
++char *
++mem2hex(char *mem, char *buf, int count, int may_fault)
++{
++      int i;
++      unsigned char ch;
++
++      if (may_fault) {
++              mem_err_expected = 1;
++              mem_err = 0;
++      }
++      for (i = 0; i < count; i++) {
++              /* printk("%lx = ", mem) ; */
++
++              ch = get_char(mem++);
++
++              /* printk("%02x\n", ch & 0xFF) ; */
++              if (may_fault && mem_err) {
++                      if (remote_debug)
++                              printk("Mem fault fetching from addr %lx\n",
++                                     (long) (mem - 1));
++                      *buf = 0;       /* truncate buffer */
++                      return (buf);
++              }
++              *buf++ = hexchars[ch >> 4];
++              *buf++ = hexchars[ch % 16];
++      }
++      *buf = 0;
++      if (may_fault)
++              mem_err_expected = 0;
++      return (buf);
++}
++
++/* convert the hex array pointed to by buf into binary to be placed in mem */
++/* return a pointer to the character AFTER the last byte written */
++/* NOTE: We use the may fault flag to also indicate if the write is to
++ * the registers (0) or "other" memory (!=0)
++ */
++char *
++hex2mem(char *buf, char *mem, int count, int may_fault)
++{
++      int i;
++      unsigned char ch;
++
++      if (may_fault) {
++              mem_err_expected = 1;
++              mem_err = 0;
++      }
++      for (i = 0; i < count; i++) {
++              ch = hex(*buf++) << 4;
++              ch = ch + hex(*buf++);
++              set_char(mem++, ch, may_fault);
++
++              if (may_fault && mem_err) {
++                      if (remote_debug)
++                              printk("Mem fault storing to addr %lx\n",
++                                     (long) (mem - 1));
++                      return (mem);
++              }
++      }
++      if (may_fault)
++              mem_err_expected = 0;
++      return (mem);
++}
++
++/**********************************************/
++/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
++/* RETURN NUMBER OF CHARS PROCESSED         */
++/**********************************************/
++int
++hexToInt(char **ptr, int *intValue)
++{
++      int numChars = 0;
++      int hexValue;
++
++      *intValue = 0;
++
++      while (**ptr) {
++              hexValue = hex(**ptr);
++              if (hexValue >= 0) {
++                      *intValue = (*intValue << 4) | hexValue;
++                      numChars++;
++              } else
++                      break;
++
++              (*ptr)++;
++      }
++
++      return (numChars);
++}
++
++#define stubhex(h) hex(h)
++#ifdef old_thread_list
++
++static int
++stub_unpack_int(char *buff, int fieldlength)
++{
++      int nibble;
++      int retval = 0;
++
++      while (fieldlength) {
++              nibble = stubhex(*buff++);
++              retval |= nibble;
++              fieldlength--;
++              if (fieldlength)
++                      retval = retval << 4;
++      }
++      return retval;
++}
++#endif
++static char *
++pack_hex_byte(char *pkt, int byte)
++{
++      *pkt++ = hexchars[(byte >> 4) & 0xf];
++      *pkt++ = hexchars[(byte & 0xf)];
++      return pkt;
++}
++
++#define BUF_THREAD_ID_SIZE 16
++
++static char *
++pack_threadid(char *pkt, threadref * id)
++{
++      char *limit;
++      unsigned char *altid;
++
++      altid = (unsigned char *) id;
++      limit = pkt + BUF_THREAD_ID_SIZE;
++      while (pkt < limit)
++              pkt = pack_hex_byte(pkt, *altid++);
++      return pkt;
++}
++
++#ifdef old_thread_list
++static char *
++unpack_byte(char *buf, int *value)
++{
++      *value = stub_unpack_int(buf, 2);
++      return buf + 2;
++}
++
++static char *
++unpack_threadid(char *inbuf, threadref * id)
++{
++      char *altref;
++      char *limit = inbuf + BUF_THREAD_ID_SIZE;
++      int x, y;
++
++      altref = (char *) id;
++
++      while (inbuf < limit) {
++              x = stubhex(*inbuf++);
++              y = stubhex(*inbuf++);
++              *altref++ = (x << 4) | y;
++      }
++      return inbuf;
++}
++#endif
++void
++int_to_threadref(threadref * id, int value)
++{
++      unsigned char *scan;
++
++      scan = (unsigned char *) id;
++      {
++              int i = 4;
++              while (i--)
++                      *scan++ = 0;
++      }
++      *scan++ = (value >> 24) & 0xff;
++      *scan++ = (value >> 16) & 0xff;
++      *scan++ = (value >> 8) & 0xff;
++      *scan++ = (value & 0xff);
++}
++int
++int_to_hex_v(unsigned char * id, int value)
++{
++      unsigned char *start = id;
++      int shift;
++      int ch;
++
++      for (shift = 28; shift >= 0; shift -= 4) {
++              if ((ch = (value >> shift) & 0xf) || (id != start)) {
++                      *id = hexchars[ch];
++                      id++;
++              }
++      }
++      if (id == start)
++              *id++ = '0';
++      return id - start;
++}
++#ifdef old_thread_list
++
++static int
++threadref_to_int(threadref * ref)
++{
++      int i, value = 0;
++      unsigned char *scan;
++
++      scan = (char *) ref;
++      scan += 4;
++      i = 4;
++      while (i-- > 0)
++              value = (value << 8) | ((*scan++) & 0xff);
++      return value;
++}
++#endif
++static int
++cmp_str(char *s1, char *s2, int count)
++{
++      while (count--) {
++              if (*s1++ != *s2++)
++                      return 0;
++      }
++      return 1;
++}
++
++#if 1                         /* this is a hold over from 2.4 where O(1) was "sometimes" */
++extern struct task_struct *kgdb_get_idle(int cpu);
++#define idle_task(cpu) kgdb_get_idle(cpu)
++#else
++#define idle_task(cpu) init_tasks[cpu]
++#endif
++
++extern int kgdb_pid_init_done;
++
++struct task_struct *
++getthread(int pid)
++{
++      struct task_struct *thread;
++      if (pid >= PID_MAX && pid <= (PID_MAX + MAX_NO_CPUS)) {
++
++              return idle_task(pid - PID_MAX);
++      } else {
++              /*
++               * find_task_by_pid is relatively safe all the time
++               * Other pid functions require lock downs which imply
++               * that we may be interrupting them (as we get here
++               * in the middle of most any lock down).
++               * Still we don't want to call until the table exists!
++               */
++              if (kgdb_pid_init_done){
++                      thread = find_task_by_pid(pid);
++                      if (thread) {
++                              return thread;
++                      }
++              }
++      }
++      return NULL;
++}
++/* *INDENT-OFF*        */
++struct hw_breakpoint {
++      unsigned enabled;
++      unsigned type;
++      unsigned len;
++      unsigned addr;
++} breakinfo[4] = { {enabled:0},
++                 {enabled:0},
++                 {enabled:0},
++                 {enabled:0}};
++/* *INDENT-ON*        */
++unsigned hw_breakpoint_status;
++void
++correct_hw_break(void)
++{
++      int breakno;
++      int correctit;
++      int breakbit;
++      unsigned dr7;
++
++      asm volatile ("movl %%db7, %0\n":"=r" (dr7)
++                    :);
++      /* *INDENT-OFF*  */
++      do {
++              unsigned addr0, addr1, addr2, addr3;
++              asm volatile ("movl %%db0, %0\n"
++                            "movl %%db1, %1\n"
++                            "movl %%db2, %2\n"
++                            "movl %%db3, %3\n"
++                            :"=r" (addr0), "=r"(addr1),
++                            "=r"(addr2), "=r"(addr3)
++                            :);
++      } while (0);
++      /* *INDENT-ON*  */
++      correctit = 0;
++      for (breakno = 0; breakno < 3; breakno++) {
++              breakbit = 2 << (breakno << 1);
++              if (!(dr7 & breakbit) && breakinfo[breakno].enabled) {
++                      correctit = 1;
++                      dr7 |= breakbit;
++                      dr7 &= ~(0xf0000 << (breakno << 2));
++                      dr7 |= (((breakinfo[breakno].len << 2) |
++                               breakinfo[breakno].type) << 16) <<
++                          (breakno << 2);
++                      switch (breakno) {
++                      case 0:
++                              asm volatile ("movl %0, %%dr0\n"::"r"
++                                            (breakinfo[breakno].addr));
++                              break;
++
++                      case 1:
++                              asm volatile ("movl %0, %%dr1\n"::"r"
++                                            (breakinfo[breakno].addr));
++                              break;
++
++                      case 2:
++                              asm volatile ("movl %0, %%dr2\n"::"r"
++                                            (breakinfo[breakno].addr));
++                              break;
++
++                      case 3:
++                              asm volatile ("movl %0, %%dr3\n"::"r"
++                                            (breakinfo[breakno].addr));
++                              break;
++                      }
++              } else if ((dr7 & breakbit) && !breakinfo[breakno].enabled) {
++                      correctit = 1;
++                      dr7 &= ~breakbit;
++                      dr7 &= ~(0xf0000 << (breakno << 2));
++              }
++      }
++      if (correctit) {
++              asm volatile ("movl %0, %%db7\n"::"r" (dr7));
++      }
++}
++
++int
++remove_hw_break(unsigned breakno)
++{
++      if (!breakinfo[breakno].enabled) {
++              return -1;
++      }
++      breakinfo[breakno].enabled = 0;
++      return 0;
++}
++
++int
++set_hw_break(unsigned breakno, unsigned type, unsigned len, unsigned addr)
++{
++      if (breakinfo[breakno].enabled) {
++              return -1;
++      }
++      breakinfo[breakno].enabled = 1;
++      breakinfo[breakno].type = type;
++      breakinfo[breakno].len = len;
++      breakinfo[breakno].addr = addr;
++      return 0;
++}
++
++#ifdef CONFIG_SMP
++static int in_kgdb_console = 0;
++
++int
++in_kgdb(struct pt_regs *regs)
++{
++      unsigned flags;
++      int cpu = smp_processor_id();
++      in_kgdb_called = 1;
++      if (!spin_is_locked(&kgdb_spinlock)) {
++              if (in_kgdb_here_log[cpu] ||    /* we are holding this cpu */
++                  in_kgdb_console) {  /* or we are doing slow i/o */
++                      return 1;
++              }
++              return 0;
++      }
++
++      /* As I see it the only reason not to let all cpus spin on
++       * the same spin_lock is to allow selected ones to proceed.
++       * This would be a good thing, so we leave it this way.
++       * Maybe someday....  Done !
++
++       * in_kgdb() is called from an NMI so we don't pretend
++       * to have any resources, like printk() for example.
++       */
++
++      kgdb_local_irq_save(flags);     /* only local here, to avoid hanging */
++      /*
++       * log arival of this cpu
++       * The NMI keeps on ticking.  Protect against recurring more
++       * than once, and ignor the cpu that has the kgdb lock
++       */
++      in_kgdb_entry_log[cpu]++;
++      in_kgdb_here_log[cpu] = regs;
++      if (cpu == spinlock_cpu || waiting_cpus[cpu].task) {
++              goto exit_in_kgdb;
++      }
++      /*
++       * For protection of the initilization of the spin locks by kgdb
++       * it locks the kgdb spinlock before it gets the wait locks set
++       * up.  We wait here for the wait lock to be taken.  If the
++       * kgdb lock goes away first??  Well, it could be a slow exit
++       * sequence where the wait lock is removed prior to the kgdb lock
++       * so if kgdb gets unlocked, we just exit.
++       */
++      while (spin_is_locked(&kgdb_spinlock) &&
++             !spin_is_locked(waitlocks + cpu)) ;
++      if (!spin_is_locked(&kgdb_spinlock)) {
++              goto exit_in_kgdb;
++      }
++      waiting_cpus[cpu].task = current;
++      waiting_cpus[cpu].pid = (current->pid) ? : (PID_MAX + cpu);
++      waiting_cpus[cpu].regs = regs;
++
++      spin_unlock_wait(waitlocks + cpu);
++      /*
++       * log departure of this cpu
++       */
++      waiting_cpus[cpu].task = 0;
++      waiting_cpus[cpu].pid = 0;
++      waiting_cpus[cpu].regs = 0;
++      correct_hw_break();
++      exit_in_kgdb:
++      in_kgdb_here_log[cpu] = 0;
++      kgdb_local_irq_restore(flags);
++      return 1;
++      /*
++         spin_unlock(continuelocks + smp_processor_id());
++       */
++}
++
++void
++smp__in_kgdb(struct pt_regs regs)
++{
++      ack_APIC_irq();
++      in_kgdb(&regs);
++}
++#else
++int
++in_kgdb(struct pt_regs *regs)
++{
++      return (kgdb_spinlock);
++}
++#endif
++
++void
++printexceptioninfo(int exceptionNo, int errorcode, char *buffer)
++{
++      unsigned dr6;
++      int i;
++      switch (exceptionNo) {
++      case 1:         /* debug exception */
++              break;
++      case 3:         /* breakpoint */
++              sprintf(buffer, "Software breakpoint");
++              return;
++      default:
++              sprintf(buffer, "Details not available");
++              return;
++      }
++      asm volatile ("movl %%db6, %0\n":"=r" (dr6)
++                    :);
++      if (dr6 & 0x4000) {
++              sprintf(buffer, "Single step");
++              return;
++      }
++      for (i = 0; i < 4; ++i) {
++              if (dr6 & (1 << i)) {
++                      sprintf(buffer, "Hardware breakpoint %d", i);
++                      return;
++              }
++      }
++      sprintf(buffer, "Unknown trap");
++      return;
++}
++
++/*
++ * This function does all command procesing for interfacing to gdb.
++ *
++ * NOTE:  The INT nn instruction leaves the state of the interrupt
++ *      enable flag UNCHANGED.  That means that when this routine
++ *      is entered via a breakpoint (INT 3) instruction from code
++ *      that has interrupts enabled, then interrupts will STILL BE
++ *      enabled when this routine is entered.  The first thing that
++ *      we do here is disable interrupts so as to prevent recursive
++ *      entries and bothersome serial interrupts while we are
++ *      trying to run the serial port in polled mode.
++ *
++ * For kernel version 2.1.xx the kgdb_cli() actually gets a spin lock so
++ * it is always necessary to do a restore_flags before returning
++ * so as to let go of that lock.
++ */
++int
++kgdb_handle_exception(int exceptionVector,
++                    int signo, int err_code, struct pt_regs *linux_regs)
++{
++      struct task_struct *usethread = NULL;
++      struct task_struct *thread_list_start = 0, *thread = NULL;
++      int addr, length;
++      unsigned long address;
++      int breakno, breaktype;
++      char *ptr;
++      int newPC;
++      threadref thref;
++      int threadid;
++      int thread_min = PID_MAX + MAX_NO_CPUS;
++#ifdef old_thread_list
++      int maxthreads;
++#endif
++      int nothreads;
++      unsigned long flags;
++      int gdb_regs[NUMREGBYTES / 4];
++      int dr6;
++      IF_SMP(int entry_state = 0);    /* 0, ok, 1, no nmi, 2 sync failed */
++#define NO_NMI 1
++#define NO_SYNC 2
++#define       regs    (*linux_regs)
++#define NUMREGS NUMREGBYTES/4
++      /*
++       * If the entry is not from the kernel then return to the Linux
++       * trap handler and let it process the interrupt normally.
++       */
++      if ((linux_regs->eflags & VM_MASK) || (3 & linux_regs->xcs)) {
++              printk("ignoring non-kernel exception\n");
++              print_regs(&regs);
++              return (0);
++      }
++      /*
++       * If we're using eth mode, set the 'mode' in the netdevice.
++       */
++
++      __asm__("movl %%cr2,%0":"=r" (address));
++
++      if (kgdb_eth != -1) {
++              kgdb_eth_set_trapmode(1);
++      }
++
++      kgdb_local_irq_save(flags);
++
++      /* Get kgdb spinlock */
++
++      KGDB_SPIN_LOCK(&kgdb_spinlock);
++      rdtscll(kgdb_info.entry_tsc);
++      /*
++       * We depend on this spinlock and the NMI watch dog to control the
++       * other cpus.  They will arrive at "in_kgdb()" as a result of the
++       * NMI and will wait there for the following spin locks to be
++       * released.
++       */
++#ifdef CONFIG_SMP
++
++#if 0
++      if (cpu_callout_map & ~MAX_CPU_MASK) {
++              printk("kgdb : too many cpus, possibly not mapped"
++                     " in contiguous space, change MAX_NO_CPUS"
++                     " in kgdb_stub and make new kernel.\n"
++                     " cpu_callout_map is %lx\n", cpu_callout_map);
++              goto exit_just_unlock;
++      }
++#endif
++      if (spinlock_count == 1) {
++              int time, end_time, dum;
++              int i;
++              int cpu_logged_in[MAX_NO_CPUS] = {[0 ... MAX_NO_CPUS - 1] = (0)
++              };
++              if (remote_debug) {
++                      printk("kgdb : cpu %d entry, syncing others\n",
++                             smp_processor_id());
++              }
++              for (i = 0; i < MAX_NO_CPUS; i++) {
++                      /*
++                       * Use trylock as we may already hold the lock if
++                       * we are holding the cpu.  Net result is all
++                       * locked.
++                       */
++                      spin_trylock(&waitlocks[i]);
++              }
++              for (i = 0; i < MAX_NO_CPUS; i++)
++                      cpu_logged_in[i] = 0;
++              /*
++               * Wait for their arrival.  We know the watch dog is active if
++               * in_kgdb() has ever been called, as it is always called on a
++               * watchdog tick.
++               */
++              rdtsc(dum, time);
++              end_time = time + 2;    /* Note: we use the High order bits! */
++              i = 1;
++              if (num_online_cpus() > 1) {
++                      int me_in_kgdb = in_kgdb_entry_log[smp_processor_id()];
++                      smp_send_nmi_allbutself();
++                      while (i < num_online_cpus() && time != end_time) {
++                              int j;
++                              for (j = 0; j < MAX_NO_CPUS; j++) {
++                                      if (waiting_cpus[j].task &&
++                                          !cpu_logged_in[j]) {
++                                              i++;
++                                              cpu_logged_in[j] = 1;
++                                              if (remote_debug) {
++                                                      printk
++                                                          ("kgdb : cpu %d arrived at kgdb\n",
++                                                           j);
++                                              }
++                                              break;
++                                      } else if (!waiting_cpus[j].task &&
++                                                 !cpu_online(j)) {
++                                              waiting_cpus[j].task = NOCPU;
++                                              cpu_logged_in[j] = 1;
++                                              waiting_cpus[j].hold = 1;
++                                              break;
++                                      }
++                                      if (!waiting_cpus[j].task &&
++                                          in_kgdb_here_log[j]) {
++
++                                              int wait = 100000;
++                                              while (wait--) ;
++                                              if (!waiting_cpus[j].task &&
++                                                  in_kgdb_here_log[j]) {
++                                                      printk
++                                                          ("kgdb : cpu %d stall"
++                                                           " in in_kgdb\n",
++                                                           j);
++                                                      i++;
++                                                      cpu_logged_in[j] = 1;
++                                                      waiting_cpus[j].task =
++                                                          (struct task_struct
++                                                           *) 1;
++                                              }
++                                      }
++                              }
++
++                              if (in_kgdb_entry_log[smp_processor_id()] >
++                                  (me_in_kgdb + 10)) {
++                                      break;
++                              }
++
++                              rdtsc(dum, time);
++                      }
++                      if (i < num_online_cpus()) {
++                              printk
++                                  ("kgdb : time out, proceeding without sync\n");
++#if 0
++                              printk("kgdb : Waiting_cpus: 0 = %d, 1 = %d\n",
++                                     waiting_cpus[0].task != 0,
++                                     waiting_cpus[1].task != 0);
++                              printk("kgdb : Cpu_logged in: 0 = %d, 1 = %d\n",
++                                     cpu_logged_in[0], cpu_logged_in[1]);
++                              printk
++                                  ("kgdb : in_kgdb_here_log in: 0 = %d, 1 = %d\n",
++                                   in_kgdb_here_log[0] != 0,
++                                   in_kgdb_here_log[1] != 0);
++#endif
++                              entry_state = NO_SYNC;
++                      } else {
++#if 0
++                              int ent =
++                                  in_kgdb_entry_log[smp_processor_id()] -
++                                  me_in_kgdb;
++                              printk("kgdb : sync after %d entries\n", ent);
++#endif
++                      }
++              } else {
++                      if (remote_debug) {
++                              printk
++                                  ("kgdb : %d cpus, but watchdog not active\n"
++                                   "proceeding without locking down other cpus\n",
++                                   num_online_cpus());
++                              entry_state = NO_NMI;
++                      }
++              }
++      }
++#endif
++
++      if (remote_debug) {
++              printk("handle_exception(exceptionVector=%d, "
++                     "signo=%d, err_code=%d, linux_regs=%p)\n",
++                     exceptionVector, signo, err_code, linux_regs);
++              printk(" address: %lx\n", address);
++
++              if (debug_regs) {
++                      print_regs(&regs);
++                      show_trace(current, (unsigned long *)&regs);
++              }
++      }
++
++      /* Disable hardware debugging while we are in kgdb */
++      /* Get the debug register status register */
++/*                                   *INDENT-OFF*  */
++      __asm__("movl %0,%%db7"
++            : /* no output */
++            :"r"(0));
++
++      asm volatile ("movl %%db6, %0\n"
++                    :"=r" (hw_breakpoint_status)
++                    :);
++
++/*                                   *INDENT-ON*  */
++      switch (exceptionVector) {
++      case 0:         /* divide error */
++      case 1:         /* debug exception */
++      case 2:         /* NMI */
++      case 3:         /* breakpoint */
++      case 4:         /* overflow */
++      case 5:         /* bounds check */
++      case 6:         /* invalid opcode */
++      case 7:         /* device not available */
++      case 8:         /* double fault (errcode) */
++      case 10:                /* invalid TSS (errcode) */
++      case 12:                /* stack fault (errcode) */
++      case 16:                /* floating point error */
++      case 17:                /* alignment check (errcode) */
++      default:                /* any undocumented */
++              break;
++      case 11:                /* segment not present (errcode) */
++      case 13:                /* general protection (errcode) */
++      case 14:                /* page fault (special errcode) */
++      case 19:                /* cache flush denied */
++              if (mem_err_expected) {
++                      /*
++                       * This fault occured because of the
++                       * get_char or set_char routines.  These
++                       * two routines use either eax of edx to
++                       * indirectly reference the location in
++                       * memory that they are working with.
++                       * For a page fault, when we return the
++                       * instruction will be retried, so we
++                       * have to make sure that these
++                       * registers point to valid memory.
++                       */
++                      mem_err = 1;    /* set mem error flag */
++                      mem_err_expected = 0;
++                      mem_err_cnt++;  /* helps in debugging */
++                      /* make valid address */
++                      regs.eax = (long) &garbage_loc;
++                      /* make valid address */
++                      regs.edx = (long) &garbage_loc;
++                      if (remote_debug)
++                              printk("Return after memory error: "
++                                     "mem_err_cnt=%d\n", mem_err_cnt);
++                      if (debug_regs)
++                              print_regs(&regs);
++                      goto exit_kgdb;
++              }
++              break;
++      }
++      if (remote_debug)
++              printk("kgdb : entered kgdb on cpu %d\n", smp_processor_id());
++
++      gdb_i386vector = exceptionVector;
++      gdb_i386errcode = err_code;
++      kgdb_info.called_from = __builtin_return_address(0);
++#ifdef CONFIG_SMP
++      /*
++       * OK, we can now communicate, lets tell gdb about the sync.
++       * but only if we had a problem.
++       */
++      switch (entry_state) {
++      case NO_NMI:
++              to_gdb("NMI not active, other cpus not stopped\n");
++              break;
++      case NO_SYNC:
++              to_gdb("Some cpus not stopped, see 'kgdb_info' for details\n");
++      default:;
++      }
++
++#endif
++/*
++ * Set up the gdb function call area.
++ */
++      trap_cpu = smp_processor_id();
++      OLD_esp = NEW_esp = (int) (&linux_regs->esp);
++
++      IF_SMP(once_again:)
++          /* reply to host that an exception has occurred */
++          remcomOutBuffer[0] = 'S';
++      remcomOutBuffer[1] = hexchars[signo >> 4];
++      remcomOutBuffer[2] = hexchars[signo % 16];
++      remcomOutBuffer[3] = 0;
++
++      if (kgdb_eth_is_initializing) {
++              kgdb_eth_is_initializing = 0;
++      } else {
++              putpacket(remcomOutBuffer);
++      }
++
++      kgdb_eth_reply_arp();
++      while (1 == 1) {
++              error = 0;
++              remcomOutBuffer[0] = 0;
++              getpacket(remcomInBuffer);
++              switch (remcomInBuffer[0]) {
++              case '?':
++                      remcomOutBuffer[0] = 'S';
++                      remcomOutBuffer[1] = hexchars[signo >> 4];
++                      remcomOutBuffer[2] = hexchars[signo % 16];
++                      remcomOutBuffer[3] = 0;
++                      break;
++              case 'd':
++                      remote_debug = !(remote_debug); /* toggle debug flag */
++                      printk("Remote debug %s\n",
++                             remote_debug ? "on" : "off");
++                      break;
++              case 'g':       /* return the value of the CPU registers */
++                      get_gdb_regs(usethread, &regs, gdb_regs);
++                      mem2hex((char *) gdb_regs,
++                              remcomOutBuffer, NUMREGBYTES, 0);
++                      break;
++              case 'G':       /* set the value of the CPU registers - return OK */
++                      hex2mem(&remcomInBuffer[1],
++                              (char *) gdb_regs, NUMREGBYTES, 0);
++                      if (!usethread || usethread == current) {
++                              gdb_regs_to_regs(gdb_regs, &regs);
++                              strcpy(remcomOutBuffer, "OK");
++                      } else {
++                              strcpy(remcomOutBuffer, "E00");
++                      }
++                      break;
++
++              case 'P':{      /* set the value of a single CPU register -
++                                 return OK */
++                              /*
++                               * For some reason, gdb wants to talk about psudo
++                               * registers (greater than 15).  These may have
++                               * meaning for ptrace, but for us it is safe to
++                               * ignor them.  We do this by dumping them into
++                               * _GS which we also ignor, but do have memory for.
++                               */
++                              int regno;
++
++                              ptr = &remcomInBuffer[1];
++                              regs_to_gdb_regs(gdb_regs, &regs);
++                              if ((!usethread || usethread == current) &&
++                                  hexToInt(&ptr, &regno) &&
++                                  *ptr++ == '=' && (regno >= 0)) {
++                                      regno =
++                                          (regno >= NUMREGS ? _GS : regno);
++                                      hex2mem(ptr, (char *) &gdb_regs[regno],
++                                              4, 0);
++                                      gdb_regs_to_regs(gdb_regs, &regs);
++                                      strcpy(remcomOutBuffer, "OK");
++                                      break;
++                              }
++                              strcpy(remcomOutBuffer, "E01");
++                              break;
++                      }
++
++                      /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
++              case 'm':
++                      /* TRY TO READ %x,%x.  IF SUCCEED, SET PTR = 0 */
++                      ptr = &remcomInBuffer[1];
++                      if (hexToInt(&ptr, &addr) &&
++                          (*(ptr++) == ',') && (hexToInt(&ptr, &length))) {
++                              ptr = 0;
++                              /*
++                               * hex doubles the byte count
++                               */
++                              if (length > (BUFMAX / 2))
++                                      length = BUFMAX / 2;
++                              mem2hex((char *) addr,
++                                      remcomOutBuffer, length, 1);
++                              if (mem_err) {
++                                      strcpy(remcomOutBuffer, "E03");
++                                      debug_error("memory fault\n", NULL);
++                              }
++                      }
++
++                      if (ptr) {
++                              strcpy(remcomOutBuffer, "E01");
++                              debug_error
++                                  ("malformed read memory command: %s\n",
++                                   remcomInBuffer);
++                      }
++                      break;
++
++                      /* MAA..AA,LLLL:
++                         Write LLLL bytes at address AA.AA return OK */
++              case 'M':
++                      /* TRY TO READ '%x,%x:'.  IF SUCCEED, SET PTR = 0 */
++                      ptr = &remcomInBuffer[1];
++                      if (hexToInt(&ptr, &addr) &&
++                          (*(ptr++) == ',') &&
++                          (hexToInt(&ptr, &length)) && (*(ptr++) == ':')) {
++                              hex2mem(ptr, (char *) addr, length, 1);
++
++                              if (mem_err) {
++                                      strcpy(remcomOutBuffer, "E03");
++                                      debug_error("memory fault\n", NULL);
++                              } else {
++                                      strcpy(remcomOutBuffer, "OK");
++                              }
++
++                              ptr = 0;
++                      }
++                      if (ptr) {
++                              strcpy(remcomOutBuffer, "E02");
++                              debug_error
++                                  ("malformed write memory command: %s\n",
++                                   remcomInBuffer);
++                      }
++                      break;
++              case 'S':
++                      remcomInBuffer[0] = 's';
++              case 'C':
++                      /* Csig;AA..AA where ;AA..AA is optional
++                       * continue with signal
++                       * Since signals are meaning less to us, delete that
++                       * part and then fall into the 'c' code.
++                       */
++                      ptr = &remcomInBuffer[1];
++                      length = 2;
++                      while (*ptr && *ptr != ';') {
++                              length++;
++                              ptr++;
++                      }
++                      if (*ptr) {
++                              do {
++                                      ptr++;
++                                      *(ptr - length++) = *ptr;
++                              } while (*ptr);
++                      } else {
++                              remcomInBuffer[1] = 0;
++                      }
++
++                      /* cAA..AA  Continue at address AA..AA(optional) */
++                      /* sAA..AA  Step one instruction from AA..AA(optional) */
++                      /* D        detach, reply OK and then continue */
++              case 'c':
++              case 's':
++              case 'D':
++
++                      /* try to read optional parameter,
++                         pc unchanged if no parm */
++                      ptr = &remcomInBuffer[1];
++                      if (hexToInt(&ptr, &addr)) {
++                              if (remote_debug)
++                                      printk("Changing EIP to 0x%x\n", addr);
++
++                              regs.eip = addr;
++                      }
++
++                      newPC = regs.eip;
++
++                      if (kgdb_eth != -1) {
++                              kgdb_eth_set_trapmode(0);
++                      }
++
++                      /* clear the trace bit */
++                      regs.eflags &= 0xfffffeff;
++
++                      /* set the trace bit if we're stepping */
++                      if (remcomInBuffer[0] == 's')
++                              regs.eflags |= 0x100;
++
++                      /* detach is a friendly version of continue. Note that
++                         debugging is still enabled (e.g hit control C)
++                       */
++                      if (remcomInBuffer[0] == 'D') {
++                              strcpy(remcomOutBuffer, "OK");
++                              putpacket(remcomOutBuffer);
++                      }
++
++                      if (remote_debug) {
++                              printk("Resuming execution\n");
++                              print_regs(&regs);
++                      }
++                      asm volatile ("movl %%db6, %0\n":"=r" (dr6)
++                                    :);
++                      if (!(dr6 & 0x4000)) {
++                              for (breakno = 0; breakno < 4; ++breakno) {
++                                      if (dr6 & (1 << breakno) &&
++                                          (breakinfo[breakno].type == 0)) {
++                                              /* Set restore flag */
++                                              regs.eflags |= 0x10000;
++                                              break;
++                                      }
++                              }
++                      }
++                      correct_hw_break();
++                      asm volatile ("movl %0, %%db6\n"::"r" (0));
++                      goto exit_kgdb;
++
++                      /* kill the program */
++              case 'k':       /* do nothing */
++                      break;
++
++                      /* query */
++              case 'q':
++                      nothreads = 0;
++                      switch (remcomInBuffer[1]) {
++                      case 'f':
++                              threadid = 1;
++                              thread_list = 2;
++                              thread_list_start = (usethread ? : current);
++                      case 's':
++                              if (!cmp_str(&remcomInBuffer[2],
++                                           "ThreadInfo", 10))
++                                      break;
++
++                              remcomOutBuffer[nothreads++] = 'm';
++                              for (; threadid < PID_MAX + MAX_NO_CPUS;
++                                   threadid++) {
++                                      thread = getthread(threadid);
++                                      if (thread) {
++                                              nothreads += int_to_hex_v(
++                                                      &remcomOutBuffer[
++                                                              nothreads],
++                                                      threadid);
++                                              if (thread_min > threadid)
++                                                      thread_min = threadid;
++                                              remcomOutBuffer[
++                                                      nothreads] = ',';
++                                              nothreads++;
++                                              if (nothreads > BUFMAX - 10)
++                                                      break;
++                                      }
++                              }
++                              if (remcomOutBuffer[nothreads - 1] == 'm') {
++                                      remcomOutBuffer[nothreads - 1] = 'l';
++                              } else {
++                                      nothreads--;
++                              }
++                              remcomOutBuffer[nothreads] = 0;
++                              break;
++
++#ifdef old_thread_list /* Old thread info request */
++                      case 'L':
++                              /* List threads */
++                              thread_list = 2;
++                              thread_list_start = (usethread ? : current);
++                              unpack_byte(remcomInBuffer + 3, &maxthreads);
++                              unpack_threadid(remcomInBuffer + 5, &thref);
++                              do {
++                                      int buf_thread_limit =
++                                          (BUFMAX - 22) / BUF_THREAD_ID_SIZE;
++                                      if (maxthreads > buf_thread_limit) {
++                                              maxthreads = buf_thread_limit;
++                                      }
++                              } while (0);
++                              remcomOutBuffer[0] = 'q';
++                              remcomOutBuffer[1] = 'M';
++                              remcomOutBuffer[4] = '0';
++                              pack_threadid(remcomOutBuffer + 5, &thref);
++
++                              threadid = threadref_to_int(&thref);
++                              for (nothreads = 0;
++                                   nothreads < maxthreads &&
++                                   threadid < PID_MAX + MAX_NO_CPUS;
++                                   threadid++) {
++                                      thread = getthread(threadid);
++                                      if (thread) {
++                                              int_to_threadref(&thref,
++                                                               threadid);
++                                              pack_threadid(remcomOutBuffer +
++                                                            21 +
++                                                            nothreads * 16,
++                                                            &thref);
++                                              nothreads++;
++                                              if (thread_min > threadid)
++                                                      thread_min = threadid;
++                                      }
++                              }
++
++                              if (threadid == PID_MAX + MAX_NO_CPUS) {
++                                      remcomOutBuffer[4] = '1';
++                              }
++                              pack_hex_byte(remcomOutBuffer + 2, nothreads);
++                              remcomOutBuffer[21 + nothreads * 16] = '\0';
++                              break;
++#endif
++                      case 'C':
++                              /* Current thread id */
++                              remcomOutBuffer[0] = 'Q';
++                              remcomOutBuffer[1] = 'C';
++                              threadid = current->pid;
++                              if (!threadid) {
++                                      /*
++                                       * idle thread
++                                       */
++                                      for (threadid = PID_MAX;
++                                           threadid < PID_MAX + MAX_NO_CPUS;
++                                           threadid++) {
++                                              if (current ==
++                                                  idle_task(threadid -
++                                                            PID_MAX))
++                                                      break;
++                                      }
++                              }
++                              int_to_threadref(&thref, threadid);
++                              pack_threadid(remcomOutBuffer + 2, &thref);
++                              remcomOutBuffer[18] = '\0';
++                              break;
++
++                      case 'E':
++                              /* Print exception info */
++                              printexceptioninfo(exceptionVector,
++                                                 err_code, remcomOutBuffer);
++                              break;
++                      case 'T':{
++                              char * nptr;
++                              /* Thread extra info */
++                              if (!cmp_str(&remcomInBuffer[2],
++                                          "hreadExtraInfo,", 15)) {
++                                      break;
++                              }
++                              ptr = &remcomInBuffer[17];
++                              hexToInt(&ptr, &threadid);
++                              thread = getthread(threadid);
++                              nptr = &thread->comm[0];
++                              length = 0;
++                              ptr = &remcomOutBuffer[0];
++                              do {
++                                      length++;
++                                      ptr = pack_hex_byte(ptr, *nptr++);
++                               } while (*nptr && length < 16);
++                              /*
++                               * would like that 16 to be the size of
++                               * task_struct.comm but don't know the
++                               * syntax..
++                               */
++                              *ptr = 0;
++                      }
++                      }
++                      break;
++
++                      /* task related */
++              case 'H':
++                      switch (remcomInBuffer[1]) {
++                      case 'g':
++                              ptr = &remcomInBuffer[2];
++                              hexToInt(&ptr, &threadid);
++                              thread = getthread(threadid);
++                              if (!thread) {
++                                      remcomOutBuffer[0] = 'E';
++                                      remcomOutBuffer[1] = '\0';
++                                      break;
++                              }
++                              /*
++                               * Just in case I forget what this is all about,
++                               * the "thread info" command to gdb causes it
++                               * to ask for a thread list.  It then switches
++                               * to each thread and asks for the registers.
++                               * For this (and only this) usage, we want to
++                               * fudge the registers of tasks not on the run
++                               * list (i.e. waiting) to show the routine that
++                               * called schedule. Also, gdb, is a minimalist
++                               * in that if the current thread is the last
++                               * it will not re-read the info when done.
++                               * This means that in this case we must show
++                               * the real registers. So here is how we do it:
++                               * Each entry we keep track of the min
++                               * thread in the list (the last that gdb will)
++                               * get info for.  We also keep track of the
++                               * starting thread.
++                               * "thread_list" is cleared when switching back
++                               * to the min thread if it is was current, or
++                               * if it was not current, thread_list is set
++                               * to 1.  When the switch to current comes,
++                               * if thread_list is 1, clear it, else do
++                               * nothing.
++                               */
++                              usethread = thread;
++                              if ((thread_list == 1) &&
++                                  (thread == thread_list_start)) {
++                                      thread_list = 0;
++                              }
++                              if (thread_list && (threadid == thread_min)) {
++                                      if (thread == thread_list_start) {
++                                              thread_list = 0;
++                                      } else {
++                                              thread_list = 1;
++                                      }
++                              }
++                              /* follow through */
++                      case 'c':
++                              remcomOutBuffer[0] = 'O';
++                              remcomOutBuffer[1] = 'K';
++                              remcomOutBuffer[2] = '\0';
++                              break;
++                      }
++                      break;
++
++                      /* Query thread status */
++              case 'T':
++                      ptr = &remcomInBuffer[1];
++                      hexToInt(&ptr, &threadid);
++                      thread = getthread(threadid);
++                      if (thread) {
++                              remcomOutBuffer[0] = 'O';
++                              remcomOutBuffer[1] = 'K';
++                              remcomOutBuffer[2] = '\0';
++                              if (thread_min > threadid)
++                                      thread_min = threadid;
++                      } else {
++                              remcomOutBuffer[0] = 'E';
++                              remcomOutBuffer[1] = '\0';
++                      }
++                      break;
++
++              case 'Y': /* set up a hardware breakpoint */
++                      ptr = &remcomInBuffer[1];
++                      hexToInt(&ptr, &breakno);
++                      ptr++;
++                      hexToInt(&ptr, &breaktype);
++                      ptr++;
++                      hexToInt(&ptr, &length);
++                      ptr++;
++                      hexToInt(&ptr, &addr);
++                      if (set_hw_break(breakno & 0x3,
++                                       breaktype & 0x3,
++                                       length & 0x3, addr) == 0) {
++                              strcpy(remcomOutBuffer, "OK");
++                      } else {
++                              strcpy(remcomOutBuffer, "ERROR");
++                      }
++                      break;
++
++                      /* Remove hardware breakpoint */
++              case 'y':
++                      ptr = &remcomInBuffer[1];
++                      hexToInt(&ptr, &breakno);
++                      if (remove_hw_break(breakno & 0x3) == 0) {
++                              strcpy(remcomOutBuffer, "OK");
++                      } else {
++                              strcpy(remcomOutBuffer, "ERROR");
++                      }
++                      break;
++
++              case 'r':       /* reboot */
++                      strcpy(remcomOutBuffer, "OK");
++                      putpacket(remcomOutBuffer);
++                      /*to_gdb("Rebooting\n"); */
++                      /* triplefault   no return from here */
++                      {
++                              static long no_idt[2];
++                              __asm__ __volatile__("lidt %0"::"m"(no_idt[0]));
++                              BREAKPOINT;
++                      }
++
++              }               /* switch */
++
++              /* reply to the request */
++              putpacket(remcomOutBuffer);
++      }                       /* while(1==1) */
++      /*
++       *  reached by goto only.
++       */
++      exit_kgdb:
++      /*
++       * Here is where we set up to trap a gdb function call.  NEW_esp
++       * will be changed if we are trying to do this.  We handle both
++       * adding and subtracting, thus allowing gdb to put grung on
++       * the stack which it removes later.
++       */
++      if (NEW_esp != OLD_esp) {
++              int *ptr = END_OF_LOOKASIDE;
++              if (NEW_esp < OLD_esp)
++                      ptr -= (OLD_esp - NEW_esp) / sizeof (int);
++              *--ptr = linux_regs->eflags;
++              *--ptr = linux_regs->xcs;
++              *--ptr = linux_regs->eip;
++              *--ptr = linux_regs->ecx;
++              *--ptr = linux_regs->ebx;
++              *--ptr = linux_regs->eax;
++              linux_regs->ecx = NEW_esp - (sizeof (int) * 6);
++              linux_regs->ebx = (unsigned int) END_OF_LOOKASIDE;
++              if (NEW_esp < OLD_esp) {
++                      linux_regs->eip = (unsigned int) fn_call_stub;
++              } else {
++                      linux_regs->eip = (unsigned int) fn_rtn_stub;
++                      linux_regs->eax = NEW_esp;
++              }
++              linux_regs->eflags &= ~(IF_BIT | TF_BIT);
++      }
++#ifdef CONFIG_SMP
++      /*
++       * Release gdb wait locks
++       * Sanity check time.  Must have at least one cpu to run.  Also single
++       * step must not be done if the current cpu is on hold.
++       */
++      if (spinlock_count == 1) {
++              int ss_hold = (regs.eflags & 0x100) && kgdb_info.hold_on_sstep;
++              int cpu_avail = 0;
++              int i;
++
++              for (i = 0; i < MAX_NO_CPUS; i++) {
++                      if (!cpu_online(i))
++                              break;
++                      if (!hold_cpu(i)) {
++                              cpu_avail = 1;
++                      }
++              }
++              /*
++               * Early in the bring up there will be NO cpus on line...
++               */
++              if (!cpu_avail && !cpus_empty(cpu_online_map)) {
++                      to_gdb("No cpus unblocked, see 'kgdb_info.hold_cpu'\n");
++                      goto once_again;
++              }
++              if (hold_cpu(smp_processor_id()) && (regs.eflags & 0x100)) {
++                      to_gdb
++                          ("Current cpu must be unblocked to single step\n");
++                      goto once_again;
++              }
++              if (!(ss_hold)) {
++                      int i;
++                      for (i = 0; i < MAX_NO_CPUS; i++) {
++                              if (!hold_cpu(i)) {
++                                      spin_unlock(&waitlocks[i]);
++                              }
++                      }
++              } else {
++                      spin_unlock(&waitlocks[smp_processor_id()]);
++              }
++              /* Release kgdb spinlock */
++              KGDB_SPIN_UNLOCK(&kgdb_spinlock);
++              /*
++               * If this cpu is on hold, this is where we
++               * do it.  Note, the NMI will pull us out of here,
++               * but will return as the above lock is not held.
++               * We will stay here till another cpu releases the lock for us.
++               */
++              spin_unlock_wait(waitlocks + smp_processor_id());
++              kgdb_local_irq_restore(flags);
++              return (0);
++      }
++#if 0
++exit_just_unlock:
++#endif
++#endif
++      /* Release kgdb spinlock */
++      KGDB_SPIN_UNLOCK(&kgdb_spinlock);
++      kgdb_local_irq_restore(flags);
++      return (0);
++}
++
++/* this function is used to set up exception handlers for tracing and
++ * breakpoints.
++ * This function is not needed as the above line does all that is needed.
++ * We leave it for backward compatitability...
++ */
++void
++set_debug_traps(void)
++{
++      /*
++       * linux_debug_hook is defined in traps.c.  We store a pointer
++       * to our own exception handler into it.
++
++       * But really folks, every hear of labeled common, an old Fortran
++       * concept.  Lots of folks can reference it and it is define if
++       * anyone does.  Only one can initialize it at link time.  We do
++       * this with the hook.  See the statement above.  No need for any
++       * executable code and it is ready as soon as the kernel is
++       * loaded.  Very desirable in kernel debugging.
++
++       linux_debug_hook = handle_exception ;
++       */
++
++      /* In case GDB is started before us, ack any packets (presumably
++         "$?#xx") sitting there.
++         putDebugChar ('+');
++
++         initialized = 1;
++       */
++}
++
++/* This function will generate a breakpoint exception.        It is used at the
++   beginning of a program to sync up with a debugger and can be used
++   otherwise as a quick means to stop program execution and "break" into
++   the debugger. */
++/* But really, just use the BREAKPOINT macro.  We will handle the int stuff
++ */
++
++#ifdef later
++/*
++ * possibly we should not go thru the traps.c code at all?  Someday.
++ */
++void
++do_kgdb_int3(struct pt_regs *regs, long error_code)
++{
++      kgdb_handle_exception(3, 5, error_code, regs);
++      return;
++}
++#endif
++#undef regs
++#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS
++asmlinkage void
++bad_sys_call_exit(int stuff)
++{
++      struct pt_regs *regs = (struct pt_regs *) &stuff;
++      printk("Sys call %d return with %x preempt_count\n",
++             (int) regs->orig_eax, preempt_count());
++}
++#endif
++#ifdef CONFIG_STACK_OVERFLOW_TEST
++#include <asm/kgdb.h>
++asmlinkage void
++stack_overflow(void)
++{
++#ifdef BREAKPOINT
++      BREAKPOINT;
++#else
++      printk("Kernel stack overflow, looping forever\n");
++#endif
++      while (1) {
++      }
++}
++#endif
++
++#if defined(CONFIG_SMP) || defined(CONFIG_KGDB_CONSOLE)
++char gdbconbuf[BUFMAX];
++
++static void
++kgdb_gdb_message(const char *s, unsigned count)
++{
++      int i;
++      int wcount;
++      char *bufptr;
++      /*
++       * This takes care of NMI while spining out chars to gdb
++       */
++      IF_SMP(in_kgdb_console = 1);
++      gdbconbuf[0] = 'O';
++      bufptr = gdbconbuf + 1;
++      while (count > 0) {
++              if ((count << 1) > (BUFMAX - 2)) {
++                      wcount = (BUFMAX - 2) >> 1;
++              } else {
++                      wcount = count;
++              }
++              count -= wcount;
++              for (i = 0; i < wcount; i++) {
++                      bufptr = pack_hex_byte(bufptr, s[i]);
++              }
++              *bufptr = '\0';
++              s += wcount;
++
++              putpacket(gdbconbuf);
++
++      }
++      IF_SMP(in_kgdb_console = 0);
++}
++#endif
++#ifdef CONFIG_SMP
++static void
++to_gdb(const char *s)
++{
++      int count = 0;
++      while (s[count] && (count++ < BUFMAX)) ;
++      kgdb_gdb_message(s, count);
++}
++#endif
++#ifdef CONFIG_KGDB_CONSOLE
++#include <linux/console.h>
++#include <linux/init.h>
++#include <linux/fs.h>
++#include <asm/uaccess.h>
++#include <asm/semaphore.h>
++
++void
++kgdb_console_write(struct console *co, const char *s, unsigned count)
++{
++
++      if (gdb_i386vector == -1) {
++              /*
++               * We have not yet talked to gdb.  What to do...
++               * lets break, on continue we can do the write.
++               * But first tell him whats up. Uh, well no can do,
++               * as this IS the console.  Oh well...
++               * We do need to wait or the messages will be lost.
++               * Other option would be to tell the above code to
++               * ignore this breakpoint and do an auto return,
++               * but that might confuse gdb.  Also this happens
++               * early enough in boot up that we don't have the traps
++               * set up yet, so...
++               */
++              breakpoint();
++      }
++      kgdb_gdb_message(s, count);
++}
++
++/*
++ * ------------------------------------------------------------
++ * Serial KGDB driver
++ * ------------------------------------------------------------
++ */
++
++static struct console kgdbcons = {
++      name:"kgdb",
++      write:kgdb_console_write,
++#ifdef CONFIG_KGDB_USER_CONSOLE
++      device:kgdb_console_device,
++#endif
++      flags:CON_PRINTBUFFER | CON_ENABLED,
++      index:-1,
++};
++
++/*
++ * The trick here is that this file gets linked before printk.o
++ * That means we get to peer at the console info in the command
++ * line before it does.        If we are up, we register, otherwise,
++ * do nothing.        By returning 0, we allow printk to look also.
++ */
++static int kgdb_console_enabled;
++
++int __init
++kgdb_console_init(char *str)
++{
++      if ((strncmp(str, "kgdb", 4) == 0) || (strncmp(str, "gdb", 3) == 0)) {
++              register_console(&kgdbcons);
++              kgdb_console_enabled = 1;
++      }
++      return 0;               /* let others look at the string */
++}
++
++__setup("console=", kgdb_console_init);
++
++#ifdef CONFIG_KGDB_USER_CONSOLE
++static kdev_t kgdb_console_device(struct console *c);
++/* This stuff sort of works, but it knocks out telnet devices
++ * we are leaving it here in case we (or you) find time to figure it out
++ * better..
++ */
++
++/*
++ * We need a real char device as well for when the console is opened for user
++ * space activities.
++ */
++
++static int
++kgdb_consdev_open(struct inode *inode, struct file *file)
++{
++      return 0;
++}
++
++static ssize_t
++kgdb_consdev_write(struct file *file, const char *buf,
++                 size_t count, loff_t * ppos)
++{
++      int size, ret = 0;
++      static char kbuf[128];
++      static DECLARE_MUTEX(sem);
++
++      /* We are not reentrant... */
++      if (down_interruptible(&sem))
++              return -ERESTARTSYS;
++
++      while (count > 0) {
++              /* need to copy the data from user space */
++              size = count;
++              if (size > sizeof (kbuf))
++                      size = sizeof (kbuf);
++              if (copy_from_user(kbuf, buf, size)) {
++                      ret = -EFAULT;
++                      break;;
++              }
++              kgdb_console_write(&kgdbcons, kbuf, size);
++              count -= size;
++              ret += size;
++              buf += size;
++      }
++
++      up(&sem);
++
++      return ret;
++}
++
++struct file_operations kgdb_consdev_fops = {
++      open:kgdb_consdev_open,
++      write:kgdb_consdev_write
++};
++static kdev_t
++kgdb_console_device(struct console *c)
++{
++      return MKDEV(TTYAUX_MAJOR, 1);
++}
++
++/*
++ * This routine gets called from the serial stub in the i386/lib
++ * This is so it is done late in bring up (just before the console open).
++ */
++void
++kgdb_console_finit(void)
++{
++      if (kgdb_console_enabled) {
++              char *cptr = cdevname(MKDEV(TTYAUX_MAJOR, 1));
++              char *cp = cptr;
++              while (*cptr && *cptr != '(')
++                      cptr++;
++              *cptr = 0;
++              unregister_chrdev(TTYAUX_MAJOR, cp);
++              register_chrdev(TTYAUX_MAJOR, "kgdb", &kgdb_consdev_fops);
++      }
++}
++#endif
++#endif
++#ifdef CONFIG_KGDB_TS
++#include <asm/msr.h>          /* time stamp code */
++#include <asm/hardirq.h>      /* in_interrupt */
++#ifdef CONFIG_KGDB_TS_64
++#define DATA_POINTS 64
++#endif
++#ifdef CONFIG_KGDB_TS_128
++#define DATA_POINTS 128
++#endif
++#ifdef CONFIG_KGDB_TS_256
++#define DATA_POINTS 256
++#endif
++#ifdef CONFIG_KGDB_TS_512
++#define DATA_POINTS 512
++#endif
++#ifdef CONFIG_KGDB_TS_1024
++#define DATA_POINTS 1024
++#endif
++#ifndef DATA_POINTS
++#define DATA_POINTS 128               /* must be a power of two */
++#endif
++#define INDEX_MASK (DATA_POINTS - 1)
++#if (INDEX_MASK & DATA_POINTS)
++#error "CONFIG_KGDB_TS_COUNT must be a power of 2"
++#endif
++struct kgdb_and_then_struct {
++#ifdef CONFIG_SMP
++      int on_cpu;
++#endif
++      struct task_struct *task;
++      long long at_time;
++      int from_ln;
++      char *in_src;
++      void *from;
++      int *with_shpf;
++      int data0;
++      int data1;
++};
++struct kgdb_and_then_struct2 {
++#ifdef CONFIG_SMP
++      int on_cpu;
++#endif
++      struct task_struct *task;
++      long long at_time;
++      int from_ln;
++      char *in_src;
++      void *from;
++      int *with_shpf;
++      struct task_struct *t1;
++      struct task_struct *t2;
++};
++struct kgdb_and_then_struct kgdb_data[DATA_POINTS];
++
++struct kgdb_and_then_struct *kgdb_and_then = &kgdb_data[0];
++int kgdb_and_then_count;
++
++void
++kgdb_tstamp(int line, char *source, int data0, int data1)
++{
++      static spinlock_t ts_spin = SPIN_LOCK_UNLOCKED;
++      int flags;
++      kgdb_local_irq_save(flags);
++      spin_lock(&ts_spin);
++      rdtscll(kgdb_and_then->at_time);
++#ifdef CONFIG_SMP
++      kgdb_and_then->on_cpu = smp_processor_id();
++#endif
++      kgdb_and_then->task = current;
++      kgdb_and_then->from_ln = line;
++      kgdb_and_then->in_src = source;
++      kgdb_and_then->from = __builtin_return_address(0);
++      kgdb_and_then->with_shpf = (int *) (((flags & IF_BIT) >> 9) |
++                                          (preempt_count() << 8));
++      kgdb_and_then->data0 = data0;
++      kgdb_and_then->data1 = data1;
++      kgdb_and_then = &kgdb_data[++kgdb_and_then_count & INDEX_MASK];
++      spin_unlock(&ts_spin);
++      kgdb_local_irq_restore(flags);
++#ifdef CONFIG_PREEMPT
++
++#endif
++      return;
++}
++#endif
++typedef int gdb_debug_hook(int exceptionVector,
++                         int signo, int err_code, struct pt_regs *linux_regs);
++gdb_debug_hook *linux_debug_hook = &kgdb_handle_exception;    /* histerical reasons... */
++
++static int __init kgdb_opt_kgdbeth(char *str)
++{
++      kgdb_eth = simple_strtoul(str, NULL, 10);
++      return 1;
++}
++
++static int __init kgdb_opt_kgdbeth_remoteip(char *str)
++{
++      kgdb_remoteip = in_aton(str);
++      return 1;
++}
++
++static int __init kgdb_opt_kgdbeth_listenport(char *str)
++{
++      kgdb_listenport = simple_strtoul(str, NULL, 10);
++      kgdb_sendport = kgdb_listenport - 1;
++      return 1;
++}
++
++static int __init parse_hw_addr(char *str, unsigned char *addr)
++{
++      int  i;
++      char *p;
++
++      p = str;
++      i = 0;
++      while(1)
++      {
++              unsigned int c;
++
++              sscanf(p, "%x:", &c);
++              addr[i++] = c;
++              while((*p != 0) && (*p != ':')) {
++                      p++;
++              }
++              if (*p == 0) {
++                      break;
++              }
++              p++;
++      }
++
++      return 1;
++}
++
++static int __init kgdb_opt_kgdbeth_remotemac(char *str)
++{
++      return parse_hw_addr(str, kgdb_remotemac);
++}
++static int __init kgdb_opt_kgdbeth_localmac(char *str)
++{
++      return parse_hw_addr(str, kgdb_localmac);
++}
++
++
++__setup("gdbeth=", kgdb_opt_kgdbeth);
++__setup("gdbeth_remoteip=", kgdb_opt_kgdbeth_remoteip);
++__setup("gdbeth_listenport=", kgdb_opt_kgdbeth_listenport);
++__setup("gdbeth_remotemac=", kgdb_opt_kgdbeth_remotemac);
++__setup("gdbeth_localmac=", kgdb_opt_kgdbeth_localmac);
++
+--- linux-2.6.0-test6/arch/i386/kernel/ldt.c   2003-08-22 19:23:40.000000000 -0700
++++ 25/arch/i386/kernel/ldt.c  2003-10-05 00:36:48.000000000 -0700
+@@ -2,7 +2,7 @@
+  * linux/kernel/ldt.c
+  *
+  * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds
+- * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
++ * Copyright (C) 1999, 2003 Ingo Molnar <mingo@redhat.com>
+  */
+ #include <linux/errno.h>
+@@ -18,6 +18,8 @@
+ #include <asm/system.h>
+ #include <asm/ldt.h>
+ #include <asm/desc.h>
++#include <linux/highmem.h>
++#include <asm/atomic_kmap.h>
+ #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
+ static void flush_ldt(void *null)
+@@ -29,34 +31,31 @@ static void flush_ldt(void *null)
+ static int alloc_ldt(mm_context_t *pc, int mincount, int reload)
+ {
+-      void *oldldt;
+-      void *newldt;
+-      int oldsize;
++      int oldsize, newsize, i;
+       if (mincount <= pc->size)
+               return 0;
++      /*
++       * LDT got larger - reallocate if necessary.
++       */
+       oldsize = pc->size;
+       mincount = (mincount+511)&(~511);
+-      if (mincount*LDT_ENTRY_SIZE > PAGE_SIZE)
+-              newldt = vmalloc(mincount*LDT_ENTRY_SIZE);
+-      else
+-              newldt = kmalloc(mincount*LDT_ENTRY_SIZE, GFP_KERNEL);
+-
+-      if (!newldt)
+-              return -ENOMEM;
+-
+-      if (oldsize)
+-              memcpy(newldt, pc->ldt, oldsize*LDT_ENTRY_SIZE);
+-      oldldt = pc->ldt;
+-      memset(newldt+oldsize*LDT_ENTRY_SIZE, 0, (mincount-oldsize)*LDT_ENTRY_SIZE);
+-      pc->ldt = newldt;
+-      wmb();
++      newsize = mincount*LDT_ENTRY_SIZE;
++      for (i = 0; i < newsize; i += PAGE_SIZE) {
++              int nr = i/PAGE_SIZE;
++              BUG_ON(i >= 64*1024);
++              if (!pc->ldt_pages[nr]) {
++                      pc->ldt_pages[nr] = alloc_page(GFP_HIGHUSER);
++                      if (!pc->ldt_pages[nr])
++                              return -ENOMEM;
++                      clear_highpage(pc->ldt_pages[nr]);
++              }
++      }
+       pc->size = mincount;
+-      wmb();
+-
+       if (reload) {
+ #ifdef CONFIG_SMP
+               cpumask_t mask;
++
+               preempt_disable();
+               load_LDT(pc);
+               mask = cpumask_of_cpu(smp_processor_id());
+@@ -67,21 +66,20 @@ static int alloc_ldt(mm_context_t *pc, i
+               load_LDT(pc);
+ #endif
+       }
+-      if (oldsize) {
+-              if (oldsize*LDT_ENTRY_SIZE > PAGE_SIZE)
+-                      vfree(oldldt);
+-              else
+-                      kfree(oldldt);
+-      }
+       return 0;
+ }
+ static inline int copy_ldt(mm_context_t *new, mm_context_t *old)
+ {
+-      int err = alloc_ldt(new, old->size, 0);
+-      if (err < 0)
++      int i, err, size = old->size, nr_pages = (size*LDT_ENTRY_SIZE + PAGE_SIZE-1)/PAGE_SIZE;
++
++      err = alloc_ldt(new, size, 0);
++      if (err < 0) {
++              new->size = 0;
+               return err;
+-      memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE);
++      }
++      for (i = 0; i < nr_pages; i++)
++              copy_user_highpage(new->ldt_pages[i], old->ldt_pages[i], 0);
+       return 0;
+ }
+@@ -96,6 +94,7 @@ int init_new_context(struct task_struct 
+       init_MUTEX(&mm->context.sem);
+       mm->context.size = 0;
++      memset(mm->context.ldt_pages, 0, sizeof(struct page *) * MAX_LDT_PAGES);
+       old_mm = current->mm;
+       if (old_mm && old_mm->context.size > 0) {
+               down(&old_mm->context.sem);
+@@ -107,23 +106,21 @@ int init_new_context(struct task_struct 
+ /*
+  * No need to lock the MM as we are the last user
++ * Do not touch the ldt register, we are already
++ * in the next thread.
+  */
+ void destroy_context(struct mm_struct *mm)
+ {
+-      if (mm->context.size) {
+-              if (mm == current->active_mm)
+-                      clear_LDT();
+-              if (mm->context.size*LDT_ENTRY_SIZE > PAGE_SIZE)
+-                      vfree(mm->context.ldt);
+-              else
+-                      kfree(mm->context.ldt);
+-              mm->context.size = 0;
+-      }
++      int i, nr_pages = (mm->context.size*LDT_ENTRY_SIZE + PAGE_SIZE-1) / PAGE_SIZE;
++
++      for (i = 0; i < nr_pages; i++)
++              __free_page(mm->context.ldt_pages[i]);
++      mm->context.size = 0;
+ }
+ static int read_ldt(void __user * ptr, unsigned long bytecount)
+ {
+-      int err;
++      int err, i;
+       unsigned long size;
+       struct mm_struct * mm = current->mm;
+@@ -138,8 +135,25 @@ static int read_ldt(void __user * ptr, u
+               size = bytecount;
+       err = 0;
+-      if (copy_to_user(ptr, mm->context.ldt, size))
+-              err = -EFAULT;
++      /*
++       * This is necessary just in case we got here straight from a
++       * context-switch where the ptes were set but no tlb flush
++       * was done yet. We rather avoid doing a TLB flush in the
++       * context-switch path and do it here instead.
++       */
++      __flush_tlb_global();
++
++      for (i = 0; i < size; i += PAGE_SIZE) {
++              int nr = i / PAGE_SIZE, bytes;
++              char *kaddr = kmap(mm->context.ldt_pages[nr]);
++
++              bytes = size - i;
++              if (bytes > PAGE_SIZE)
++                      bytes = PAGE_SIZE;
++              if (copy_to_user(ptr + i, kaddr, size - i))
++                      err = -EFAULT;
++              kunmap(mm->context.ldt_pages[nr]);
++      }
+       up(&mm->context.sem);
+       if (err < 0)
+               return err;
+@@ -158,7 +172,7 @@ static int read_default_ldt(void __user 
+       err = 0;
+       address = &default_ldt[0];
+-      size = 5*sizeof(struct desc_struct);
++      size = 5*LDT_ENTRY_SIZE;
+       if (size > bytecount)
+               size = bytecount;
+@@ -200,7 +214,15 @@ static int write_ldt(void __user * ptr, 
+                       goto out_unlock;
+       }
+-      lp = (__u32 *) ((ldt_info.entry_number << 3) + (char *) mm->context.ldt);
++      /*
++       * No rescheduling allowed from this point to the install.
++       *
++       * We do a TLB flush for the same reason as in the read_ldt() path.
++       */
++      preempt_disable();
++      __flush_tlb_global();
++      lp = (__u32 *) ((ldt_info.entry_number << 3) +
++                      (char *) __kmap_atomic_vaddr(KM_LDT_PAGE0));
+       /* Allow LDTs to be cleared by the user. */
+       if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
+@@ -221,6 +243,7 @@ install:
+       *lp     = entry_1;
+       *(lp+1) = entry_2;
+       error = 0;
++      preempt_enable();
+ out_unlock:
+       up(&mm->context.sem);
+@@ -248,3 +271,26 @@ asmlinkage int sys_modify_ldt(int func, 
+       }
+       return ret;
+ }
++
++/*
++ * load one particular LDT into the current CPU
++ */
++void load_LDT_nolock(mm_context_t *pc, int cpu)
++{
++      struct page **pages = pc->ldt_pages;
++      int count = pc->size;
++      int nr_pages, i;
++
++      if (likely(!count)) {
++              pages = &default_ldt_page;
++              count = 5;
++      }
++              nr_pages = (count*LDT_ENTRY_SIZE + PAGE_SIZE-1) / PAGE_SIZE;
++
++      for (i = 0; i < nr_pages; i++) {
++              __kunmap_atomic_type(KM_LDT_PAGE0 - i);
++              __kmap_atomic(pages[i], KM_LDT_PAGE0 - i);
++      }
++      set_ldt_desc(cpu, (void *)__kmap_atomic_vaddr(KM_LDT_PAGE0), count);
++      load_LDT_desc();
++}
+--- linux-2.6.0-test6/arch/i386/kernel/Makefile        2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/i386/kernel/Makefile       2003-10-05 00:36:48.000000000 -0700
+@@ -7,13 +7,14 @@ extra-y := head.o init_task.o vmlinux.ld
+ obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \
+               ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \
+               pci-dma.o i386_ksyms.o i387.o dmi_scan.o bootflag.o \
+-              doublefault.o
++              doublefault.o efi.o efi_stub.o entry_trampoline.o
+ obj-y                         += cpu/
+ obj-y                         += timers/
+ obj-$(CONFIG_ACPI_BOOT)               += acpi/
+ obj-$(CONFIG_X86_BIOS_REBOOT) += reboot.o
+ obj-$(CONFIG_MCA)             += mca.o
++obj-$(CONFIG_KGDB)            += kgdb_stub.o
+ obj-$(CONFIG_X86_MSR)         += msr.o
+ obj-$(CONFIG_X86_CPUID)               += cpuid.o
+ obj-$(CONFIG_MICROCODE)               += microcode.o
+--- linux-2.6.0-test6/arch/i386/kernel/mca.c   2003-08-22 19:23:40.000000000 -0700
++++ 25/arch/i386/kernel/mca.c  2003-10-05 00:36:10.000000000 -0700
+@@ -132,7 +132,9 @@ struct resource mca_standard_resources[]
+ #define MCA_STANDARD_RESOURCES        (sizeof(mca_standard_resources)/sizeof(struct resource))
+ /**
+- *    mca_read_pos - read the POS registers into a memory buffer
++ *    mca_read_and_store_pos - read the POS registers into a memory buffer
++ *      @pos: a char pointer to 8 bytes, contains the POS register value on
++ *            successful return
+  *
+  *    Returns 1 if a card actually exists (i.e. the pos isn't
+  *    all 0xff) or 0 otherwise
+--- linux-2.6.0-test6/arch/i386/kernel/mpparse.c       2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/i386/kernel/mpparse.c      2003-10-05 00:36:48.000000000 -0700
+@@ -169,7 +169,7 @@ void __init MP_processor_info (struct mp
+       if (num_processors >= NR_CPUS) {
+               printk(KERN_WARNING "NR_CPUS limit of %i reached.  Cannot "
+-                      "boot CPU(apicid 0x%d).\n", NR_CPUS, m->mpc_apicid);
++                      "boot CPU(apicid 0x%x).\n", NR_CPUS, m->mpc_apicid);
+               return;
+       }
+       num_processors++;
+@@ -616,6 +616,31 @@ static inline void __init construct_defa
+       }
+ }
++#ifdef CONFIG_X86_IO_APIC
++/* irq_vector must be have an entry for all RTEs of all I/O APICs. */
++void __init alloc_irq_vector_array(void)
++{
++      int     total = 0;
++      int     idx;
++      union IO_APIC_reg_01    reg_01;
++
++      /* The I/O APIC fixmaps aren't inited yet, so use the first one. */
++      for (idx = 0; idx < nr_ioapics; idx++) {
++              set_fixmap_nocache(FIX_IO_APIC_BASE_0, mp_ioapics[idx].mpc_apicaddr);
++              reg_01.raw = io_apic_read(0, 1);
++              total += reg_01.bits.entries + 1;
++      }
++
++      /* Always alloc at least NR_IRQS vectors. */
++      nr_irqs = max(total, NR_IRQS);
++      irq_vector = (u8 *) alloc_bootmem(nr_irqs);
++      memset(irq_vector, 0, nr_irqs);
++      irq_vector[0] = FIRST_DEVICE_VECTOR;
++}
++#else
++void __init alloc_irq_vector_array(void) { }
++#endif /* CONFIG_X86_IO_APIC */
++
+ static struct intel_mp_floating *mpf_found;
+ /*
+@@ -633,6 +658,7 @@ void __init get_smp_config (void)
+        */
+       if (acpi_lapic && acpi_ioapic) {
+               printk(KERN_INFO "Using ACPI (MADT) for SMP configuration information\n");
++              alloc_irq_vector_array();
+               return;
+       }
+       else if (acpi_lapic)
+@@ -661,10 +687,11 @@ void __init get_smp_config (void)
+                * Read the physical hardware table.  Anything here will
+                * override the defaults.
+                */
+-              if (!smp_read_mpc((void *)mpf->mpf_physptr)) {
++              if (!smp_read_mpc((void *)phys_to_virt(mpf->mpf_physptr))) {
+                       smp_found_config = 0;
+                       printk(KERN_ERR "BIOS bug, MP table errors detected!...\n");
+                       printk(KERN_ERR "... disabling SMP support. (tell your hw vendor)\n");
++                      alloc_irq_vector_array();
+                       return;
+               }
+               /*
+@@ -688,6 +715,7 @@ void __init get_smp_config (void)
+       } else
+               BUG();
++      alloc_irq_vector_array();
+       printk(KERN_INFO "Processors: %d\n", num_processors);
+       /*
+        * Only use the first configuration found.
+@@ -830,7 +858,7 @@ void __init mp_register_lapic (
+       MP_processor_info(&processor);
+ }
+-#ifdef CONFIG_X86_IO_APIC
++#if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_ACPI_INTERPRETER)
+ #define MP_ISA_BUS            0
+ #define MP_MAX_IOAPIC_PIN     127
+@@ -1019,10 +1047,6 @@ void __init mp_config_acpi_legacy_irqs (
+       }
+ }
+-#ifdef        CONFIG_ACPI
+-
+-/* Ensure the ACPI SCI interrupt level is active low, edge-triggered */
+-
+ extern FADT_DESCRIPTOR acpi_fadt;
+ void __init mp_config_ioapic_for_sci(int irq)
+@@ -1031,6 +1055,7 @@ void __init mp_config_ioapic_for_sci(int
+       int ioapic_pin;
+       struct acpi_table_madt *madt;
+       struct acpi_table_int_src_ovr *entry = NULL;
++      acpi_interrupt_flags flags;
+       void *madt_end;
+       acpi_status status;
+@@ -1049,32 +1074,37 @@ void __init mp_config_ioapic_for_sci(int
+               while ((void *) entry < madt_end) {
+                       if (entry->header.type == ACPI_MADT_INT_SRC_OVR &&
+-                          acpi_fadt.sci_int == entry->bus_irq) {
+-                              /*
+-                               * See the note at the end of ACPI 2.0b section
+-                               * 5.2.10.8 for what this is about.
+-                               */
+-                              if (entry->bus_irq != entry->global_irq) {
+-                                      acpi_fadt.sci_int = entry->global_irq;
+-                                      irq = entry->global_irq;
+-                                      break;
+-                              }
+-                              else
+-                                      return;
+-                      }
+-
++                          acpi_fadt.sci_int == entry->bus_irq)
++                              goto found;
++                      
+                       entry = (struct acpi_table_int_src_ovr *)
+                               ((unsigned long) entry + entry->header.length);
+               }
+       }
++      /*
++       * Although the ACPI spec says that the SCI should be level/low
++       * don't reprogram it unless there is an explicit MADT OVR entry
++       * instructing us to do so -- otherwise we break Tyan boards which
++       * have the SCI wired edge/high but no MADT OVR.
++       */
++      return;
++
++found:
++      /*
++       * See the note at the end of ACPI 2.0b section
++       * 5.2.10.8 for what this is about.
++       */
++      flags = entry->flags;
++      acpi_fadt.sci_int = entry->global_irq;
++      irq = entry->global_irq;
+       ioapic = mp_find_ioapic(irq);
+       ioapic_pin = irq - mp_ioapic_routing[ioapic].irq_start;
+-      io_apic_set_pci_routing(ioapic, ioapic_pin, irq, 1, 1); // Active low, level triggered
++      io_apic_set_pci_routing(ioapic, ioapic_pin, irq, 
++                              (flags.trigger >> 1) , (flags.polarity >> 1));
+ }
+-#endif        /* CONFIG_ACPI */
+ #ifdef CONFIG_ACPI_PCI
+@@ -1110,8 +1140,10 @@ void __init mp_parse_prt (void)
+               }
+               /* Don't set up the ACPI SCI because it's already set up */
+-              if (acpi_fadt.sci_int == irq)
++                if (acpi_fadt.sci_int == irq) {
++                        entry->irq = irq; /*we still need to set entry's irq*/
+                       continue;
++                }
+       
+               ioapic = mp_find_ioapic(irq);
+               if (ioapic < 0)
+@@ -1136,15 +1168,19 @@ void __init mp_parse_prt (void)
+               if ((1<<bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) {
+                       printk(KERN_DEBUG "Pin %d-%d already programmed\n",
+                               mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
+-                      entry->irq = irq;
++                      if (use_pci_vector() && !platform_legacy_irq(irq))
++                              irq = IO_APIC_VECTOR(irq);
++                      entry->irq = irq;
+                       continue;
+               }
+               mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<<bit);
+-              if (!io_apic_set_pci_routing(ioapic, ioapic_pin, irq, edge_level, active_high_low))
+-                      entry->irq = irq;
+-
++              if (!io_apic_set_pci_routing(ioapic, ioapic_pin, irq, edge_level, active_high_low)) {
++                      if (use_pci_vector() && !platform_legacy_irq(irq))
++                              irq = IO_APIC_VECTOR(irq);
++                      entry->irq = irq;
++              }
+               printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d -> IRQ %d\n",
+                       entry->id.segment, entry->id.bus, 
+                       entry->id.device, ('A' + entry->pin), 
+@@ -1154,5 +1190,5 @@ void __init mp_parse_prt (void)
+ }
+ #endif /*CONFIG_ACPI_PCI*/
+-#endif        /* CONFIG_X86_IO_APIC */
++#endif /*CONFIG_X86_IO_APIC && CONFIG_ACPI_INTERPRETER*/
+ #endif /*CONFIG_ACPI_BOOT*/
+--- linux-2.6.0-test6/arch/i386/kernel/nmi.c   2003-08-08 22:55:10.000000000 -0700
++++ 25/arch/i386/kernel/nmi.c  2003-10-05 00:33:38.000000000 -0700
+@@ -31,7 +31,16 @@
+ #include <asm/mpspec.h>
+ #include <asm/nmi.h>
++#ifdef CONFIG_KGDB
++#include <asm/kgdb.h>
++#ifdef CONFIG_SMP
++unsigned int nmi_watchdog = NMI_IO_APIC;
++#else
++unsigned int nmi_watchdog = NMI_LOCAL_APIC;
++#endif
++#else
+ unsigned int nmi_watchdog = NMI_NONE;
++#endif
+ static unsigned int nmi_hz = HZ;
+ unsigned int nmi_perfctr_msr; /* the MSR to reset in NMI handler */
+ extern void show_registers(struct pt_regs *regs);
+@@ -408,6 +417,9 @@ void touch_nmi_watchdog (void)
+       for (i = 0; i < NR_CPUS; i++)
+               alert_counter[i] = 0;
+ }
++#ifdef CONFIG_KGDB
++int tune_watchdog = 5*HZ;
++#endif
+ void nmi_watchdog_tick (struct pt_regs * regs)
+ {
+@@ -421,12 +433,24 @@ void nmi_watchdog_tick (struct pt_regs *
+       sum = irq_stat[cpu].apic_timer_irqs;
++#ifdef CONFIG_KGDB
++      if (! in_kgdb(regs) && last_irq_sums[cpu] == sum ) {
++
++#else
+       if (last_irq_sums[cpu] == sum) {
++#endif
+               /*
+                * Ayiee, looks like this CPU is stuck ...
+                * wait a few IRQs (5 seconds) before doing the oops ...
+                */
+               alert_counter[cpu]++;
++#ifdef CONFIG_KGDB
++                if (alert_counter[cpu] == tune_watchdog) {
++                        kgdb_handle_exception(2, SIGPWR, 0, regs);
++                        last_irq_sums[cpu] = sum;
++                        alert_counter[cpu] = 0;
++                }
++#endif
+               if (alert_counter[cpu] == 5*nmi_hz) {
+                       spin_lock(&nmi_print_lock);
+                       /*
+--- linux-2.6.0-test6/arch/i386/kernel/process.c       2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/i386/kernel/process.c      2003-10-05 00:36:48.000000000 -0700
+@@ -47,6 +47,7 @@
+ #include <asm/i387.h>
+ #include <asm/irq.h>
+ #include <asm/desc.h>
++#include <asm/atomic_kmap.h>
+ #ifdef CONFIG_MATH_EMULATION
+ #include <asm/math_emu.h>
+ #endif
+@@ -298,6 +299,9 @@ void flush_thread(void)
+       struct task_struct *tsk = current;
+       memset(tsk->thread.debugreg, 0, sizeof(unsigned long)*8);
++#ifdef CONFIG_X86_HIGH_ENTRY
++      clear_thread_flag(TIF_DB7);
++#endif
+       memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array));        
+       /*
+        * Forget coprocessor state..
+@@ -311,9 +315,8 @@ void release_thread(struct task_struct *
+       if (dead_task->mm) {
+               // temporary debugging check
+               if (dead_task->mm->context.size) {
+-                      printk("WARNING: dead process %8s still has LDT? <%p/%d>\n",
++                      printk("WARNING: dead process %8s still has LDT? <%d>\n",
+                                       dead_task->comm,
+-                                      dead_task->mm->context.ldt,
+                                       dead_task->mm->context.size);
+                       BUG();
+               }
+@@ -348,7 +351,17 @@ int copy_thread(int nr, unsigned long cl
+       p->thread.esp = (unsigned long) childregs;
+       p->thread.esp0 = (unsigned long) (childregs+1);
++      /*
++       * get the two stack pages, for the virtual stack.
++       *
++       * IMPORTANT: this code relies on the fact that the task
++       * structure is an 8K aligned piece of physical memory.
++       */
++      p->thread.stack_page0 = virt_to_page((unsigned long)p->thread_info);
++      p->thread.stack_page1 = virt_to_page((unsigned long)p->thread_info + PAGE_SIZE);
++
+       p->thread.eip = (unsigned long) ret_from_fork;
++      p->thread_info->real_stack = p->thread_info;
+       savesegment(fs,p->thread.fs);
+       savesegment(gs,p->thread.gs);
+@@ -500,10 +513,40 @@ struct task_struct * __switch_to(struct 
+       __unlazy_fpu(prev_p);
++#ifdef CONFIG_X86_HIGH_ENTRY
++      /*
++       * Set the ptes of the virtual stack. (NOTE: a one-page TLB flush is
++       * needed because otherwise NMIs could interrupt the
++       * user-return code with a virtual stack and stale TLBs.)
++       */
++      __kunmap_atomic_type(KM_VSTACK0);
++      __kunmap_atomic_type(KM_VSTACK1);
++      __kmap_atomic(next->stack_page0, KM_VSTACK0);
++      __kmap_atomic(next->stack_page1, KM_VSTACK1);
++
++      /*
++       * NOTE: here we rely on the task being the stack as well
++       */
++      next_p->thread_info->virtual_stack = (void *)__kmap_atomic_vaddr(KM_VSTACK0);
++
++#if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP)
++      /*
++       * If next was preempted on entry from userspace to kernel,
++       * and now it's on a different cpu, we need to adjust %esp.
++       * This assumes that entry.S does not copy %esp while on the
++       * virtual stack (with interrupts enabled): which is so,
++       * except within __SWITCH_KERNELSPACE itself.
++       */
++      if (unlikely(next->esp >= TASK_SIZE)) {
++              next->esp &= THREAD_SIZE - 1;
++              next->esp |= (unsigned long) next_p->thread_info->virtual_stack;
++      }
++#endif
++#endif
+       /*
+-       * Reload esp0, LDT and the page table pointer:
++       * Reload esp0:
+        */
+-      load_esp0(tss, next->esp0);
++      load_esp0(tss, virtual_esp0(next_p));
+       /*
+        * Load the per-thread Thread-Local Storage descriptor.
+--- linux-2.6.0-test6/arch/i386/kernel/reboot.c        2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/i386/kernel/reboot.c       2003-10-05 00:36:48.000000000 -0700
+@@ -7,6 +7,7 @@
+ #include <linux/init.h>
+ #include <linux/interrupt.h>
+ #include <linux/mc146818rtc.h>
++#include <linux/efi.h>
+ #include <asm/uaccess.h>
+ #include <asm/apic.h>
+ #include "mach_reboot.h"
+@@ -153,12 +154,11 @@ void machine_real_restart(unsigned char 
+       CMOS_WRITE(0x00, 0x8f);
+       spin_unlock_irqrestore(&rtc_lock, flags);
+-      /* Remap the kernel at virtual address zero, as well as offset zero
+-         from the kernel segment.  This assumes the kernel segment starts at
+-         virtual address PAGE_OFFSET. */
+-
+-      memcpy (swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
+-              sizeof (swapper_pg_dir [0]) * KERNEL_PGD_PTRS);
++      /*
++       * Remap the first 16 MB of RAM (which includes the kernel image)
++       * at virtual address zero:
++       */
++      setup_identity_mappings(swapper_pg_dir, 0, 16*1024*1024);
+       /*
+        * Use `swapper_pg_dir' as our page directory.
+@@ -262,7 +262,12 @@ void machine_restart(char * __unused)
+       disable_IO_APIC();
+ #endif
+-      if(!reboot_thru_bios) {
++      if (!reboot_thru_bios) {
++              if (efi_enabled) {
++                      efi.reset_system(EFI_RESET_COLD, EFI_SUCCESS, 0, 0);
++                      __asm__ __volatile__("lidt %0": :"m" (no_idt));
++                      __asm__ __volatile__("int3");
++              }
+               /* rebooting needs to touch the page at absolute addr 0 */
+               *((unsigned short *)__va(0x472)) = reboot_mode;
+               for (;;) {
+@@ -272,6 +277,8 @@ void machine_restart(char * __unused)
+                       __asm__ __volatile__("int3");
+               }
+       }
++      if (efi_enabled)
++              efi.reset_system(EFI_RESET_WARM, EFI_SUCCESS, 0, 0);
+       machine_real_restart(jump_to_bios, sizeof(jump_to_bios));
+ }
+@@ -282,6 +289,8 @@ void machine_halt(void)
+ void machine_power_off(void)
+ {
++      if (efi_enabled)
++              efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, 0);
+       if (pm_power_off)
+               pm_power_off();
+ }
+--- linux-2.6.0-test6/arch/i386/kernel/setup.c 2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/i386/kernel/setup.c        2003-10-05 00:36:22.000000000 -0700
+@@ -36,6 +36,8 @@
+ #include <linux/root_dev.h>
+ #include <linux/highmem.h>
+ #include <linux/module.h>
++#include <linux/efi.h>
++#include <linux/init.h>
+ #include <video/edid.h>
+ #include <asm/e820.h>
+ #include <asm/mpspec.h>
+@@ -56,6 +58,8 @@ static inline char * __init machine_spec
+  * Machine setup..
+  */
++int efi_enabled = 0;
++
+ /* cpu data as detected by the assembly code in head.S */
+ struct cpuinfo_x86 new_cpu_data __initdata = { 0, 0, 0, 0, -1, 1, 0, 0, -1 };
+ /* common cpu data for all cpus */
+@@ -64,10 +68,10 @@ struct cpuinfo_x86 boot_cpu_data = { 0, 
+ unsigned long mmu_cr4_features;
+ EXPORT_SYMBOL_GPL(mmu_cr4_features);
+-#ifdef        CONFIG_ACPI
+-      int acpi_disabled __initdata = 0;
++#ifdef        CONFIG_ACPI_INTERPRETER
++      int acpi_disabled = 0;
+ #else
+-      int acpi_disabled __initdata = 1;
++      int acpi_disabled = 1;
+ #endif
+ EXPORT_SYMBOL(acpi_disabled);
+@@ -144,6 +148,20 @@ static void __init limit_regions (unsign
+       int i;
+       unsigned long long current_size = 0;
++      if (efi_enabled) {
++              for (i = 0; i < memmap.nr_map; i++) {
++                      current_size = memmap.map[i].phys_addr +
++                                     (memmap.map[i].num_pages << 12);
++                      if (memmap.map[i].type == EFI_CONVENTIONAL_MEMORY) {
++                              if (current_size > size) {
++                                      memmap.map[i].num_pages -=
++                                              (((current_size-size) + PAGE_SIZE-1) >> PAGE_SHIFT);
++                                      memmap.nr_map = i + 1;
++                                      return;
++                              }
++                      }
++              }
++      }
+       for (i = 0; i < e820.nr_map; i++) {
+               if (e820.map[i].type == E820_RAM) {
+                       current_size += e820.map[i].size;
+@@ -158,17 +176,21 @@ static void __init limit_regions (unsign
+ static void __init add_memory_region(unsigned long long start,
+                                   unsigned long long size, int type)
+ {
+-      int x = e820.nr_map;
++      int x;
+-      if (x == E820MAX) {
+-          printk(KERN_ERR "Ooops! Too many entries in the memory map!\n");
+-          return;
+-      }
++      if (!efi_enabled) {
++                      x = e820.nr_map;
+-      e820.map[x].addr = start;
+-      e820.map[x].size = size;
+-      e820.map[x].type = type;
+-      e820.nr_map++;
++              if (x == E820MAX) {
++                  printk(KERN_ERR "Ooops! Too many entries in the memory map!\n");
++                  return;
++              }
++
++              e820.map[x].addr = start;
++              e820.map[x].size = size;
++              e820.map[x].type = type;
++              e820.nr_map++;
++      }
+ } /* add_memory_region */
+ #define E820_DEBUG    1
+@@ -445,7 +467,6 @@ static inline void copy_edd(void)
+ static void __init setup_memory_region(void)
+ {
+       char *who = machine_specific_memory_setup();
+-
+       printk(KERN_INFO "BIOS-provided physical RAM map:\n");
+       print_memory_map(who);
+ } /* setup_memory_region */
+@@ -583,6 +604,23 @@ static void __init parse_cmdline_early (
+ }
+ /*
++ * Callback for efi_memory_walk.
++ */
++static int __init
++efi_find_max_pfn(unsigned long start, unsigned long end, void *arg)
++{
++      unsigned long *max_pfn = arg, pfn;
++
++      if (start < end) {
++              pfn = PFN_UP(end -1);
++              if (pfn > *max_pfn)
++                      *max_pfn = pfn;
++      }
++      return 0;
++}
++
++
++/*
+  * Find the highest page frame number we have available
+  */
+ void __init find_max_pfn(void)
+@@ -590,6 +628,11 @@ void __init find_max_pfn(void)
+       int i;
+       max_pfn = 0;
++      if (efi_enabled) {
++              efi_memmap_walk(efi_find_max_pfn, &max_pfn);
++              return;
++      }
++
+       for (i = 0; i < e820.nr_map; i++) {
+               unsigned long start, end;
+               /* RAM? */
+@@ -664,6 +707,25 @@ unsigned long __init find_max_low_pfn(vo
+ }
+ #ifndef CONFIG_DISCONTIGMEM
++
++/*
++ * Free all available memory for boot time allocation.  Used
++ * as a callback function by efi_memory_walk()
++ */
++
++static int __init
++free_available_memory(unsigned long start, unsigned long end, void *arg)
++{
++      /* check max_low_pfn */
++      if (start >= ((max_low_pfn + 1) << PAGE_SHIFT))
++              return 0;
++      if (end >= ((max_low_pfn + 1) << PAGE_SHIFT))
++              end = (max_low_pfn + 1) << PAGE_SHIFT;
++      if (start < end)
++              free_bootmem(start, end - start);
++
++      return 0;
++}
+ /*
+  * Register fully available low RAM pages with the bootmem allocator.
+  */
+@@ -671,6 +733,10 @@ static void __init register_bootmem_low_
+ {
+       int i;
++      if (efi_enabled) {
++              efi_memmap_walk(free_available_memory, NULL);
++              return;
++      }
+       for (i = 0; i < e820.nr_map; i++) {
+               unsigned long curr_pfn, last_pfn, size;
+               /*
+@@ -798,9 +864,9 @@ extern unsigned long setup_memory(void);
+  * Request address space for all standard RAM and ROM resources
+  * and also for regions reported as reserved by the e820.
+  */
+-static void __init register_memory(unsigned long max_low_pfn)
++static void __init
++legacy_init_iomem_resources(struct resource *code_resource, struct resource *data_resource)
+ {
+-      unsigned long low_mem_size;
+       int i;
+       probe_roms();
+@@ -825,11 +891,26 @@ static void __init register_memory(unsig
+                        *  so we try it repeatedly and let the resource manager
+                        *  test it.
+                        */
+-                      request_resource(res, &code_resource);
+-                      request_resource(res, &data_resource);
++                      request_resource(res, code_resource);
++                      request_resource(res, data_resource);
+               }
+       }
++}
++
++/*
++ * Request address space for all standard resources
++ */
++static void __init register_memory(unsigned long max_low_pfn)
++{
++      unsigned long low_mem_size;
++      int i;
++      if (efi_enabled)
++              efi_initialize_iomem_resources(&code_resource, &data_resource);
++      else
++              legacy_init_iomem_resources(&code_resource, &data_resource);
++
++       /* EFI systems may still have VGA */
+       request_graphics_resource();
+       /* request I/O space for devices used on all i[345]86 PCs */
+@@ -949,6 +1030,13 @@ static int __init noreplacement_setup(ch
+ __setup("noreplacement", noreplacement_setup); 
++/*
++ * Determine if we were loaded by an EFI loader.  If so, then we have also been
++ * passed the efi memmap, systab, etc., so we should use these data structures
++ * for initialization.  Note, the efi init code path is determined by the
++ * global efi_enabled. This allows the same kernel image to be used on existing
++ * systems (with a traditional BIOS) as well as on EFI systems.
++ */
+ void __init setup_arch(char **cmdline_p)
+ {
+       unsigned long max_low_pfn;
+@@ -957,6 +1045,12 @@ void __init setup_arch(char **cmdline_p)
+       pre_setup_arch_hook();
+       early_cpu_init();
++      /* FIXME: This isn't an official loader_type right
++       * now but does currently work with elilo.
++       */
++      if ((LOADER_TYPE == 0x50) && EFI_SYSTAB)
++              efi_enabled = 1;
++
+       ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV);
+       drive_info = DRIVE_INFO;
+       screen_info = SCREEN_INFO;
+@@ -979,7 +1073,11 @@ void __init setup_arch(char **cmdline_p)
+       rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
+ #endif
+       ARCH_SETUP
+-      setup_memory_region();
++      if (efi_enabled)
++              efi_init();
++      else
++              setup_memory_region();
++
+       copy_edd();
+       if (!MOUNT_ROOT_RDONLY)
+@@ -1013,6 +1111,8 @@ void __init setup_arch(char **cmdline_p)
+ #ifdef CONFIG_X86_GENERICARCH
+       generic_apic_probe(*cmdline_p);
+ #endif        
++      if (efi_enabled)
++              efi_map_memmap();
+       /*
+        * Parse the ACPI tables for possible boot-time SMP configuration.
+@@ -1028,7 +1128,8 @@ void __init setup_arch(char **cmdline_p)
+ #ifdef CONFIG_VT
+ #if defined(CONFIG_VGA_CONSOLE)
+-      conswitchp = &vga_con;
++      if (!efi_enabled || (efi_mem_type(0xa0000) != EFI_CONVENTIONAL_MEMORY))
++              conswitchp = &vga_con;
+ #elif defined(CONFIG_DUMMY_CONSOLE)
+       conswitchp = &dummy_con;
+ #endif
+--- linux-2.6.0-test6/arch/i386/kernel/signal.c        2003-06-14 12:18:09.000000000 -0700
++++ 25/arch/i386/kernel/signal.c       2003-10-05 00:36:48.000000000 -0700
+@@ -128,25 +128,25 @@ sys_sigaltstack(const stack_t __user *us
+  */
+ static int
+-restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *peax)
++restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *__sc, int *peax)
+ {
+-      unsigned int err = 0;
++      struct sigcontext scratch; /* 88 bytes of scratch area */
+-#define COPY(x)               err |= __get_user(regs->x, &sc->x)
++      if (copy_from_user(&scratch, __sc, sizeof(scratch)))
++              return -EFAULT;
++
++#define COPY(x)               regs->x = scratch.x
+ #define COPY_SEG(seg)                                                 \
+-      { unsigned short tmp;                                           \
+-        err |= __get_user(tmp, &sc->seg);                             \
++      { unsigned short tmp = scratch.seg;                             \
+         regs->x##seg = tmp; }
+ #define COPY_SEG_STRICT(seg)                                          \
+-      { unsigned short tmp;                                           \
+-        err |= __get_user(tmp, &sc->seg);                             \
++      { unsigned short tmp = scratch.seg;                             \
+         regs->x##seg = tmp|3; }
+ #define GET_SEG(seg)                                                  \
+-      { unsigned short tmp;                                           \
+-        err |= __get_user(tmp, &sc->seg);                             \
++      { unsigned short tmp = scratch.seg;                             \
+         loadsegment(seg,tmp); }
+       GET_SEG(gs);
+@@ -165,27 +165,23 @@ restore_sigcontext(struct pt_regs *regs,
+       COPY_SEG_STRICT(ss);
+       
+       {
+-              unsigned int tmpflags;
+-              err |= __get_user(tmpflags, &sc->eflags);
++              unsigned int tmpflags = scratch.eflags;
+               regs->eflags = (regs->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
+               regs->orig_eax = -1;            /* disable syscall checks */
+       }
+       {
+-              struct _fpstate __user * buf;
+-              err |= __get_user(buf, &sc->fpstate);
++              struct _fpstate * buf = scratch.fpstate;
+               if (buf) {
+                       if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
+-                              goto badframe;
+-                      err |= restore_i387(buf);
++                              return -EFAULT;
++                      if (restore_i387(buf))
++                              return -EFAULT;
+               }
+       }
+-      err |= __get_user(*peax, &sc->eax);
+-      return err;
+-
+-badframe:
+-      return 1;
++      *peax = scratch.eax;
++      return 0;
+ }
+ asmlinkage int sys_sigreturn(unsigned long __unused)
+@@ -263,46 +259,47 @@ badframe:
+  */
+ static int
+-setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate,
++setup_sigcontext(struct sigcontext __user *__sc, struct _fpstate __user *fpstate,
+                struct pt_regs *regs, unsigned long mask)
+ {
+-      int tmp, err = 0;
++      struct sigcontext sc; /* 88 bytes of scratch area */
++      int tmp;
+       tmp = 0;
+       __asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp));
+-      err |= __put_user(tmp, (unsigned int *)&sc->gs);
++      *(unsigned int *)&sc.gs = tmp;
+       __asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp));
+-      err |= __put_user(tmp, (unsigned int *)&sc->fs);
+-
+-      err |= __put_user(regs->xes, (unsigned int *)&sc->es);
+-      err |= __put_user(regs->xds, (unsigned int *)&sc->ds);
+-      err |= __put_user(regs->edi, &sc->edi);
+-      err |= __put_user(regs->esi, &sc->esi);
+-      err |= __put_user(regs->ebp, &sc->ebp);
+-      err |= __put_user(regs->esp, &sc->esp);
+-      err |= __put_user(regs->ebx, &sc->ebx);
+-      err |= __put_user(regs->edx, &sc->edx);
+-      err |= __put_user(regs->ecx, &sc->ecx);
+-      err |= __put_user(regs->eax, &sc->eax);
+-      err |= __put_user(current->thread.trap_no, &sc->trapno);
+-      err |= __put_user(current->thread.error_code, &sc->err);
+-      err |= __put_user(regs->eip, &sc->eip);
+-      err |= __put_user(regs->xcs, (unsigned int *)&sc->cs);
+-      err |= __put_user(regs->eflags, &sc->eflags);
+-      err |= __put_user(regs->esp, &sc->esp_at_signal);
+-      err |= __put_user(regs->xss, (unsigned int *)&sc->ss);
++      *(unsigned int *)&sc.fs = tmp;
++      *(unsigned int *)&sc.es = regs->xes;
++      *(unsigned int *)&sc.ds = regs->xds;
++      sc.edi = regs->edi;
++      sc.esi = regs->esi;
++      sc.ebp = regs->ebp;
++      sc.esp = regs->esp;
++      sc.ebx = regs->ebx;
++      sc.edx = regs->edx;
++      sc.ecx = regs->ecx;
++      sc.eax = regs->eax;
++      sc.trapno = current->thread.trap_no;
++      sc.err = current->thread.error_code;
++      sc.eip = regs->eip;
++      *(unsigned int *)&sc.cs = regs->xcs;
++      sc.eflags = regs->eflags;
++      sc.esp_at_signal = regs->esp;
++      *(unsigned int *)&sc.ss = regs->xss;
+       tmp = save_i387(fpstate);
+       if (tmp < 0)
+-        err = 1;
+-      else
+-        err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate);
++              return 1;
++      sc.fpstate = tmp ? fpstate : NULL;
+       /* non-iBCS2 extensions.. */
+-      err |= __put_user(mask, &sc->oldmask);
+-      err |= __put_user(current->thread.cr2, &sc->cr2);
++      sc.oldmask = mask;
++      sc.cr2 = current->thread.cr2;
+-      return err;
++      if (copy_to_user(__sc, &sc, sizeof(sc)))
++              return 1;
++      return 0;
+ }
+ /*
+@@ -440,7 +437,7 @@ static void setup_rt_frame(int sig, stru
+       /* Create the ucontext.  */
+       err |= __put_user(0, &frame->uc.uc_flags);
+       err |= __put_user(0, &frame->uc.uc_link);
+-      err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
++      err |= __put_user(current->sas_ss_sp, (unsigned long *)&frame->uc.uc_stack.ss_sp);
+       err |= __put_user(sas_ss_flags(regs->esp),
+                         &frame->uc.uc_stack.ss_flags);
+       err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+--- linux-2.6.0-test6/arch/i386/kernel/smpboot.c       2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/i386/kernel/smpboot.c      2003-10-05 00:34:39.000000000 -0700
+@@ -499,8 +499,8 @@ static struct task_struct * __init fork_
+ #ifdef CONFIG_NUMA
+ /* which logical CPUs are on which nodes */
+-cpumask_t node_2_cpu_mask[MAX_NR_NODES] =
+-                              { [0 ... MAX_NR_NODES-1] = CPU_MASK_NONE };
++cpumask_t node_2_cpu_mask[MAX_NUMNODES] =
++                              { [0 ... MAX_NUMNODES-1] = CPU_MASK_NONE };
+ /* which node each logical CPU is on */
+ int cpu_2_node[NR_CPUS] = { [0 ... NR_CPUS-1] = 0 };
+@@ -518,7 +518,7 @@ static inline void unmap_cpu_to_node(int
+       int node;
+       printk("Unmapping cpu %d from all nodes\n", cpu);
+-      for (node = 0; node < MAX_NR_NODES; node ++)
++      for (node = 0; node < MAX_NUMNODES; node ++)
+               cpu_clear(cpu, node_2_cpu_mask[node]);
+       cpu_2_node[cpu] = -1;
+ }
+@@ -937,6 +937,7 @@ int cpu_sibling_map[NR_CPUS] __cacheline
+ static void __init smp_boot_cpus(unsigned int max_cpus)
+ {
+       int apicid, cpu, bit, kicked;
++      unsigned long bogosum = 0;
+       /*
+        * Setup boot CPU information
+@@ -1048,26 +1049,25 @@ static void __init smp_boot_cpus(unsigne
+       /*
+        * Allow the user to impress friends.
+        */
+-
+       Dprintk("Before bogomips.\n");
+-      if (!cpucount) {
+-              printk(KERN_ERR "Error: only one processor found.\n");
+-      } else {
+-              unsigned long bogosum = 0;
+-              for (cpu = 0; cpu < NR_CPUS; cpu++)
+-                      if (cpu_isset(cpu, cpu_callout_map))
+-                              bogosum += cpu_data[cpu].loops_per_jiffy;
+-              printk(KERN_INFO "Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
+-                      cpucount+1,
+-                      bogosum/(500000/HZ),
+-                      (bogosum/(5000/HZ))%100);
+-              Dprintk("Before bogocount - setting activated=1.\n");
+-      }
++      for (cpu = 0; cpu < NR_CPUS; cpu++)
++              if (cpu_isset(cpu, cpu_callout_map))
++                      bogosum += cpu_data[cpu].loops_per_jiffy;
++      printk(KERN_INFO
++              "Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
++              cpucount+1,
++              bogosum/(500000/HZ),
++              (bogosum/(5000/HZ))%100);
++      
++      Dprintk("Before bogocount - setting activated=1.\n");
+       if (smp_b_stepping)
+               printk(KERN_WARNING "WARNING: SMP operation may be unreliable with B stepping processors.\n");
+-      /* Don't taint if we are running SMP kernel on a single non-MP approved Athlon  */
++      /*
++       * Don't taint if we are running SMP kernel on a single non-MP
++       * approved Athlon
++       */
+       if (tainted & TAINT_UNSAFE_SMP) {
+               if (cpucount)
+                       printk (KERN_INFO "WARNING: This combination of AMD processors is not suitable for SMP.\n");
+--- linux-2.6.0-test6/arch/i386/kernel/smp.c   2003-08-22 19:23:40.000000000 -0700
++++ 25/arch/i386/kernel/smp.c  2003-10-05 00:36:48.000000000 -0700
+@@ -327,10 +327,12 @@ asmlinkage void smp_invalidate_interrupt
+                
+       if (flush_mm == cpu_tlbstate[cpu].active_mm) {
+               if (cpu_tlbstate[cpu].state == TLBSTATE_OK) {
++#ifndef CONFIG_X86_SWITCH_PAGETABLES
+                       if (flush_va == FLUSH_ALL)
+                               local_flush_tlb();
+                       else
+                               __flush_tlb_one(flush_va);
++#endif
+               } else
+                       leave_mm(cpu);
+       }
+@@ -396,21 +398,6 @@ static void flush_tlb_others(cpumask_t c
+       spin_unlock(&tlbstate_lock);
+ }
+       
+-void flush_tlb_current_task(void)
+-{
+-      struct mm_struct *mm = current->mm;
+-      cpumask_t cpu_mask;
+-
+-      preempt_disable();
+-      cpu_mask = mm->cpu_vm_mask;
+-      cpu_clear(smp_processor_id(), cpu_mask);
+-
+-      local_flush_tlb();
+-      if (!cpus_empty(cpu_mask))
+-              flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
+-      preempt_enable();
+-}
+-
+ void flush_tlb_mm (struct mm_struct * mm)
+ {
+       cpumask_t cpu_mask;
+@@ -442,7 +429,10 @@ void flush_tlb_page(struct vm_area_struc
+       if (current->active_mm == mm) {
+               if(current->mm)
+-                      __flush_tlb_one(va);
++#ifndef CONFIG_X86_SWITCH_PAGETABLES
++                      __flush_tlb_one(va)
++#endif
++                              ;
+                else
+                       leave_mm(smp_processor_id());
+       }
+@@ -466,7 +456,17 @@ void flush_tlb_all(void)
+ {
+       on_each_cpu(do_flush_tlb_all, 0, 1, 1);
+ }
+-
++#ifdef CONFIG_KGDB
++/*
++ * By using the NMI code instead of a vector we just sneak thru the
++ * word generator coming out with just what we want.  AND it does
++ * not matter if clustered_apic_mode is set or not.
++ */
++void smp_send_nmi_allbutself(void)
++{
++      send_IPI_allbutself(APIC_DM_NMI);
++}
++#endif
+ /*
+  * this function sends a 'reschedule' IPI to another CPU.
+  * it goes straight through and wastes no time serializing
+--- linux-2.6.0-test6/arch/i386/kernel/sysenter.c      2003-08-08 22:55:10.000000000 -0700
++++ 25/arch/i386/kernel/sysenter.c     2003-10-05 00:36:48.000000000 -0700
+@@ -18,13 +18,18 @@
+ #include <asm/msr.h>
+ #include <asm/pgtable.h>
+ #include <asm/unistd.h>
++#include <linux/highmem.h>
+ extern asmlinkage void sysenter_entry(void);
+ void enable_sep_cpu(void *info)
+ {
+       int cpu = get_cpu();
++#ifdef CONFIG_X86_HIGH_ENTRY
++      struct tss_struct *tss = (struct tss_struct *) __fix_to_virt(FIX_TSS_0) + cpu;
++#else
+       struct tss_struct *tss = init_tss + cpu;
++#endif
+       tss->ss1 = __KERNEL_CS;
+       tss->esp1 = sizeof(struct tss_struct) + (unsigned long) tss;
+--- linux-2.6.0-test6/arch/i386/kernel/time.c  2003-09-08 13:58:55.000000000 -0700
++++ 25/arch/i386/kernel/time.c 2003-10-05 00:36:22.000000000 -0700
+@@ -44,6 +44,7 @@
+ #include <linux/module.h>
+ #include <linux/sysdev.h>
+ #include <linux/bcd.h>
++#include <linux/efi.h>
+ #include <asm/io.h>
+ #include <asm/smp.h>
+@@ -160,6 +161,37 @@ static int set_rtc_mmss(unsigned long no
+       return retval;
+ }
++static int efi_set_rtc_mmss(unsigned long nowtime)
++{
++      int real_seconds, real_minutes;
++      unsigned long   flags;
++      efi_status_t    status;
++      efi_time_t      eft;
++      efi_time_cap_t  cap;
++
++      spin_lock_irqsave(&rtc_lock, flags);
++
++      status = efi.get_time(&eft, &cap);
++      if (status != EFI_SUCCESS)
++              panic("Ooops, efitime: can't read time!\n");
++      real_seconds = nowtime % 60;
++      real_minutes = nowtime / 60;
++
++      if (((abs(real_minutes - eft.minute) + 15)/30) & 1)
++              real_minutes += 30;
++      real_minutes %= 60;
++
++      eft.minute = real_minutes;
++      eft.second = real_seconds;
++
++      status = efi.set_time(&eft);
++      if (status != EFI_SUCCESS)
++              panic("Ooops: efitime: can't read time!\n");
++
++      spin_unlock_irqrestore(&rtc_lock, flags);
++      return 0;
++}
++
+ /* last time the cmos clock got updated */
+ static long last_rtc_update;
+@@ -212,7 +244,7 @@ static inline void do_timer_interrupt(in
+                       >= USEC_AFTER - ((unsigned) TICK_SIZE) / 2 &&
+           (xtime.tv_nsec / 1000)
+                       <= USEC_BEFORE + ((unsigned) TICK_SIZE) / 2) {
+-              if (set_rtc_mmss(xtime.tv_sec) == 0)
++              if ((efi_enabled && (!efi_set_rtc_mmss(xtime.tv_sec) )) || (set_rtc_mmss(xtime.tv_sec) == 0))
+                       last_rtc_update = xtime.tv_sec;
+               else
+                       last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+@@ -277,6 +309,27 @@ static struct sysdev_class pit_sysclass 
+       set_kset_name("pit"),
+ };
++/*
++ * This is called before the RT mappings are in place, so we
++ * need to be able to get the time in physical mode.
++ */
++unsigned long efi_get_time(void)
++{
++      efi_status_t status;
++      unsigned long flags;
++      efi_time_t eft;
++      efi_time_cap_t cap;
++
++      spin_lock_irqsave(&rtc_lock, flags);
++      status = phys_efi_get_time(&eft, &cap);
++      if (status != EFI_SUCCESS)
++              printk("Oops: efitime: can't read time status: 0x%lx\n", status);
++
++      spin_unlock_irqrestore(&rtc_lock, flags);
++
++      return mktime(eft.year, eft.month, eft.day, eft.hour, eft.minute, eft.second);
++}
++
+ /* XXX this driverfs stuff should probably go elsewhere later -john */
+ static struct sys_device device_i8253 = {
+       .id     = 0,
+@@ -298,7 +351,10 @@ extern void (*late_time_init)(void);
+ /* Duplicate of time_init() below, with hpet_enable part added */
+ void __init hpet_time_init(void)
+ {
+-      xtime.tv_sec = get_cmos_time();
++      if (efi_enabled)
++              xtime.tv_sec = efi_get_time();
++      else
++              xtime.tv_sec = get_cmos_time();
+       wall_to_monotonic.tv_sec = -xtime.tv_sec;
+       xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
+       wall_to_monotonic.tv_nsec = -xtime.tv_nsec;
+@@ -324,8 +380,10 @@ void __init time_init(void)
+               return;
+       }
+ #endif
+-
+-      xtime.tv_sec = get_cmos_time();
++      if (efi_enabled)
++              xtime.tv_sec = efi_get_time();
++      else
++              xtime.tv_sec = get_cmos_time();
+       wall_to_monotonic.tv_sec = -xtime.tv_sec;
+       xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
+       wall_to_monotonic.tv_nsec = -xtime.tv_nsec;
+--- linux-2.6.0-test6/arch/i386/kernel/traps.c 2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/i386/kernel/traps.c        2003-10-05 00:36:48.000000000 -0700
+@@ -54,12 +54,8 @@
+ #include "mach_traps.h"
+-asmlinkage int system_call(void);
+-asmlinkage void lcall7(void);
+-asmlinkage void lcall27(void);
+-
+-struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 },
+-              { 0, 0 }, { 0, 0 } };
++struct desc_struct default_ldt[] __attribute__((__section__(".data.default_ldt"))) = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
++struct page *default_ldt_page;
+ /* Do we ignore FPU interrupts ? */
+ char ignore_fpu_irq = 0;
+@@ -91,6 +87,43 @@ asmlinkage void alignment_check(void);
+ asmlinkage void spurious_interrupt_bug(void);
+ asmlinkage void machine_check(void);
++#ifdef CONFIG_KGDB
++extern void sysenter_entry(void);
++#include <asm/kgdb.h>
++#include <linux/init.h>
++extern void int3(void);
++extern void debug(void);
++void set_intr_gate(unsigned int n, void *addr);
++static void set_intr_usr_gate(unsigned int n, void *addr);
++/*
++ * Should be able to call this breakpoint() very early in
++ * bring up.  Just hard code the call where needed.
++ * The breakpoint() code is here because set_?_gate() functions
++ * are local (static) to trap.c.  They need be done only once,
++ * but it does not hurt to do them over.
++ */
++void breakpoint(void)
++{
++      init_entry_mappings();
++        set_intr_usr_gate(3,&int3); /* disable ints on trap */
++      set_intr_gate(1,&debug);
++      set_intr_gate(14,&page_fault);
++
++        BREAKPOINT;
++}
++#define       CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after)            \
++    {                                                                 \
++      if (!user_mode(regs)  ) \
++      {                                                               \
++              kgdb_handle_exception(trapnr, signr, error_code, regs); \
++              after;                                                  \
++      } else if ((trapnr == 3) && (regs->eflags &0x200)) local_irq_enable(); \
++    }
++#else
++#define       CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after)
++#endif
++
++
+ static int kstack_depth_to_print = 24;
+ void show_trace(struct task_struct *task, unsigned long * stack)
+@@ -173,8 +206,9 @@ void show_registers(struct pt_regs *regs
+               ss = regs->xss & 0xffff;
+       }
+       print_modules();
+-      printk("CPU:    %d\nEIP:    %04x:[<%08lx>]    %s\nEFLAGS: %08lx\n",
+-              smp_processor_id(), 0xffff & regs->xcs, regs->eip, print_tainted(), regs->eflags);
++      printk("CPU:    %d\nEIP:    %04x:[<%08lx>]    %s VLI\nEFLAGS: %08lx\n",
++              smp_processor_id(), 0xffff & regs->xcs,
++              regs->eip, print_tainted(), regs->eflags);
+       print_symbol("EIP is at %s\n", regs->eip);
+       printk("eax: %08lx   ebx: %08lx   ecx: %08lx   edx: %08lx\n",
+@@ -190,23 +224,27 @@ void show_registers(struct pt_regs *regs
+        * time of the fault..
+        */
+       if (in_kernel) {
++              u8 *eip;
+               printk("\nStack: ");
+               show_stack(NULL, (unsigned long*)esp);
+               printk("Code: ");
+-              if(regs->eip < PAGE_OFFSET)
+-                      goto bad;
+-              for(i=0;i<20;i++)
+-              {
+-                      unsigned char c;
+-                      if(__get_user(c, &((unsigned char*)regs->eip)[i])) {
+-bad:
++              eip = (u8 *)regs->eip - 43;
++              for (i = 0; i < 64; i++, eip++) {
++                      unsigned char c = 0xff;
++
++                      if ((user_mode(regs) && get_user(c, eip)) ||
++                          (!user_mode(regs) && __direct_get_user(c, eip))) {
++
+                               printk(" Bad EIP value.");
+                               break;
+                       }
+-                      printk("%02x ", c);
++                      if (eip == (u8 *)regs->eip)
++                              printk("<%02x> ", c);
++                      else
++                              printk("%02x ", c);
+               }
+       }
+       printk("\n");
+@@ -253,12 +291,36 @@ spinlock_t die_lock = SPIN_LOCK_UNLOCKED
+ void die(const char * str, struct pt_regs * regs, long err)
+ {
+       static int die_counter;
++      int nl = 0;
+       console_verbose();
+       spin_lock_irq(&die_lock);
+       bust_spinlocks(1);
+       handle_BUG(regs);
+       printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
++#ifdef CONFIG_PREEMPT
++      printk("PREEMPT ");
++      nl = 1;
++#endif
++#ifdef CONFIG_SMP
++      printk("SMP ");
++      nl = 1;
++#endif
++#ifdef CONFIG_DEBUG_PAGEALLOC
++      printk("DEBUG_PAGEALLOC");
++      nl = 1;
++#endif
++      if (nl)
++              printk("\n");
++#ifdef CONFIG_KGDB
++      /* This is about the only place we want to go to kgdb even if in
++       * user mode.  But we must go in via a trap so within kgdb we will
++       * always be in kernel mode.
++       */
++      if (user_mode(regs))
++              BREAKPOINT;
++#endif
++      CHK_REMOTE_DEBUG(0,SIGTRAP,err,regs,)
+       show_registers(regs);
+       bust_spinlocks(0);
+       spin_unlock_irq(&die_lock);
+@@ -328,6 +390,7 @@ static inline void do_trap(int trapnr, i
+ #define DO_ERROR(trapnr, signr, str, name) \
+ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
+ { \
++      CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,)\
+       do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \
+ }
+@@ -345,7 +408,9 @@ asmlinkage void do_##name(struct pt_regs
+ #define DO_VM86_ERROR(trapnr, signr, str, name) \
+ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
+ { \
++      CHK_REMOTE_DEBUG(trapnr, signr, error_code,regs, return)\
+       do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \
++      return; \
+ }
+ #define DO_VM86_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
+@@ -388,8 +453,10 @@ gp_in_vm86:
+       return;
+ gp_in_kernel:
+-      if (!fixup_exception(regs))
++      if (!fixup_exception(regs)){
++              CHK_REMOTE_DEBUG(13,SIGSEGV,error_code,regs,)
+               die("general protection fault", regs, error_code);
++      }
+ }
+ static void mem_parity_error(unsigned char reason, struct pt_regs * regs)
+@@ -528,10 +595,18 @@ asmlinkage void do_debug(struct pt_regs 
+       if (regs->eflags & X86_EFLAGS_IF)
+               local_irq_enable();
+-      /* Mask out spurious debug traps due to lazy DR7 setting */
++      /*
++       * Mask out spurious debug traps due to lazy DR7 setting or
++       * due to 4G/4G kernel mode:
++       */
+       if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
+               if (!tsk->thread.debugreg[7])
+                       goto clear_dr7;
++              if (!user_mode(regs)) {
++                      // restore upon return-to-userspace:
++                      set_thread_flag(TIF_DB7);
++                      goto clear_dr7;
++              }
+       }
+       if (regs->eflags & VM_MASK)
+@@ -551,8 +626,18 @@ asmlinkage void do_debug(struct pt_regs 
+                * allowing programs to debug themselves without the ptrace()
+                * interface.
+                */
++#ifdef CONFIG_KGDB
++              /*
++               * I think this is the only "real" case of a TF in the kernel
++               * that really belongs to user space.  Others are
++               * "Ours all ours!"
++               */
++              if (((regs->xcs & 3) == 0) && ((void *)regs->eip == sysenter_entry))
++                      goto clear_TF_reenable;
++#else
+               if ((regs->xcs & 3) == 0)
+                       goto clear_TF_reenable;
++#endif
+               if ((tsk->ptrace & (PT_DTRACE|PT_PTRACED)) == PT_DTRACE)
+                       goto clear_TF;
+       }
+@@ -564,6 +649,17 @@ asmlinkage void do_debug(struct pt_regs 
+       info.si_errno = 0;
+       info.si_code = TRAP_BRKPT;
+       
++#ifdef CONFIG_KGDB
++        /*
++       * If this is a kernel mode trap, we need to reset db7 to allow us
++       * to continue sanely ALSO skip the signal delivery
++         */
++      if ((regs->xcs & 3) == 0)
++              goto clear_dr7;
++
++        /* if not kernel, allow ints but only if they were on */
++       if ( regs->eflags & 0x200) local_irq_enable();
++#endif
+       /* If this is a kernel mode trap, save the user PC on entry to 
+        * the kernel, that's what the debugger can make sense of.
+        */
+@@ -578,6 +674,7 @@ clear_dr7:
+       __asm__("movl %0,%%db7"
+               : /* no output */
+               : "r" (0));
++      CHK_REMOTE_DEBUG(1,SIGTRAP,error_code,regs,)
+       return;
+ debug_vm86:
+@@ -773,19 +870,53 @@ asmlinkage void math_emulate(long arg)
+ #endif /* CONFIG_MATH_EMULATION */
+-#ifdef CONFIG_X86_F00F_BUG
+-void __init trap_init_f00f_bug(void)
++void __init trap_init_virtual_IDT(void)
+ {
+-      __set_fixmap(FIX_F00F_IDT, __pa(&idt_table), PAGE_KERNEL_RO);
+-
+       /*
+-       * Update the IDT descriptor and reload the IDT so that
+-       * it uses the read-only mapped virtual address.
++       * "idt" is magic - it overlaps the idt_descr
++       * variable so that updating idt will automatically
++       * update the idt descriptor..
+        */
+-      idt_descr.address = fix_to_virt(FIX_F00F_IDT);
++      __set_fixmap(FIX_IDT, __pa(&idt_table), PAGE_KERNEL_RO);
++      idt_descr.address = __fix_to_virt(FIX_IDT);
++
+       __asm__ __volatile__("lidt %0" : : "m" (idt_descr));
+ }
++
++void __init trap_init_virtual_GDT(void)
++{
++      int cpu = smp_processor_id();
++      struct Xgt_desc_struct *gdt_desc = cpu_gdt_descr + cpu;
++      struct Xgt_desc_struct tmp_desc = {0, 0};
++      struct tss_struct * t;
++
++      __asm__ __volatile__("sgdt %0": "=m" (tmp_desc): :"memory");
++
++#ifdef CONFIG_X86_HIGH_ENTRY
++      if (!cpu) {
++              __set_fixmap(FIX_GDT_0, __pa(cpu_gdt_table), PAGE_KERNEL);
++              __set_fixmap(FIX_GDT_1, __pa(cpu_gdt_table) + PAGE_SIZE, PAGE_KERNEL);
++              __set_fixmap(FIX_TSS_0, __pa(init_tss), PAGE_KERNEL);
++              __set_fixmap(FIX_TSS_1, __pa(init_tss) + 1*PAGE_SIZE, PAGE_KERNEL);
++              __set_fixmap(FIX_TSS_2, __pa(init_tss) + 2*PAGE_SIZE, PAGE_KERNEL);
++              __set_fixmap(FIX_TSS_3, __pa(init_tss) + 3*PAGE_SIZE, PAGE_KERNEL);
++      }
++
++      gdt_desc->address = __fix_to_virt(FIX_GDT_0) + sizeof(cpu_gdt_table[0]) * cpu;
++#else
++      gdt_desc->address = (unsigned long)cpu_gdt_table[cpu];
++#endif
++      __asm__ __volatile__("lgdt %0": "=m" (*gdt_desc));
++
++#ifdef CONFIG_X86_HIGH_ENTRY
++      t = (struct tss_struct *) __fix_to_virt(FIX_TSS_0) + cpu;
++#else
++      t = init_tss + cpu;
+ #endif
++      set_tss_desc(cpu, t);
++      cpu_gdt_table[cpu][GDT_ENTRY_TSS].b &= 0xfffffdff;
++      load_TR_desc();
++}
+ #define _set_gate(gate_addr,type,dpl,addr,seg) \
+ do { \
+@@ -812,20 +943,26 @@ void set_intr_gate(unsigned int n, void 
+       _set_gate(idt_table+n,14,0,addr,__KERNEL_CS);
+ }
+-static void __init set_trap_gate(unsigned int n, void *addr)
++void __init set_trap_gate(unsigned int n, void *addr)
+ {
+       _set_gate(idt_table+n,15,0,addr,__KERNEL_CS);
+ }
+-static void __init set_system_gate(unsigned int n, void *addr)
++void __init set_system_gate(unsigned int n, void *addr)
+ {
+       _set_gate(idt_table+n,15,3,addr,__KERNEL_CS);
+ }
+-static void __init set_call_gate(void *a, void *addr)
++void __init set_call_gate(void *a, void *addr)
+ {
+       _set_gate(a,12,3,addr,__KERNEL_CS);
+ }
++#ifdef CONFIG_KGDB
++void set_intr_usr_gate(unsigned int n, void *addr)
++{
++      _set_gate(idt_table+n,14,3,addr,__KERNEL_CS);
++}
++#endif
+ static void __init set_task_gate(unsigned int n, unsigned int gdt_entry)
+ {
+@@ -844,11 +981,16 @@ void __init trap_init(void)
+ #ifdef CONFIG_X86_LOCAL_APIC
+       init_apic_mappings();
+ #endif
++      init_entry_mappings();
+       set_trap_gate(0,&divide_error);
+       set_intr_gate(1,&debug);
+       set_intr_gate(2,&nmi);
++#ifndef CONFIG_KGDB
+       set_system_gate(3,&int3);       /* int3-5 can be called from all */
++#else
++      set_intr_usr_gate(3,&int3);     /* int3-5 can be called from all */
++#endif
+       set_system_gate(4,&overflow);
+       set_system_gate(5,&bounds);
+       set_trap_gate(6,&invalid_op);
+--- linux-2.6.0-test6/arch/i386/kernel/vm86.c  2003-06-14 12:17:58.000000000 -0700
++++ 25/arch/i386/kernel/vm86.c 2003-10-05 00:36:48.000000000 -0700
+@@ -117,7 +117,7 @@ struct pt_regs * save_v86_state(struct k
+       tss = init_tss + get_cpu();
+       current->thread.esp0 = current->thread.saved_esp0;
+-      load_esp0(tss, current->thread.esp0);
++      load_esp0(tss, virtual_esp0(current));
+       current->thread.saved_esp0 = 0;
+       put_cpu();
+@@ -294,7 +294,8 @@ static void do_sys_vm86(struct kernel_vm
+       asm volatile("movl %%gs,%0":"=m" (tsk->thread.saved_gs));
+       tss = init_tss + get_cpu();
+-      tss->esp0 = tsk->thread.esp0 = (unsigned long) &info->VM86_TSS_ESP0;
++      tsk->thread.esp0 = (unsigned long) &info->VM86_TSS_ESP0;
++      tss->esp0 = virtual_esp0(tsk);
+       disable_sysenter(tss);
+       put_cpu();
+--- linux-2.6.0-test6/arch/i386/kernel/vmlinux.lds.S   2003-08-22 19:23:40.000000000 -0700
++++ 25/arch/i386/kernel/vmlinux.lds.S  2003-10-05 00:36:48.000000000 -0700
+@@ -3,6 +3,9 @@
+  */
+ #include <asm-generic/vmlinux.lds.h>
++#include <linux/config.h>
++#include <asm/page.h>
++#include <asm/asm_offsets.h>
+       
+ OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+ OUTPUT_ARCH(i386)
+@@ -10,7 +13,7 @@ ENTRY(startup_32)
+ jiffies = jiffies_64;
+ SECTIONS
+ {
+-  . = 0xC0000000 + 0x100000;
++  . = __PAGE_OFFSET + 0x100000;
+   /* read-only */
+   _text = .;                  /* Text and read-only data */
+   .text : {
+@@ -19,6 +22,19 @@ SECTIONS
+       *(.gnu.warning)
+       } = 0x9090
++#ifdef CONFIG_X86_4G
++  . = ALIGN(PAGE_SIZE_asm);
++  __entry_tramp_start = .;
++  . = FIX_ENTRY_TRAMPOLINE_0_addr;
++  __start___entry_text = .;
++  .entry.text : AT (__entry_tramp_start) { *(.entry.text) }
++  __entry_tramp_end = __entry_tramp_start + SIZEOF(.entry.text);
++  . = __entry_tramp_end;
++  . = ALIGN(PAGE_SIZE_asm);
++#else
++  .entry.text : { *(.entry.text) }
++#endif
++
+   _etext = .;                 /* End of text section */
+   . = ALIGN(16);              /* Exception table */
+@@ -34,15 +50,12 @@ SECTIONS
+       CONSTRUCTORS
+       }
+-  . = ALIGN(4096);
++  . = ALIGN(PAGE_SIZE_asm);
+   __nosave_begin = .;
+   .data_nosave : { *(.data.nosave) }
+-  . = ALIGN(4096);
++  . = ALIGN(PAGE_SIZE_asm);
+   __nosave_end = .;
+-  . = ALIGN(4096);
+-  .data.page_aligned : { *(.data.idt) }
+-
+   . = ALIGN(32);
+   .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+@@ -52,7 +65,7 @@ SECTIONS
+   .data.init_task : { *(.data.init_task) }
+   /* will be freed after init */
+-  . = ALIGN(4096);            /* Init code and data */
++  . = ALIGN(PAGE_SIZE_asm);           /* Init code and data */
+   __init_begin = .;
+   .init.text : { 
+       _sinittext = .;
+@@ -91,7 +104,7 @@ SECTIONS
+      from .altinstructions and .eh_frame */
+   .exit.text : { *(.exit.text) }
+   .exit.data : { *(.exit.data) }
+-  . = ALIGN(4096);
++  . = ALIGN(PAGE_SIZE_asm);
+   __initramfs_start = .;
+   .init.ramfs : { *(.init.ramfs) }
+   __initramfs_end = .;
+@@ -99,10 +112,22 @@ SECTIONS
+   __per_cpu_start = .;
+   .data.percpu  : { *(.data.percpu) }
+   __per_cpu_end = .;
+-  . = ALIGN(4096);
++  . = ALIGN(PAGE_SIZE_asm);
+   __init_end = .;
+   /* freed after init ends here */
+-      
++
++  . = ALIGN(PAGE_SIZE_asm);
++  .data.page_aligned_tss : { *(.data.tss) }
++
++  . = ALIGN(PAGE_SIZE_asm);
++  .data.page_aligned_default_ldt : { *(.data.default_ldt) }
++
++  . = ALIGN(PAGE_SIZE_asm);
++  .data.page_aligned_idt : { *(.data.idt) }
++
++  . = ALIGN(PAGE_SIZE_asm);
++  .data.page_aligned_gdt : { *(.data.gdt) }
++
+   __bss_start = .;            /* BSS */
+   .bss : { *(.bss) }
+   __bss_stop = .; 
+@@ -122,4 +147,6 @@ SECTIONS
+   .stab.index 0 : { *(.stab.index) }
+   .stab.indexstr 0 : { *(.stab.indexstr) }
+   .comment 0 : { *(.comment) }
++
++
+ }
+--- linux-2.6.0-test6/arch/i386/kernel/vsyscall.lds    2003-06-14 12:18:07.000000000 -0700
++++ 25/arch/i386/kernel/vsyscall.lds   2003-10-05 00:36:48.000000000 -0700
+@@ -5,7 +5,7 @@
+  */
+ /* This must match <asm/fixmap.h>.  */
+-VSYSCALL_BASE = 0xffffe000;
++VSYSCALL_BASE = 0xffffd000;
+ SECTIONS
+ {
+--- linux-2.6.0-test6/arch/i386/kernel/vsyscall-sysenter.S     2003-06-14 12:18:08.000000000 -0700
++++ 25/arch/i386/kernel/vsyscall-sysenter.S    2003-10-05 00:36:48.000000000 -0700
+@@ -7,6 +7,11 @@
+       .type __kernel_vsyscall,@function
+ __kernel_vsyscall:
+ .LSTART_vsyscall:
++      cmpl $192, %eax
++      jne 1f
++      int $0x80
++      ret
++1:
+       push %ecx
+ .Lpush_ecx:
+       push %edx
+--- linux-2.6.0-test6/arch/i386/lib/checksum.S 2003-06-14 12:18:30.000000000 -0700
++++ 25/arch/i386/lib/checksum.S        2003-10-05 00:36:48.000000000 -0700
+@@ -280,14 +280,14 @@ unsigned int csum_partial_copy_generic (
+       .previous
+ .align 4
+-.globl csum_partial_copy_generic
++.globl direct_csum_partial_copy_generic
+                               
+ #ifndef CONFIG_X86_USE_PPRO_CHECKSUM
+ #define ARGBASE 16            
+ #define FP            12
+               
+-csum_partial_copy_generic:
++direct_csum_partial_copy_generic:
+       subl  $4,%esp   
+       pushl %edi
+       pushl %esi
+@@ -422,7 +422,7 @@ DST(       movb %cl, (%edi)        )
+ #define ARGBASE 12
+               
+-csum_partial_copy_generic:
++direct_csum_partial_copy_generic:
+       pushl %ebx
+       pushl %edi
+       pushl %esi
+--- linux-2.6.0-test6/arch/i386/lib/dec_and_lock.c     2003-06-26 22:07:23.000000000 -0700
++++ 25/arch/i386/lib/dec_and_lock.c    2003-10-05 00:36:40.000000000 -0700
+@@ -10,6 +10,7 @@
+ #include <linux/spinlock.h>
+ #include <asm/atomic.h>
++#ifndef ATOMIC_DEC_AND_LOCK
+ int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
+ {
+       int counter;
+@@ -38,3 +39,5 @@ slow_path:
+       spin_unlock(lock);
+       return 0;
+ }
++#endif
++
+--- linux-2.6.0-test6/arch/i386/lib/getuser.S  2003-06-14 12:17:56.000000000 -0700
++++ 25/arch/i386/lib/getuser.S 2003-10-05 00:36:48.000000000 -0700
+@@ -9,6 +9,7 @@
+  * return value.
+  */
+ #include <asm/thread_info.h>
++#include <asm/asm_offsets.h>
+ /*
+@@ -28,7 +29,7 @@
+ .globl __get_user_1
+ __get_user_1:
+       GET_THREAD_INFO(%edx)
+-      cmpl TI_ADDR_LIMIT(%edx),%eax
++      cmpl TI_addr_limit(%edx),%eax
+       jae bad_get_user
+ 1:    movzbl (%eax),%edx
+       xorl %eax,%eax
+@@ -40,7 +41,7 @@ __get_user_2:
+       addl $1,%eax
+       jc bad_get_user
+       GET_THREAD_INFO(%edx)
+-      cmpl TI_ADDR_LIMIT(%edx),%eax
++      cmpl TI_addr_limit(%edx),%eax
+       jae bad_get_user
+ 2:    movzwl -1(%eax),%edx
+       xorl %eax,%eax
+@@ -52,7 +53,7 @@ __get_user_4:
+       addl $3,%eax
+       jc bad_get_user
+       GET_THREAD_INFO(%edx)
+-      cmpl TI_ADDR_LIMIT(%edx),%eax
++      cmpl TI_addr_limit(%edx),%eax
+       jae bad_get_user
+ 3:    movl -3(%eax),%edx
+       xorl %eax,%eax
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/arch/i386/lib/kgdb_serial.c     2003-10-05 00:33:44.000000000 -0700
+@@ -0,0 +1,499 @@
++/*
++ * Serial interface GDB stub
++ *
++ * Written (hacked together) by David Grothe (dave@gcom.com)
++ * Modified to allow invokation early in boot see also
++ * kgdb.h for instructions by George Anzinger(george@mvista.com)
++ * Modified to handle debugging over ethernet by Robert Walsh
++ * <rjwalsh@durables.org> and wangdi <wangdi@clusterfs.com>, based on
++ * code by San Mehat.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/errno.h>
++#include <linux/signal.h>
++#include <linux/sched.h>
++#include <linux/timer.h>
++#include <linux/interrupt.h>
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++#include <linux/serial.h>
++#include <linux/serial_reg.h>
++#include <linux/config.h>
++#include <linux/major.h>
++#include <linux/string.h>
++#include <linux/fcntl.h>
++#include <linux/ptrace.h>
++#include <linux/ioport.h>
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/highmem.h>
++#include <asm/system.h>
++#include <asm/io.h>
++#include <asm/segment.h>
++#include <asm/bitops.h>
++#include <asm/system.h>
++#include <asm/kgdb_local.h>
++#ifdef CONFIG_KGDB_USER_CONSOLE
++extern void kgdb_console_finit(void);
++#endif
++#define PRNT_off
++#define TEST_EXISTANCE
++#ifdef PRNT
++#define dbprintk(s) printk s
++#else
++#define dbprintk(s)
++#endif
++#define TEST_INTERRUPT_off
++#ifdef TEST_INTERRUPT
++#define intprintk(s) printk s
++#else
++#define intprintk(s)
++#endif
++
++#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
++
++#define       GDB_BUF_SIZE    512     /* power of 2, please */
++
++static char gdb_buf[GDB_BUF_SIZE];
++static int gdb_buf_in_inx;
++static atomic_t gdb_buf_in_cnt;
++static int gdb_buf_out_inx;
++
++struct async_struct *gdb_async_info;
++static int gdb_async_irq;
++
++#define outb_px(a,b) outb_p(b,a)
++
++static void program_uart(struct async_struct *info);
++static void write_char(struct async_struct *info, int chr);
++/*
++ * Get a byte from the hardware data buffer and return it
++ */
++static int
++read_data_bfr(struct async_struct *info)
++{
++      char it = inb_p(info->port + UART_LSR);
++
++      if (it & UART_LSR_DR)
++              return (inb_p(info->port + UART_RX));
++      /*
++       * If we have a framing error assume somebody messed with
++       * our uart.  Reprogram it and send '-' both ways...
++       */
++      if (it & 0xc) {
++              program_uart(info);
++              write_char(info, '-');
++              return ('-');
++      }
++      return (-1);
++
++}                             /* read_data_bfr */
++
++/*
++ * Get a char if available, return -1 if nothing available.
++ * Empty the receive buffer first, then look at the interface hardware.
++
++ * Locking here is a bit of a problem.        We MUST not lock out communication
++ * if we are trying to talk to gdb about a kgdb entry.        ON the other hand
++ * we can loose chars in the console pass thru if we don't lock.  It is also
++ * possible that we could hold the lock or be waiting for it when kgdb
++ * NEEDS to talk.  Since kgdb locks down the world, it does not need locks.
++ * We do, of course have possible issues with interrupting a uart operation,
++ * but we will just depend on the uart status to help keep that straight.
++
++ */
++static spinlock_t uart_interrupt_lock = SPIN_LOCK_UNLOCKED;
++#ifdef CONFIG_SMP
++extern spinlock_t kgdb_spinlock;
++#endif
++
++static int
++read_char(struct async_struct *info)
++{
++      int chr;
++      unsigned long flags;
++      local_irq_save(flags);
++#ifdef CONFIG_SMP
++      if (!spin_is_locked(&kgdb_spinlock)) {
++              spin_lock(&uart_interrupt_lock);
++      }
++#endif
++      if (atomic_read(&gdb_buf_in_cnt) != 0) {        /* intr routine has q'd chars */
++              chr = gdb_buf[gdb_buf_out_inx++];
++              gdb_buf_out_inx &= (GDB_BUF_SIZE - 1);
++              atomic_dec(&gdb_buf_in_cnt);
++      } else {
++              chr = read_data_bfr(info);
++      }
++#ifdef CONFIG_SMP
++      if (!spin_is_locked(&kgdb_spinlock)) {
++              spin_unlock(&uart_interrupt_lock);
++      }
++#endif
++      local_irq_restore(flags);
++      return (chr);
++}
++
++/*
++ * Wait until the interface can accept a char, then write it.
++ */
++static void
++write_char(struct async_struct *info, int chr)
++{
++      while (!(inb_p(info->port + UART_LSR) & UART_LSR_THRE)) ;
++
++      outb_p(chr, info->port + UART_TX);
++
++}                             /* write_char */
++
++/*
++ * Mostly we don't need a spinlock, but since the console goes
++ * thru here with interrutps on, well, we need to catch those
++ * chars.
++ */
++/*
++ * This is the receiver interrupt routine for the GDB stub.
++ * It will receive a limited number of characters of input
++ * from the gdb  host machine and save them up in a buffer.
++ *
++ * When the gdb stub routine tty_getDebugChar() is called it
++ * draws characters out of the buffer until it is empty and
++ * then reads directly from the serial port.
++ *
++ * We do not attempt to write chars from the interrupt routine
++ * since the stubs do all of that via tty_putDebugChar() which
++ * writes one byte after waiting for the interface to become
++ * ready.
++ *
++ * The debug stubs like to run with interrupts disabled since,
++ * after all, they run as a consequence of a breakpoint in
++ * the kernel.
++ *
++ * Perhaps someone who knows more about the tty driver than I
++ * care to learn can make this work for any low level serial
++ * driver.
++ */
++static irqreturn_t
++gdb_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++      struct async_struct *info;
++      unsigned long flags;
++
++      info = gdb_async_info;
++      if (!info || !info->tty || irq != gdb_async_irq)
++              return IRQ_NONE;
++
++      local_irq_save(flags);
++      spin_lock(&uart_interrupt_lock);
++      do {
++              int chr = read_data_bfr(info);
++              intprintk(("Debug char on int: %x hex\n", chr));
++              if (chr < 0)
++                      continue;
++
++              if (chr == 3) { /* Ctrl-C means remote interrupt */
++                      BREAKPOINT;
++                      continue;
++              }
++
++              if (atomic_read(&gdb_buf_in_cnt) >= GDB_BUF_SIZE) {
++                      /* buffer overflow tosses early char */
++                      read_char(info);
++              }
++              gdb_buf[gdb_buf_in_inx++] = chr;
++              gdb_buf_in_inx &= (GDB_BUF_SIZE - 1);
++      } while (inb_p(info->port + UART_IIR) & UART_IIR_RDI);
++      spin_unlock(&uart_interrupt_lock);
++      local_irq_restore(flags);
++      return IRQ_HANDLED;
++}                             /* gdb_interrupt */
++
++/*
++ * Just a NULL routine for testing.
++ */
++void
++gdb_null(void)
++{
++}                             /* gdb_null */
++
++/* These structure are filled in with values defined in asm/kgdb_local.h
++ */
++static struct serial_state state = SB_STATE;
++static struct async_struct local_info = SB_INFO;
++static int ok_to_enable_ints = 0;
++static void kgdb_enable_ints_now(void);
++
++extern char *kgdb_version;
++/*
++ * Hook an IRQ for KGDB.
++ *
++ * This routine is called from tty_putDebugChar, below.
++ */
++static int ints_disabled = 1;
++int
++gdb_hook_interrupt(struct async_struct *info, int verb)
++{
++      struct serial_state *state = info->state;
++      unsigned long flags;
++      int port;
++#ifdef TEST_EXISTANCE
++      int scratch, scratch2;
++#endif
++
++      /* The above fails if memory managment is not set up yet.
++       * Rather than fail the set up, just keep track of the fact
++       * and pick up the interrupt thing later.
++       */
++      gdb_async_info = info;
++      port = gdb_async_info->port;
++      gdb_async_irq = state->irq;
++      if (verb) {
++              printk("kgdb %s : port =%x, IRQ=%d, divisor =%d\n",
++                     kgdb_version,
++                     port,
++                     gdb_async_irq, gdb_async_info->state->custom_divisor);
++      }
++      local_irq_save(flags);
++#ifdef TEST_EXISTANCE
++      /* Existance test */
++      /* Should not need all this, but just in case.... */
++
++      scratch = inb_p(port + UART_IER);
++      outb_px(port + UART_IER, 0);
++      outb_px(0xff, 0x080);
++      scratch2 = inb_p(port + UART_IER);
++      outb_px(port + UART_IER, scratch);
++      if (scratch2) {
++              printk
++                  ("gdb_hook_interrupt: Could not clear IER, not a UART!\n");
++              local_irq_restore(flags);
++              return 1;       /* We failed; there's nothing here */
++      }
++      scratch2 = inb_p(port + UART_LCR);
++      outb_px(port + UART_LCR, 0xBF); /* set up for StarTech test */
++      outb_px(port + UART_EFR, 0);    /* EFR is the same as FCR */
++      outb_px(port + UART_LCR, 0);
++      outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO);
++      scratch = inb_p(port + UART_IIR) >> 6;
++      if (scratch == 1) {
++              printk("gdb_hook_interrupt: Undefined UART type!"
++                     "  Not a UART! \n");
++              local_irq_restore(flags);
++              return 1;
++      } else {
++              dbprintk(("gdb_hook_interrupt: UART type "
++                        "is %d where 0=16450, 2=16550 3=16550A\n", scratch));
++      }
++      scratch = inb_p(port + UART_MCR);
++      outb_px(port + UART_MCR, UART_MCR_LOOP | scratch);
++      outb_px(port + UART_MCR, UART_MCR_LOOP | 0x0A);
++      scratch2 = inb_p(port + UART_MSR) & 0xF0;
++      outb_px(port + UART_MCR, scratch);
++      if (scratch2 != 0x90) {
++              printk("gdb_hook_interrupt: "
++                     "Loop back test failed! Not a UART!\n");
++              local_irq_restore(flags);
++              return scratch2 + 1000; /* force 0 to fail */
++      }
++#endif                                /* test existance */
++      program_uart(info);
++      local_irq_restore(flags);
++
++      return (0);
++
++}                             /* gdb_hook_interrupt */
++
++static void
++program_uart(struct async_struct *info)
++{
++      int port = info->port;
++
++      (void) inb_p(port + UART_RX);
++      outb_px(port + UART_IER, 0);
++
++      (void) inb_p(port + UART_RX);   /* serial driver comments say */
++      (void) inb_p(port + UART_IIR);  /* this clears the interrupt regs */
++      (void) inb_p(port + UART_MSR);
++      outb_px(port + UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB);
++      outb_px(port + UART_DLL, info->state->custom_divisor & 0xff);   /* LS */
++      outb_px(port + UART_DLM, info->state->custom_divisor >> 8);     /* MS  */
++      outb_px(port + UART_MCR, info->MCR);
++
++      outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1 | UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR);        /* set fcr */
++      outb_px(port + UART_LCR, UART_LCR_WLEN8);       /* reset DLAB */
++      outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1);    /* set fcr */
++      if (!ints_disabled) {
++              intprintk(("KGDB: Sending %d to port %x offset %d\n",
++                         gdb_async_info->IER,
++                         (int) gdb_async_info->port, UART_IER));
++              outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER);
++      }
++      return;
++}
++
++/*
++ * tty_getDebugChar
++ *
++ * This is a GDB stub routine.        It waits for a character from the
++ * serial interface and then returns it.  If there is no serial
++ * interface connection then it returns a bogus value which will
++ * almost certainly cause the system to hang.  In the
++ */
++int kgdb_in_isr = 0;
++int kgdb_in_lsr = 0;
++extern spinlock_t kgdb_spinlock;
++
++/* Caller takes needed protections */
++
++int
++tty_getDebugChar(void)
++{
++      volatile int chr, dum, time, end_time;
++
++      dbprintk(("tty_getDebugChar(port %x): ", gdb_async_info->port));
++
++      if (gdb_async_info == NULL) {
++              gdb_hook_interrupt(&local_info, 0);
++      }
++      /*
++       * This trick says if we wait a very long time and get
++       * no char, return the -1 and let the upper level deal
++       * with it.
++       */
++      rdtsc(dum, time);
++      end_time = time + 2;
++      while (((chr = read_char(gdb_async_info)) == -1) &&
++             (end_time - time) > 0) {
++              rdtsc(dum, time);
++      };
++      /*
++       * This covers our butts if some other code messes with
++       * our uart, hay, it happens :o)
++       */
++      if (chr == -1)
++              program_uart(gdb_async_info);
++
++      dbprintk(("%c\n", chr > ' ' && chr < 0x7F ? chr : ' '));
++      return (chr);
++
++}                             /* tty_getDebugChar */
++
++static int count = 3;
++static spinlock_t one_at_atime = SPIN_LOCK_UNLOCKED;
++
++static int __init
++kgdb_enable_ints(void)
++{
++      if (kgdb_eth != -1) {
++              return 0;
++      }
++      if (gdb_async_info == NULL) {
++              gdb_hook_interrupt(&local_info, 1);
++      }
++      ok_to_enable_ints = 1;
++      kgdb_enable_ints_now();
++#ifdef CONFIG_KGDB_USER_CONSOLE
++      kgdb_console_finit();
++#endif
++      return 0;
++}
++
++#ifdef CONFIG_SERIAL_8250
++void shutdown_for_kgdb(struct async_struct *gdb_async_info);
++#endif
++
++#ifdef CONFIG_DISCONTIGMEM
++static inline int kgdb_mem_init_done(void)
++{
++      return highmem_start_page != NULL;
++}
++#else
++static inline int kgdb_mem_init_done(void)
++{
++      return max_mapnr != 0;
++}
++#endif
++
++static void
++kgdb_enable_ints_now(void)
++{
++      if (!spin_trylock(&one_at_atime))
++              return;
++      if (!ints_disabled)
++              goto exit;
++      if (kgdb_mem_init_done() &&
++                      ints_disabled) {        /* don't try till mem init */
++#ifdef CONFIG_SERIAL_8250
++              /*
++               * The ifdef here allows the system to be configured
++               * without the serial driver.
++               * Don't make it a module, however, it will steal the port
++               */
++              shutdown_for_kgdb(gdb_async_info);
++#endif
++              ints_disabled = request_irq(gdb_async_info->state->irq,
++                                          gdb_interrupt,
++                                          IRQ_T(gdb_async_info),
++                                          "KGDB-stub", NULL);
++              intprintk(("KGDB: request_irq returned %d\n", ints_disabled));
++      }
++      if (!ints_disabled) {
++              intprintk(("KGDB: Sending %d to port %x offset %d\n",
++                         gdb_async_info->IER,
++                         (int) gdb_async_info->port, UART_IER));
++              outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER);
++      }
++      exit:
++      spin_unlock(&one_at_atime);
++}
++
++/*
++ * tty_putDebugChar
++ *
++ * This is a GDB stub routine.        It waits until the interface is ready
++ * to transmit a char and then sends it.  If there is no serial
++ * interface connection then it simply returns to its caller, having
++ * pretended to send the char.        Caller takes needed protections.
++ */
++void
++tty_putDebugChar(int chr)
++{
++      dbprintk(("tty_putDebugChar(port %x): chr=%02x '%c', ints_on=%d\n",
++                gdb_async_info->port,
++                chr,
++                chr > ' ' && chr < 0x7F ? chr : ' ', ints_disabled ? 0 : 1));
++
++      if (gdb_async_info == NULL) {
++              gdb_hook_interrupt(&local_info, 0);
++      }
++
++      write_char(gdb_async_info, chr);        /* this routine will wait */
++      count = (chr == '#') ? 0 : count + 1;
++      if ((count == 2)) {     /* try to enable after */
++              if (ints_disabled & ok_to_enable_ints)
++                      kgdb_enable_ints_now(); /* try to enable after */
++
++              /* We do this a lot because, well we really want to get these
++               * interrupts.  The serial driver will clear these bits when it
++               * initializes the chip.  Every thing else it does is ok,
++               * but this.
++               */
++              if (!ints_disabled) {
++                      outb_px(gdb_async_info->port + UART_IER,
++                              gdb_async_info->IER);
++              }
++      }
++
++}                             /* tty_putDebugChar */
++
++/*
++ * This does nothing for the serial port, since it doesn't buffer.
++ */
++
++void tty_flushDebugChar(void)
++{
++}
++
++module_init(kgdb_enable_ints);
+--- linux-2.6.0-test6/arch/i386/lib/Makefile   2003-06-26 22:07:23.000000000 -0700
++++ 25/arch/i386/lib/Makefile  2003-10-05 00:33:38.000000000 -0700
+@@ -9,4 +9,5 @@ lib-y = checksum.o delay.o \
+ lib-$(CONFIG_X86_USE_3DNOW) += mmx.o
+ lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o
++lib-$(CONFIG_KGDB) += kgdb_serial.o
+ lib-$(CONFIG_DEBUG_IOVIRT)  += iodebug.o
+--- linux-2.6.0-test6/arch/i386/lib/usercopy.c 2003-08-22 19:23:40.000000000 -0700
++++ 25/arch/i386/lib/usercopy.c        2003-10-05 00:36:48.000000000 -0700
+@@ -76,7 +76,7 @@ do {                                                                    \
+  * and returns @count.
+  */
+ long
+-__strncpy_from_user(char *dst, const char __user *src, long count)
++__direct_strncpy_from_user(char *dst, const char __user *src, long count)
+ {
+       long res;
+       __do_strncpy_from_user(dst, src, count, res);
+@@ -102,7 +102,7 @@ __strncpy_from_user(char *dst, const cha
+  * and returns @count.
+  */
+ long
+-strncpy_from_user(char *dst, const char __user *src, long count)
++direct_strncpy_from_user(char *dst, const char __user *src, long count)
+ {
+       long res = -EFAULT;
+       if (access_ok(VERIFY_READ, src, 1))
+@@ -147,7 +147,7 @@ do {                                                                       \
+  * On success, this will be zero.
+  */
+ unsigned long
+-clear_user(void __user *to, unsigned long n)
++direct_clear_user(void __user *to, unsigned long n)
+ {
+       might_sleep();
+       if (access_ok(VERIFY_WRITE, to, n))
+@@ -167,7 +167,7 @@ clear_user(void __user *to, unsigned lon
+  * On success, this will be zero.
+  */
+ unsigned long
+-__clear_user(void __user *to, unsigned long n)
++__direct_clear_user(void __user *to, unsigned long n)
+ {
+       __do_clear_user(to, n);
+       return n;
+@@ -184,7 +184,7 @@ __clear_user(void __user *to, unsigned l
+  * On exception, returns 0.
+  * If the string is too long, returns a value greater than @n.
+  */
+-long strnlen_user(const char __user *s, long n)
++long direct_strnlen_user(const char __user *s, long n)
+ {
+       unsigned long mask = -__addr_ok(s);
+       unsigned long res, tmp;
+@@ -573,3 +573,4 @@ unsigned long __copy_from_user_ll(void *
+               n = __copy_user_zeroing_intel(to, (const void *) from, n);
+       return n;
+ }
++
+--- linux-2.6.0-test6/arch/i386/Makefile       2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/i386/Makefile      2003-10-05 00:33:38.000000000 -0700
+@@ -84,6 +84,9 @@ mcore-$(CONFIG_X86_ES7000)   := mach-es700
+ # default subarch .h files
+ mflags-y += -Iinclude/asm-i386/mach-default
++mflags-$(CONFIG_KGDB) += -gdwarf-2
++mflags-$(CONFIG_KGDB_MORE) += $(shell echo $(CONFIG_KGDB_OPTIONS) | sed -e 's/"//g')
++
+ head-y := arch/i386/kernel/head.o arch/i386/kernel/init_task.o
+ libs-y                                        += arch/i386/lib/
+--- linux-2.6.0-test6/arch/i386/math-emu/fpu_system.h  2003-06-14 12:18:06.000000000 -0700
++++ 25/arch/i386/math-emu/fpu_system.h 2003-10-05 00:36:48.000000000 -0700
+@@ -15,6 +15,7 @@
+ #include <linux/sched.h>
+ #include <linux/kernel.h>
+ #include <linux/mm.h>
++#include <asm/atomic_kmap.h>
+ /* This sets the pointer FPU_info to point to the argument part
+    of the stack frame of math_emulate() */
+@@ -22,7 +23,7 @@
+ /* s is always from a cpu register, and the cpu does bounds checking
+  * during register load --> no further bounds checks needed */
+-#define LDT_DESCRIPTOR(s)     (((struct desc_struct *)current->mm->context.ldt)[(s) >> 3])
++#define LDT_DESCRIPTOR(s)     (((struct desc_struct *)__kmap_atomic_vaddr(KM_LDT_PAGE0))[(s) >> 3])
+ #define SEG_D_SIZE(x)         ((x).b & (3 << 21))
+ #define SEG_G_BIT(x)          ((x).b & (1 << 23))
+ #define SEG_GRANULARITY(x)    (((x).b & (1 << 23)) ? 4096 : 1)
+--- linux-2.6.0-test6/arch/i386/mm/extable.c   2003-06-14 12:18:51.000000000 -0700
++++ 25/arch/i386/mm/extable.c  2003-10-05 00:36:48.000000000 -0700
+@@ -6,6 +6,52 @@
+ #include <linux/module.h>
+ #include <linux/spinlock.h>
+ #include <asm/uaccess.h>
++#include <asm/pgtable.h>
++
++extern struct exception_table_entry __start___ex_table[];
++extern struct exception_table_entry __stop___ex_table[];
++
++/*
++ * The exception table needs to be sorted because we use the macros
++ * which put things into the exception table in a variety of sections
++ * as well as the init section and the main kernel text section.
++ */
++static inline void
++sort_ex_table(struct exception_table_entry *start,
++            struct exception_table_entry *finish)
++{
++      struct exception_table_entry el, *p, *q;
++
++      /* insertion sort */
++      for (p = start + 1; p < finish; ++p) {
++              /* start .. p-1 is sorted */
++              if (p[0].insn < p[-1].insn) {
++                      /* move element p down to its right place */
++                      el = *p;
++                      q = p;
++                      do {
++                              /* el comes before q[-1], move q[-1] up one */
++                              q[0] = q[-1];
++                              --q;
++                      } while (q > start && el.insn < q[-1].insn);
++                      *q = el;
++              }
++      }
++}
++
++void fixup_sort_exception_table(void)
++{
++      struct exception_table_entry *p;
++
++      /*
++       * Fix up the trampoline exception addresses:
++       */
++      for (p = __start___ex_table; p < __stop___ex_table; p++) {
++              p->insn = (unsigned long)(void *)p->insn;
++              p->fixup = (unsigned long)(void *)p->fixup;
++      }
++      sort_ex_table(__start___ex_table, __stop___ex_table);
++}
+ /* Simple binary search */
+ const struct exception_table_entry *
+@@ -15,13 +61,15 @@ search_extable(const struct exception_ta
+ {
+         while (first <= last) {
+               const struct exception_table_entry *mid;
+-              long diff;
+               mid = (last - first) / 2 + first;
+-              diff = mid->insn - value;
+-                if (diff == 0)
++              /*
++               * careful, the distance between entries can be
++               * larger than 2GB:
++               */
++                if (mid->insn == value)
+                         return mid;
+-                else if (diff < 0)
++                else if (mid->insn < value)
+                         first = mid+1;
+                 else
+                         last = mid-1;
+--- linux-2.6.0-test6/arch/i386/mm/fault.c     2003-06-26 22:07:23.000000000 -0700
++++ 25/arch/i386/mm/fault.c    2003-10-05 00:36:50.000000000 -0700
+@@ -19,6 +19,7 @@
+ #include <linux/init.h>
+ #include <linux/tty.h>
+ #include <linux/vt_kern.h>            /* For unblank_screen() */
++#include <linux/highmem.h>
+ #include <linux/module.h>
+ #include <asm/system.h>
+@@ -26,6 +27,7 @@
+ #include <asm/pgalloc.h>
+ #include <asm/hardirq.h>
+ #include <asm/desc.h>
++#include <asm/tlbflush.h>
+ extern void die(const char *,struct pt_regs *,long);
+@@ -55,6 +57,161 @@ void bust_spinlocks(int yes)
+       console_loglevel = loglevel_save;
+ }
++/*
++ * Return EIP plus the CS segment base.  The segment limit is also
++ * adjusted, clamped to the kernel/user address space (whichever is
++ * appropriate), and returned in *eip_limit.
++ *
++ * The segment is checked, because it might have been changed by another
++ * task between the original faulting instruction and here.
++ *
++ * If CS is no longer a valid code segment, or if EIP is beyond the
++ * limit, or if it is a kernel address when CS is not a kernel segment,
++ * then the returned value will be greater than *eip_limit.
++ */
++static inline unsigned long get_segment_eip(struct pt_regs *regs,
++                                          unsigned long *eip_limit)
++{
++      unsigned long eip = regs->eip;
++      unsigned seg = regs->xcs & 0xffff;
++      u32 seg_ar, seg_limit, base, *desc;
++
++      /* The standard kernel/user address space limit. */
++      *eip_limit = (seg & 3) ? USER_DS.seg : KERNEL_DS.seg;
++
++      /* Unlikely, but must come before segment checks. */
++      if (unlikely((regs->eflags & VM_MASK) != 0))
++              return eip + (seg << 4);
++
++      /* By far the commonest cases. */
++      if (likely(seg == __USER_CS || seg == __KERNEL_CS))
++              return eip;
++
++      /* Check the segment exists, is within the current LDT/GDT size,
++         that kernel/user (ring 0..3) has the appropriate privilege,
++         that it's a code segment, and get the limit. */
++      __asm__ ("larl %3,%0; lsll %3,%1"
++               : "=&r" (seg_ar), "=r" (seg_limit) : "0" (0), "rm" (seg));
++      if ((~seg_ar & 0x9800) || eip > seg_limit) {
++              *eip_limit = 0;
++              return 1;        /* So that returned eip > *eip_limit. */
++      }
++
++      /* Get the GDT/LDT descriptor base.
++         When you look for races in this code remember that
++         LDT and other horrors are only used in user space. */
++      if (seg & (1<<2)) {
++              /* Must lock the LDT while reading it. */
++              down(&current->mm->context.sem);
++#if 1
++              /* horrible hack for 4/4 disabled kernels.
++                 I'm not quite sure what the TLB flush is good for,
++                 it's mindlessly copied from the read_ldt code */
++              __flush_tlb_global();
++              desc = kmap(current->mm->context.ldt_pages[(seg & ~7)/PAGE_SIZE]);
++              desc = (void *)desc + ((seg & ~7) % PAGE_SIZE);
++#else
++              desc = current->mm->context.ldt;
++              desc = (void *)desc + (seg & ~7);
++#endif
++      } else {
++              /* Must disable preemption while reading the GDT. */
++              desc = (u32 *)&cpu_gdt_table[get_cpu()];
++              desc = (void *)desc + (seg & ~7);
++      }
++      base = (desc[0] >> 16) |
++              ((desc[1] & 0xff) << 16) |
++              (desc[1] & 0xff000000);
++      if (seg & (1<<2)) {
++#if 1
++              kunmap((void *)((unsigned long)desc & PAGE_MASK));
++#endif
++              up(&current->mm->context.sem);
++      } else
++              put_cpu();
++
++      /* Adjust EIP and segment limit, and clamp at the kernel limit.
++         It's legitimate for segments to wrap at 0xffffffff. */
++      seg_limit += base;
++      if (seg_limit < *eip_limit && seg_limit >= base)
++              *eip_limit = seg_limit;
++      return eip + base;
++}
++
++/*
++ * Sometimes AMD Athlon/Opteron CPUs report invalid exceptions on prefetch.
++ * Check that here and ignore it.
++ */
++static int __is_prefetch(struct pt_regs *regs, unsigned long addr)
++{
++      unsigned long limit;
++      unsigned long instr = get_segment_eip (regs, &limit);
++      int scan_more = 1;
++      int prefetch = 0;
++      int i;
++
++      for (i = 0; scan_more && i < 15; i++) {
++              unsigned char opcode;
++              unsigned char instr_hi;
++              unsigned char instr_lo;
++
++              if (instr > limit)
++                      break;
++              if (__get_user(opcode, (unsigned char *) instr))
++                      break;
++
++              instr_hi = opcode & 0xf0;
++              instr_lo = opcode & 0x0f;
++              instr++;
++
++              switch (instr_hi) {
++              case 0x20:
++              case 0x30:
++                      /* Values 0x26,0x2E,0x36,0x3E are valid x86 prefixes. */
++                      scan_more = ((instr_lo & 7) == 0x6);
++                      break;
++
++              case 0x60:
++                      /* 0x64 thru 0x67 are valid prefixes in all modes. */
++                      scan_more = (instr_lo & 0xC) == 0x4;
++                      break;
++              case 0xF0:
++                      /* 0xF0, 0xF2, and 0xF3 are valid prefixes in all modes. */
++                      scan_more = !instr_lo || (instr_lo>>1) == 1;
++                      break;
++              case 0x00:
++                      /* Prefetch instruction is 0x0F0D or 0x0F18 */
++                      scan_more = 0;
++                      if (instr > limit)
++                              break;
++                      if (__get_user(opcode, (unsigned char *) instr))
++                              break;
++                      prefetch = (instr_lo == 0xF) &&
++                              (opcode == 0x0D || opcode == 0x18);
++                      break;
++              default:
++                      scan_more = 0;
++                      break;
++              }
++      }
++
++#if 1
++      if (prefetch)
++              printk("prefetch handled at %lx eip %lx instr %lx cs %x\n",
++                     addr, regs->eip, instr, regs->xcs);
++#endif
++
++      return prefetch;
++}
++
++static inline int is_prefetch(struct pt_regs *regs, unsigned long addr)
++{
++      if (unlikely(boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
++                   boot_cpu_data.x86 >= 6))
++              return __is_prefetch(regs, addr);
++      return 0;
++}
++
+ asmlinkage void do_invalid_op(struct pt_regs *, unsigned long);
+ /*
+@@ -86,6 +243,8 @@ asmlinkage void do_page_fault(struct pt_
+       tsk = current;
++      info.si_code = SEGV_MAPERR;
++
+       /*
+        * We fault-in kernel-space virtual memory on-demand. The
+        * 'reference' page table is init_mm.pgd.
+@@ -99,18 +258,26 @@ asmlinkage void do_page_fault(struct pt_
+        * (error_code & 4) == 0, and that the fault was not a
+        * protection error (error_code & 1) == 0.
+        */
+-      if (address >= TASK_SIZE && !(error_code & 5))
++#ifdef CONFIG_X86_4G
++      /* On 4/4 all kernels faults are either bugs, vmalloc or prefetch */
++      if (unlikely((regs->xcs & 3) == 0))
+               goto vmalloc_fault;
++#else
++      if (unlikely(address >= TASK_SIZE)) {
++              if (!(error_code & 5))
++                      goto vmalloc_fault;
++              goto bad_area_nosemaphore;
++      }
++#endif
+       mm = tsk->mm;
+-      info.si_code = SEGV_MAPERR;
+       /*
+        * If we're in an interrupt, have no user context or are running in an
+        * atomic region then we must not take the fault..
+        */
+       if (in_atomic() || !mm)
+-              goto no_context;
++              goto bad_area_nosemaphore;
+       down_read(&mm->mmap_sem);
+@@ -198,8 +365,16 @@ good_area:
+ bad_area:
+       up_read(&mm->mmap_sem);
++bad_area_nosemaphore:
+       /* User mode accesses just cause a SIGSEGV */
+       if (error_code & 4) {
++              /*
++               * Valid to do another page fault here because this one came
++               * from user space.
++               */
++              if (is_prefetch(regs, address))
++                      return;
++
+               tsk->thread.cr2 = address;
+               tsk->thread.error_code = error_code;
+               tsk->thread.trap_no = 14;
+@@ -232,10 +407,24 @@ no_context:
+       if (fixup_exception(regs))
+               return;
++      /*
++       * Valid to do another page fault here, because if this fault
++       * had been triggered by is_prefetch fixup_exception would have
++       * handled it.
++       */
++      if (is_prefetch(regs, address))
++              return;
++
+ /*
+  * Oops. The kernel tried to access some bad page. We'll have to
+  * terminate things with extreme prejudice.
+  */
++#ifdef CONFIG_KGDB
++        if (!user_mode(regs)){
++                kgdb_handle_exception(14,SIGBUS, error_code, regs);
++                return;
++        }
++#endif
+       bust_spinlocks(1);
+@@ -286,10 +475,14 @@ out_of_memory:
+ do_sigbus:
+       up_read(&mm->mmap_sem);
+-      /*
+-       * Send a sigbus, regardless of whether we were in kernel
+-       * or user mode.
+-       */
++      /* Kernel mode? Handle exceptions or die */
++      if (!(error_code & 4))
++              goto no_context;
++
++      /* User space => ok to do another page fault */
++      if (is_prefetch(regs, address))
++              return;
++
+       tsk->thread.cr2 = address;
+       tsk->thread.error_code = error_code;
+       tsk->thread.trap_no = 14;
+@@ -298,10 +491,6 @@ do_sigbus:
+       info.si_code = BUS_ADRERR;
+       info.si_addr = (void *)address;
+       force_sig_info(SIGBUS, &info, tsk);
+-
+-      /* Kernel mode? Handle exceptions or die */
+-      if (!(error_code & 4))
+-              goto no_context;
+       return;
+ vmalloc_fault:
+--- linux-2.6.0-test6/arch/i386/mm/init.c      2003-08-08 22:55:10.000000000 -0700
++++ 25/arch/i386/mm/init.c     2003-10-05 00:36:48.000000000 -0700
+@@ -25,6 +25,7 @@
+ #include <linux/bootmem.h>
+ #include <linux/slab.h>
+ #include <linux/proc_fs.h>
++#include <linux/efi.h>
+ #include <asm/processor.h>
+ #include <asm/system.h>
+@@ -38,125 +39,13 @@
+ #include <asm/tlb.h>
+ #include <asm/tlbflush.h>
+ #include <asm/sections.h>
++#include <asm/desc.h>
+ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+ unsigned long highstart_pfn, highend_pfn;
+ static int do_test_wp_bit(void);
+-/*
+- * Creates a middle page table and puts a pointer to it in the
+- * given global directory entry. This only returns the gd entry
+- * in non-PAE compilation mode, since the middle layer is folded.
+- */
+-static pmd_t * __init one_md_table_init(pgd_t *pgd)
+-{
+-      pmd_t *pmd_table;
+-              
+-#ifdef CONFIG_X86_PAE
+-      pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+-      set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT));
+-      if (pmd_table != pmd_offset(pgd, 0)) 
+-              BUG();
+-#else
+-      pmd_table = pmd_offset(pgd, 0);
+-#endif
+-
+-      return pmd_table;
+-}
+-
+-/*
+- * Create a page table and place a pointer to it in a middle page
+- * directory entry.
+- */
+-static pte_t * __init one_page_table_init(pmd_t *pmd)
+-{
+-      if (pmd_none(*pmd)) {
+-              pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+-              set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE));
+-              if (page_table != pte_offset_kernel(pmd, 0))
+-                      BUG();  
+-
+-              return page_table;
+-      }
+-      
+-      return pte_offset_kernel(pmd, 0);
+-}
+-
+-/*
+- * This function initializes a certain range of kernel virtual memory 
+- * with new bootmem page tables, everywhere page tables are missing in
+- * the given range.
+- */
+-
+-/*
+- * NOTE: The pagetables are allocated contiguous on the physical space 
+- * so we can cache the place of the first one and move around without 
+- * checking the pgd every time.
+- */
+-static void __init page_table_range_init (unsigned long start, unsigned long end, pgd_t *pgd_base)
+-{
+-      pgd_t *pgd;
+-      pmd_t *pmd;
+-      int pgd_idx, pmd_idx;
+-      unsigned long vaddr;
+-
+-      vaddr = start;
+-      pgd_idx = pgd_index(vaddr);
+-      pmd_idx = pmd_index(vaddr);
+-      pgd = pgd_base + pgd_idx;
+-
+-      for ( ; (pgd_idx < PTRS_PER_PGD) && (vaddr != end); pgd++, pgd_idx++) {
+-              if (pgd_none(*pgd)) 
+-                      one_md_table_init(pgd);
+-
+-              pmd = pmd_offset(pgd, vaddr);
+-              for (; (pmd_idx < PTRS_PER_PMD) && (vaddr != end); pmd++, pmd_idx++) {
+-                      if (pmd_none(*pmd)) 
+-                              one_page_table_init(pmd);
+-
+-                      vaddr += PMD_SIZE;
+-              }
+-              pmd_idx = 0;
+-      }
+-}
+-
+-/*
+- * This maps the physical memory to kernel virtual address space, a total 
+- * of max_low_pfn pages, by creating page tables starting from address 
+- * PAGE_OFFSET.
+- */
+-static void __init kernel_physical_mapping_init(pgd_t *pgd_base)
+-{
+-      unsigned long pfn;
+-      pgd_t *pgd;
+-      pmd_t *pmd;
+-      pte_t *pte;
+-      int pgd_idx, pmd_idx, pte_ofs;
+-
+-      pgd_idx = pgd_index(PAGE_OFFSET);
+-      pgd = pgd_base + pgd_idx;
+-      pfn = 0;
+-
+-      for (; pgd_idx < PTRS_PER_PGD; pgd++, pgd_idx++) {
+-              pmd = one_md_table_init(pgd);
+-              if (pfn >= max_low_pfn)
+-                      continue;
+-              for (pmd_idx = 0; pmd_idx < PTRS_PER_PMD && pfn < max_low_pfn; pmd++, pmd_idx++) {
+-                      /* Map with big pages if possible, otherwise create normal page tables. */
+-                      if (cpu_has_pse) {
+-                              set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE));
+-                              pfn += PTRS_PER_PTE;
+-                      } else {
+-                              pte = one_page_table_init(pmd);
+-
+-                              for (pte_ofs = 0; pte_ofs < PTRS_PER_PTE && pfn < max_low_pfn; pte++, pfn++, pte_ofs++)
+-                                      set_pte(pte, pfn_pte(pfn, PAGE_KERNEL));
+-                      }
+-              }
+-      }       
+-}
+-
+ static inline int page_kills_ppro(unsigned long pagenr)
+ {
+       if (pagenr >= 0x70000 && pagenr <= 0x7003F)
+@@ -164,12 +53,30 @@ static inline int page_kills_ppro(unsign
+       return 0;
+ }
++extern int is_available_memory(efi_memory_desc_t *);
++
+ static inline int page_is_ram(unsigned long pagenr)
+ {
+       int i;
++      unsigned long addr, end;
++
++      if (efi_enabled) {
++              efi_memory_desc_t *md;
++
++              for (i = 0; i < memmap.nr_map; i++) {
++                      md = &memmap.map[i];
++                      if (!is_available_memory(md))
++                              continue;
++                      addr = (md->phys_addr+PAGE_SIZE-1) >> PAGE_SHIFT;
++                      end = (md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT)) >> PAGE_SHIFT;
++
++                      if ((pagenr >= addr) && (pagenr < end))
++                              return 1;
++              }
++              return 0;
++      }
+       for (i = 0; i < e820.nr_map; i++) {
+-              unsigned long addr, end;
+               if (e820.map[i].type != E820_RAM)       /* not usable memory */
+                       continue;
+@@ -186,38 +93,14 @@ static inline int page_is_ram(unsigned l
+       return 0;
+ }
+-#ifdef CONFIG_HIGHMEM
+ pte_t *kmap_pte;
+-pgprot_t kmap_prot;
+ #define kmap_get_fixmap_pte(vaddr)                                    \
+       pte_offset_kernel(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr))
+ void __init kmap_init(void)
+ {
+-      unsigned long kmap_vstart;
+-
+-      /* cache the first kmap pte */
+-      kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN);
+-      kmap_pte = kmap_get_fixmap_pte(kmap_vstart);
+-
+-      kmap_prot = PAGE_KERNEL;
+-}
+-
+-void __init permanent_kmaps_init(pgd_t *pgd_base)
+-{
+-      pgd_t *pgd;
+-      pmd_t *pmd;
+-      pte_t *pte;
+-      unsigned long vaddr;
+-
+-      vaddr = PKMAP_BASE;
+-      page_table_range_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base);
+-
+-      pgd = swapper_pg_dir + pgd_index(vaddr);
+-      pmd = pmd_offset(pgd, vaddr);
+-      pte = pte_offset_kernel(pmd, vaddr);
+-      pkmap_page_table = pte; 
++      kmap_pte = kmap_get_fixmap_pte(__fix_to_virt(FIX_KMAP_BEGIN));
+ }
+ void __init one_highpage_init(struct page *page, int pfn, int bad_ppro)
+@@ -232,6 +115,8 @@ void __init one_highpage_init(struct pag
+               SetPageReserved(page);
+ }
++#ifdef CONFIG_HIGHMEM
++
+ #ifndef CONFIG_DISCONTIGMEM
+ void __init set_highmem_pages_init(int bad_ppro) 
+ {
+@@ -243,12 +128,9 @@ void __init set_highmem_pages_init(int b
+ #else
+ extern void set_highmem_pages_init(int);
+ #endif /* !CONFIG_DISCONTIGMEM */
+-
+ #else
+-#define kmap_init() do { } while (0)
+-#define permanent_kmaps_init(pgd_base) do { } while (0)
+-#define set_highmem_pages_init(bad_ppro) do { } while (0)
+-#endif /* CONFIG_HIGHMEM */
++# define set_highmem_pages_init(bad_ppro) do { } while (0)
++#endif
+ unsigned long __PAGE_KERNEL = _PAGE_KERNEL;
+@@ -258,30 +140,125 @@ unsigned long __PAGE_KERNEL = _PAGE_KERN
+ extern void __init remap_numa_kva(void);
+ #endif
+-static void __init pagetable_init (void)
++static __init void prepare_pagetables(pgd_t *pgd_base, unsigned long address)
++{
++      pgd_t *pgd;
++      pmd_t *pmd;
++      pte_t *pte;
++
++      pgd = pgd_base + pgd_index(address);
++      pmd = pmd_offset(pgd, address);
++      if (!pmd_present(*pmd)) {
++              pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
++              set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte)));
++      }
++}
++
++static void __init fixrange_init (unsigned long start, unsigned long end, pgd_t *pgd_base)
++{
++      unsigned long vaddr;
++
++      for (vaddr = start; vaddr != end; vaddr += PAGE_SIZE)
++              prepare_pagetables(pgd_base, vaddr);
++}
++
++void setup_identity_mappings(pgd_t *pgd_base, unsigned long start, unsigned long end)
+ {
+       unsigned long vaddr;
+-      pgd_t *pgd_base = swapper_pg_dir;
++      pgd_t *pgd;
++      int i, j, k;
++      pmd_t *pmd;
++      pte_t *pte, *pte_base;
++
++      pgd = pgd_base;
++
++      for (i = 0; i < PTRS_PER_PGD; pgd++, i++) {
++              vaddr = i*PGDIR_SIZE;
++              if (end && (vaddr >= end))
++                      break;
++              pmd = pmd_offset(pgd, 0);
++              for (j = 0; j < PTRS_PER_PMD; pmd++, j++) {
++                      vaddr = i*PGDIR_SIZE + j*PMD_SIZE;
++                      if (end && (vaddr >= end))
++                              break;
++                      if (vaddr < start)
++                              continue;
++                      if (cpu_has_pse) {
++                              unsigned long __pe;
++
++                              set_in_cr4(X86_CR4_PSE);
++                              boot_cpu_data.wp_works_ok = 1;
++                              __pe = _KERNPG_TABLE + _PAGE_PSE + vaddr - start;
++                              /* Make it "global" too if supported */
++                              if (cpu_has_pge) {
++                                      set_in_cr4(X86_CR4_PGE);
++#if !defined(CONFIG_X86_SWITCH_PAGETABLES)
++                                      __pe += _PAGE_GLOBAL;
++                                      __PAGE_KERNEL |= _PAGE_GLOBAL;
++#endif
++                              }
++                              set_pmd(pmd, __pmd(__pe));
++                              continue;
++                      }
++                      if (!pmd_present(*pmd))
++                              pte_base = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
++                      else
++                              pte_base = (pte_t *) page_address(pmd_page(*pmd));
++                      pte = pte_base;
++                      for (k = 0; k < PTRS_PER_PTE; pte++, k++) {
++                              vaddr = i*PGDIR_SIZE + j*PMD_SIZE + k*PAGE_SIZE;
++                              if (end && (vaddr >= end))
++                                      break;
++                              if (vaddr < start)
++                                      continue;
++                              *pte = mk_pte_phys(vaddr-start, PAGE_KERNEL);
++                      }
++                      set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(pte_base)));
++              }
++      }
++}
++static void __init pagetable_init (void)
++{
++      unsigned long vaddr, end;
++      pgd_t *pgd_base;
+ #ifdef CONFIG_X86_PAE
+       int i;
+-      /* Init entries of the first-level page table to the zero page */
+-      for (i = 0; i < PTRS_PER_PGD; i++)
+-              set_pgd(pgd_base + i, __pgd(__pa(empty_zero_page) | _PAGE_PRESENT));
+ #endif
+-      /* Enable PSE if available */
+-      if (cpu_has_pse) {
+-              set_in_cr4(X86_CR4_PSE);
+-      }
++      /*
++       * This can be zero as well - no problem, in that case we exit
++       * the loops anyway due to the PTRS_PER_* conditions.
++       */
++      end = (unsigned long)__va(max_low_pfn*PAGE_SIZE);
+-      /* Enable PGE if available */
+-      if (cpu_has_pge) {
+-              set_in_cr4(X86_CR4_PGE);
+-              __PAGE_KERNEL |= _PAGE_GLOBAL;
++      pgd_base = swapper_pg_dir;
++#ifdef CONFIG_X86_PAE
++      /*
++       * It causes too many problems if there's no proper pmd set up
++       * for all 4 entries of the PGD - so we allocate all of them.
++       * PAE systems will not miss this extra 4-8K anyway ...
++       */
++      for (i = 0; i < PTRS_PER_PGD; i++) {
++              pmd_t *pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
++              set_pgd(pgd_base + i, __pgd(__pa(pmd) + 0x1));
+       }
++#endif
++      /*
++       * Set up lowmem-sized identity mappings at PAGE_OFFSET:
++       */
++      setup_identity_mappings(pgd_base, PAGE_OFFSET, end);
+-      kernel_physical_mapping_init(pgd_base);
++      /*
++       * Add flat-mode identity-mappings - SMP needs it when
++       * starting up on an AP from real-mode. (In the non-PAE
++       * case we already have these mappings through head.S.)
++       * All user-space mappings are explicitly cleared after
++       * SMP startup.
++       */
++#if CONFIG_SMP && CONFIG_X86_PAE
++      setup_identity_mappings(pgd_base, 0, 16*1024*1024);
++#endif
+       remap_numa_kva();
+       /*
+@@ -289,38 +266,64 @@ static void __init pagetable_init (void)
+        * created - mappings will be set by set_fixmap():
+        */
+       vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
+-      page_table_range_init(vaddr, 0, pgd_base);
++      fixrange_init(vaddr, 0, pgd_base);
+-      permanent_kmaps_init(pgd_base);
++#if CONFIG_HIGHMEM
++      {
++              pgd_t *pgd;
++              pmd_t *pmd;
++              pte_t *pte;
+-#ifdef CONFIG_X86_PAE
+-      /*
+-       * Add low memory identity-mappings - SMP needs it when
+-       * starting up on an AP from real-mode. In the non-PAE
+-       * case we already have these mappings through head.S.
+-       * All user-space mappings are explicitly cleared after
+-       * SMP startup.
+-       */
+-      pgd_base[0] = pgd_base[USER_PTRS_PER_PGD];
++              /*
++               * Permanent kmaps:
++               */
++              vaddr = PKMAP_BASE;
++              fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base);
++
++              pgd = swapper_pg_dir + pgd_index(vaddr);
++              pmd = pmd_offset(pgd, vaddr);
++              pte = pte_offset_kernel(pmd, vaddr);
++              pkmap_page_table = pte;
++      }
+ #endif
+ }
+-void zap_low_mappings (void)
++/*
++ * Clear kernel pagetables in a PMD_SIZE-aligned range.
++ */
++static void clear_mappings(pgd_t *pgd_base, unsigned long start, unsigned long end)
+ {
+-      int i;
++      unsigned long vaddr;
++      pgd_t *pgd;
++      pmd_t *pmd;
++      int i, j;
++
++      pgd = pgd_base;
++
++      for (i = 0; i < PTRS_PER_PGD; pgd++, i++) {
++              vaddr = i*PGDIR_SIZE;
++              if (end && (vaddr >= end))
++                      break;
++              pmd = pmd_offset(pgd, 0);
++              for (j = 0; j < PTRS_PER_PMD; pmd++, j++) {
++                      vaddr = i*PGDIR_SIZE + j*PMD_SIZE;
++                      if (end && (vaddr >= end))
++                              break;
++                      if (vaddr < start)
++                              continue;
++                      pmd_clear(pmd);
++              }
++      }
++      flush_tlb_all();
++}
++
++void __init zap_low_mappings(void)
++{
++      printk("zapping low mappings.\n");
+       /*
+        * Zap initial low-memory mappings.
+-       *
+-       * Note that "pgd_clear()" doesn't do it for
+-       * us, because pgd_clear() is a no-op on i386.
+        */
+-      for (i = 0; i < USER_PTRS_PER_PGD; i++)
+-#ifdef CONFIG_X86_PAE
+-              set_pgd(swapper_pg_dir+i, __pgd(1 + __pa(empty_zero_page)));
+-#else
+-              set_pgd(swapper_pg_dir+i, __pgd(0));
+-#endif
+-      flush_tlb_all();
++      clear_mappings(swapper_pg_dir, 0, 16*1024*1024);
+ }
+ #ifndef CONFIG_DISCONTIGMEM
+@@ -424,6 +427,7 @@ extern void set_max_mapnr_init(void);
+ #endif /* !CONFIG_DISCONTIGMEM */
+ static struct kcore_list kcore_mem, kcore_vmalloc; 
++extern void fixup_sort_exception_table(void);
+ void __init mem_init(void)
+ {
+@@ -432,6 +436,8 @@ void __init mem_init(void)
+       int tmp;
+       int bad_ppro;
++      fixup_sort_exception_table();
++
+ #ifndef CONFIG_DISCONTIGMEM
+       if (!mem_map)
+               BUG();
+@@ -507,13 +513,18 @@ void __init mem_init(void)
+ #ifndef CONFIG_SMP
+       zap_low_mappings();
+ #endif
++      entry_trampoline_setup();
++      default_ldt_page = virt_to_page(default_ldt);
++      load_LDT(&init_mm.context);
+ }
+-kmem_cache_t *pgd_cache;
+-kmem_cache_t *pmd_cache;
++kmem_cache_t *pgd_cache, *pmd_cache, *kpmd_cache;
+ void __init pgtable_cache_init(void)
+ {
++      void (*ctor)(void *, kmem_cache_t *, unsigned long);
++      void (*dtor)(void *, kmem_cache_t *, unsigned long);
++
+       if (PTRS_PER_PMD > 1) {
+               pmd_cache = kmem_cache_create("pmd",
+                                       PTRS_PER_PMD*sizeof(pmd_t),
+@@ -523,13 +534,36 @@ void __init pgtable_cache_init(void)
+                                       NULL);
+               if (!pmd_cache)
+                       panic("pgtable_cache_init(): cannot create pmd cache");
++
++              if (TASK_SIZE > PAGE_OFFSET) {
++                      kpmd_cache = kmem_cache_create("kpmd",
++                                      PTRS_PER_PMD*sizeof(pmd_t),
++                                      0,
++                                      SLAB_HWCACHE_ALIGN | SLAB_MUST_HWCACHE_ALIGN,
++                                      kpmd_ctor,
++                                      NULL);
++                      if (!kpmd_cache)
++                              panic("pgtable_cache_init(): "
++                                              "cannot create kpmd cache");
++              }
+       }
++
++      if (PTRS_PER_PMD == 1 || TASK_SIZE <= PAGE_OFFSET)
++              ctor = pgd_ctor;
++      else
++              ctor = NULL;
++
++      if (PTRS_PER_PMD == 1 && TASK_SIZE <= PAGE_OFFSET)
++              dtor = pgd_dtor;
++      else
++              dtor = NULL;
++
+       pgd_cache = kmem_cache_create("pgd",
+                               PTRS_PER_PGD*sizeof(pgd_t),
+                               0,
+                               SLAB_HWCACHE_ALIGN | SLAB_MUST_HWCACHE_ALIGN,
+-                              pgd_ctor,
+-                              PTRS_PER_PMD == 1 ? pgd_dtor : NULL);
++                              ctor,
++                              dtor);
+       if (!pgd_cache)
+               panic("pgtable_cache_init(): Cannot create pgd cache");
+ }
+--- linux-2.6.0-test6/arch/i386/mm/ioremap.c   2003-06-14 12:18:04.000000000 -0700
++++ 25/arch/i386/mm/ioremap.c  2003-10-05 00:33:23.000000000 -0700
+@@ -158,7 +158,7 @@ void * __ioremap(unsigned long phys_addr
+               return NULL;
+       area->phys_addr = phys_addr;
+       addr = area->addr;
+-      if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size, flags)) {
++      if (remap_area_pages((unsigned long) addr, phys_addr, size, flags)) {
+               vunmap(addr);
+               return NULL;
+       }
+--- linux-2.6.0-test6/arch/i386/mm/pgtable.c   2003-08-08 22:55:10.000000000 -0700
++++ 25/arch/i386/mm/pgtable.c  2003-10-05 00:36:48.000000000 -0700
+@@ -21,6 +21,7 @@
+ #include <asm/e820.h>
+ #include <asm/tlb.h>
+ #include <asm/tlbflush.h>
++#include <asm/atomic_kmap.h>
+ void show_mem(void)
+ {
+@@ -157,11 +158,20 @@ void pmd_ctor(void *pmd, kmem_cache_t *c
+       memset(pmd, 0, PTRS_PER_PMD*sizeof(pmd_t));
+ }
++void kpmd_ctor(void *__pmd, kmem_cache_t *cache, unsigned long flags)
++{
++      pmd_t *kpmd, *pmd;
++      kpmd = pmd_offset(&swapper_pg_dir[PTRS_PER_PGD-1],
++                              (PTRS_PER_PMD - NR_SHARED_PMDS)*PMD_SIZE);
++      pmd = (pmd_t *)__pmd + (PTRS_PER_PMD - NR_SHARED_PMDS);
++
++      memset(__pmd, 0, (PTRS_PER_PMD - NR_SHARED_PMDS)*sizeof(pmd_t));
++      memcpy(pmd, kpmd, NR_SHARED_PMDS*sizeof(pmd_t));
++}
++
+ /*
+- * List of all pgd's needed for non-PAE so it can invalidate entries
+- * in both cached and uncached pgd's; not needed for PAE since the
+- * kernel pmd is shared. If PAE were not to share the pmd a similar
+- * tactic would be needed. This is essentially codepath-based locking
++ * List of all pgd's needed so it can invalidate entries in both cached
++ * and uncached pgd's. This is essentially codepath-based locking
+  * against pageattr.c; it is the unique case in which a valid change
+  * of kernel pagetables can't be lazily synchronized by vmalloc faults.
+  * vmalloc faults work because attached pagetables are never freed.
+@@ -170,30 +180,60 @@ void pmd_ctor(void *pmd, kmem_cache_t *c
+  * could be used. The locking scheme was chosen on the basis of
+  * manfred's recommendations and having no core impact whatsoever.
+  * -- wli
++ *
++ * The entire issue goes away when XKVA is configured.
+  */
+ spinlock_t pgd_lock = SPIN_LOCK_UNLOCKED;
+ LIST_HEAD(pgd_list);
+-void pgd_ctor(void *pgd, kmem_cache_t *cache, unsigned long unused)
++/*
++ * This is not that hard to figure out.
++ * (a) PTRS_PER_PMD == 1 means non-PAE.
++ * (b) PTRS_PER_PMD > 1 means PAE.
++ * (c) TASK_SIZE > PAGE_OFFSET means XKVA.
++ * (d) TASK_SIZE <= PAGE_OFFSET means non-XKVA.
++ *
++ * Do *NOT* back out the preconstruction like the patch I'm cleaning
++ * up after this very instant did, or at all, for that matter.
++ * This is never called when PTRS_PER_PMD > 1 && TASK_SIZE > PAGE_OFFSET.
++ * -- wli
++ */
++void pgd_ctor(void *__pgd, kmem_cache_t *cache, unsigned long unused)
+ {
++      pgd_t *pgd = (pgd_t *)__pgd;
+       unsigned long flags;
+-      if (PTRS_PER_PMD == 1)
+-              spin_lock_irqsave(&pgd_lock, flags);
++      if (PTRS_PER_PMD == 1) {
++              if (TASK_SIZE <= PAGE_OFFSET)
++                      spin_lock_irqsave(&pgd_lock, flags);
++              else
++                      memcpy(&pgd[PTRS_PER_PGD - NR_SHARED_PMDS],
++                              &swapper_pg_dir[PTRS_PER_PGD - NR_SHARED_PMDS],
++                              NR_SHARED_PMDS * sizeof(pgd_t));
++      }
+-      memcpy((pgd_t *)pgd + USER_PTRS_PER_PGD,
+-                      swapper_pg_dir + USER_PTRS_PER_PGD,
+-                      (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
++      if (TASK_SIZE <= PAGE_OFFSET)
++              memcpy(pgd + USER_PTRS_PER_PGD,
++                      swapper_pg_dir + USER_PTRS_PER_PGD,
++                      (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+       if (PTRS_PER_PMD > 1)
+               return;
+-      list_add(&virt_to_page(pgd)->lru, &pgd_list);
+-      spin_unlock_irqrestore(&pgd_lock, flags);
+-      memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t));
++      if (TASK_SIZE > PAGE_OFFSET)
++              memset(pgd, 0, (PTRS_PER_PGD - NR_SHARED_PMDS)*sizeof(pgd_t));
++      else {
++              list_add(&virt_to_page(pgd)->lru, &pgd_list);
++              spin_unlock_irqrestore(&pgd_lock, flags);
++              memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t));
++      }
+ }
+-/* never called when PTRS_PER_PMD > 1 */
++/*
++ * Never called when PTRS_PER_PMD > 1 || TASK_SIZE > PAGE_OFFSET
++ * for with PAE we would list_del() multiple times, and for non-PAE
++ * with XKVA all the AGP pgd shootdown code is unnecessary.
++ */
+ void pgd_dtor(void *pgd, kmem_cache_t *cache, unsigned long unused)
+ {
+       unsigned long flags; /* can be called from interrupt context */
+@@ -203,6 +243,12 @@ void pgd_dtor(void *pgd, kmem_cache_t *c
+       spin_unlock_irqrestore(&pgd_lock, flags);
+ }
++/*
++ * See the comments above pgd_ctor() wrt. preconstruction.
++ * Do *NOT* memcpy() here. If you do, you back out important
++ * anti- cache pollution code.
++ *
++ */
+ pgd_t *pgd_alloc(struct mm_struct *mm)
+ {
+       int i;
+@@ -211,15 +257,33 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
+       if (PTRS_PER_PMD == 1 || !pgd)
+               return pgd;
++      /*
++       * In the 4G userspace case alias the top 16 MB virtual
++       * memory range into the user mappings as well (these
++       * include the trampoline and CPU data structures).
++       */
+       for (i = 0; i < USER_PTRS_PER_PGD; ++i) {
+-              pmd_t *pmd = kmem_cache_alloc(pmd_cache, GFP_KERNEL);
++              kmem_cache_t *cache;
++              pmd_t *pmd;
++
++              if (TASK_SIZE > PAGE_OFFSET && i == USER_PTRS_PER_PGD - 1)
++                      cache = kpmd_cache;
++              else
++                      cache = pmd_cache;
++
++              pmd = kmem_cache_alloc(cache, GFP_KERNEL);
+               if (!pmd)
+                       goto out_oom;
+               set_pgd(&pgd[i], __pgd(1 + __pa((u64)((u32)pmd))));
+       }
+-      return pgd;
++      return pgd;
+ out_oom:
++      /*
++       * we don't have to handle the kpmd_cache here, since it's the
++       * last allocation, and has either nothing to free or when it
++       * succeeds the whole operation succeeds.
++       */
+       for (i--; i >= 0; i--)
+               kmem_cache_free(pmd_cache, (void *)__va(pgd_val(pgd[i])-1));
+       kmem_cache_free(pgd_cache, pgd);
+@@ -230,10 +294,29 @@ void pgd_free(pgd_t *pgd)
+ {
+       int i;
+-      /* in the PAE case user pgd entries are overwritten before usage */
+-      if (PTRS_PER_PMD > 1)
+-              for (i = 0; i < USER_PTRS_PER_PGD; ++i)
+-                      kmem_cache_free(pmd_cache, (void *)__va(pgd_val(pgd[i])-1));
+       /* in the non-PAE case, clear_page_tables() clears user pgd entries */
++      if (PTRS_PER_PMD == 1)
++              goto out_free;
++
++      /* in the PAE case user pgd entries are overwritten before usage */
++      for (i = 0; i < USER_PTRS_PER_PGD; ++i) {
++              kmem_cache_t *cache;
++              pmd_t *pmd = __va(pgd_val(pgd[i]) - 1);
++
++              /*
++               * only userspace pmd's are cleared for us
++               * by mm/memory.c; it's a slab cache invariant
++               * that we must separate the kernel pmd slab
++               * all times, else we'll have bad pmd's.
++               */
++              if (TASK_SIZE > PAGE_OFFSET && i == USER_PTRS_PER_PGD - 1)
++                      cache = kpmd_cache;
++              else
++                      cache = pmd_cache;
++
++              kmem_cache_free(cache, pmd);
++      }
++out_free:
+       kmem_cache_free(pgd_cache, pgd);
+ }
++
+--- linux-2.6.0-test6/arch/i386/pci/acpi.c     2003-08-22 19:23:40.000000000 -0700
++++ 25/arch/i386/pci/acpi.c    2003-10-05 00:34:16.000000000 -0700
+@@ -15,10 +15,11 @@ struct pci_bus * __devinit pci_acpi_scan
+ static int __init pci_acpi_init(void)
+ {
++      extern int acpi_disabled;
+       if (pcibios_scanned)
+               return 0;
+-      if (!(pci_probe & PCI_NO_ACPI_ROUTING)) {
++      if (!(pci_probe & PCI_NO_ACPI_ROUTING) && !acpi_disabled) {
+               if (!acpi_pci_irq_init()) {
+                       printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
+                       printk(KERN_INFO "PCI: if you experience problems, try using option 'pci=noacpi' or even 'acpi=off'\n");
+--- linux-2.6.0-test6/arch/i386/pci/irq.c      2003-08-08 22:55:10.000000000 -0700
++++ 25/arch/i386/pci/irq.c     2003-10-05 00:36:20.000000000 -0700
+@@ -680,8 +680,10 @@ static int pcibios_lookup_irq(struct pci
+                       if ( dev2->irq && dev2->irq != irq && \
+                       (!(pci_probe & PCI_USE_PIRQ_MASK) || \
+                       ((1 << dev2->irq) & mask)) ) {
++#ifndef CONFIG_PCI_USE_VECTOR
+                               printk(KERN_INFO "IRQ routing conflict for %s, have irq %d, want irq %d\n",
+                                      pci_name(dev2), dev2->irq, irq);
++#endif
+                               continue;
+                       }
+                       dev2->irq = irq;
+@@ -745,6 +747,10 @@ static void __init pcibios_fixup_irqs(vo
+                                                       bridge->bus->number, PCI_SLOT(bridge->devfn), pin, irq);
+                               }
+                               if (irq >= 0) {
++                                      if (use_pci_vector() &&
++                                              !platform_legacy_irq(irq))
++                                              irq = IO_APIC_VECTOR(irq);
++
+                                       printk(KERN_INFO "PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %d\n",
+                                               dev->bus->number, PCI_SLOT(dev->devfn), pin, irq);
+                                       dev->irq = irq;
+--- linux-2.6.0-test6/arch/ia64/ia32/ia32_ioctl.c      2003-09-08 13:58:56.000000000 -0700
++++ 25/arch/ia64/ia32/ia32_ioctl.c     2003-10-05 00:34:44.000000000 -0700
+@@ -26,43 +26,11 @@
+       _ret;                                           \
+ })
+-#define P(i)  ((void *)(unsigned long)(i))
+-
+ asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
+ #define CODE
+ #include "compat_ioctl.c"
+-#define       VFAT_IOCTL_READDIR_BOTH32       _IOR('r', 1, struct linux32_dirent[2])
+-#define       VFAT_IOCTL_READDIR_SHORT32      _IOR('r', 2, struct linux32_dirent[2])
+-
+-static long
+-put_dirent32 (struct dirent *d, struct linux32_dirent *d32)
+-{
+-      size_t namelen = strlen(d->d_name);
+-
+-      return (put_user(d->d_ino, &d32->d_ino)
+-              || put_user(d->d_off, &d32->d_off)
+-              || put_user(d->d_reclen, &d32->d_reclen)
+-              || copy_to_user(d32->d_name, d->d_name, namelen + 1));
+-}
+-
+-static int vfat_ioctl32(unsigned fd, unsigned cmd,  void *ptr) 
+-{
+-      int ret;
+-      mm_segment_t oldfs = get_fs();
+-      struct dirent d[2]; 
+-
+-      set_fs(KERNEL_DS);
+-      ret = sys_ioctl(fd,cmd,(unsigned long)&d); 
+-      set_fs(oldfs); 
+-      if (!ret) { 
+-              ret |= put_dirent32(&d[0], (struct linux32_dirent *)ptr); 
+-              ret |= put_dirent32(&d[1], ((struct linux32_dirent *)ptr) + 1); 
+-      }
+-      return ret; 
+-} 
+-
+ typedef int (* ioctl32_handler_t)(unsigned int, unsigned int, unsigned long, struct file *);
+ #define COMPATIBLE_IOCTL(cmd)         HANDLE_IOCTL((cmd),sys_ioctl)
+@@ -73,8 +41,6 @@ typedef int (* ioctl32_handler_t)(unsign
+       };
+ IOCTL_TABLE_START
+-HANDLE_IOCTL(VFAT_IOCTL_READDIR_BOTH32, vfat_ioctl32)
+-HANDLE_IOCTL(VFAT_IOCTL_READDIR_SHORT32, vfat_ioctl32)
+ #define DECLARES
+ #include "compat_ioctl.c"
+ #include <linux/compat_ioctl.h>
+--- linux-2.6.0-test6/arch/ia64/ia32/ia32priv.h        2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/ia64/ia32/ia32priv.h       2003-10-05 00:34:44.000000000 -0700
+@@ -249,13 +249,6 @@ typedef struct siginfo32 {
+       } _sifields;
+ } siginfo_t32;
+-struct linux32_dirent {
+-      u32     d_ino;
+-      u32     d_off;
+-      u16     d_reclen;
+-      char    d_name[256];
+-};
+-
+ struct old_linux32_dirent {
+       u32     d_ino;
+       u32     d_offset;
+--- linux-2.6.0-test6/arch/ia64/ia32/sys_ia32.c        2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/ia64/ia32/sys_ia32.c       2003-10-05 00:34:44.000000000 -0700
+@@ -707,8 +707,8 @@ sys32_settimeofday (struct compat_timeva
+ }
+ struct getdents32_callback {
+-      struct linux32_dirent * current_dir;
+-      struct linux32_dirent * previous;
++      struct compat_dirent * current_dir;
++      struct compat_dirent * previous;
+       int count;
+       int error;
+ };
+@@ -722,7 +722,7 @@ static int
+ filldir32 (void *__buf, const char *name, int namlen, loff_t offset, ino_t ino,
+          unsigned int d_type)
+ {
+-      struct linux32_dirent * dirent;
++      struct compat_dirent * dirent;
+       struct getdents32_callback * buf = (struct getdents32_callback *) __buf;
+       int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1, 4);
+@@ -748,10 +748,10 @@ filldir32 (void *__buf, const char *name
+ }
+ asmlinkage long
+-sys32_getdents (unsigned int fd, struct linux32_dirent *dirent, unsigned int count)
++sys32_getdents (unsigned int fd, struct compat_dirent *dirent, unsigned int count)
+ {
+       struct file * file;
+-      struct linux32_dirent * lastdirent;
++      struct compat_dirent * lastdirent;
+       struct getdents32_callback buf;
+       int error;
+--- linux-2.6.0-test6/arch/ia64/kernel/acpi.c  2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/ia64/kernel/acpi.c 2003-10-05 00:34:41.000000000 -0700
+@@ -41,6 +41,7 @@
+ #include <linux/irq.h>
+ #include <linux/acpi.h>
+ #include <linux/efi.h>
++#include <linux/mmzone.h>
+ #include <asm/io.h>
+ #include <asm/iosapic.h>
+ #include <asm/machvec.h>
+@@ -56,7 +57,7 @@ void (*pm_power_off) (void);
+ unsigned char acpi_kbd_controller_present = 1;
+-int acpi_disabled __initdata; /* XXX this shouldn't be needed---we can't boot without ACPI! */
++int acpi_disabled;    /* XXX this shouldn't be needed---we can't boot without ACPI! */
+ const char *
+ acpi_get_sysname (void)
+@@ -341,7 +342,7 @@ static u32 __initdata pxm_flag[PXM_FLAG_
+ #define pxm_bit_test(bit)     (test_bit(bit,(void *)pxm_flag))
+ /* maps to convert between proximity domain and logical node ID */
+ int __initdata pxm_to_nid_map[MAX_PXM_DOMAINS];
+-int __initdata nid_to_pxm_map[NR_NODES];
++int __initdata nid_to_pxm_map[MAX_NUMNODES];
+ static struct acpi_table_slit __initdata *slit_table;
+ /*
+--- linux-2.6.0-test6/arch/ia64/kernel/perfmon.c       2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/ia64/kernel/perfmon.c      2003-10-05 00:34:03.000000000 -0700
+@@ -2165,6 +2165,7 @@ pfm_alloc_fd(struct file **cfile)
+       d_add(file->f_dentry, inode);
+       file->f_vfsmnt = mntget(pfmfs_mnt);
++      file->f_mapping = inode->i_mapping;
+       file->f_op    = &pfm_file_ops;
+       file->f_mode  = FMODE_READ;
+--- linux-2.6.0-test6/arch/ia64/kernel/unaligned.c     2003-08-22 19:23:40.000000000 -0700
++++ 25/arch/ia64/kernel/unaligned.c    2003-10-05 00:36:18.000000000 -0700
+@@ -1347,7 +1347,7 @@ ia64_handle_unaligned (unsigned long ifa
+                        * be holding locks...
+                        */
+                       if (user_mode(regs))
+-                              tty_write_message(current->tty, buf);
++                              tty_write_message(process_tty(current), buf);
+                       buf[len-1] = '\0';      /* drop '\r' */
+                       printk(KERN_WARNING "%s", buf); /* watch for command names containing %s */
+               }
+--- linux-2.6.0-test6/arch/ia64/mm/discontig.c 2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/ia64/mm/discontig.c        2003-10-05 00:34:41.000000000 -0700
+@@ -14,7 +14,6 @@
+ #include <linux/mm.h>
+ #include <linux/swap.h>
+ #include <linux/bootmem.h>
+-#include <linux/mmzone.h>
+ #include <linux/acpi.h>
+ #include <linux/efi.h>
+ #include <asm/pgalloc.h>
+@@ -26,10 +25,10 @@
+  */
+ #define GRANULEROUNDUP(n) (((n)+IA64_GRANULE_SIZE-1) & ~(IA64_GRANULE_SIZE-1))
+-static struct ia64_node_data  *node_data[NR_NODES];
+-static long                   boot_pg_data[8*NR_NODES+sizeof(pg_data_t)]  __initdata;
+-static pg_data_t              *pg_data_ptr[NR_NODES] __initdata;
+-static bootmem_data_t         bdata[NR_NODES][NR_BANKS_PER_NODE+1] __initdata;
++static struct ia64_node_data  *node_data[MAX_NUMNODES];
++static long                   boot_pg_data[8*MAX_NUMNODES+sizeof(pg_data_t)]  __initdata;
++static pg_data_t              *pg_data_ptr[MAX_NUMNODES] __initdata;
++static bootmem_data_t         bdata[MAX_NUMNODES][NR_BANKS_PER_NODE+1] __initdata;
+ /*
+  * Return the compact node number of this cpu. Used prior to
+  * setting up the cpu_data area.
+--- linux-2.6.0-test6/arch/ia64/mm/numa.c      2003-09-08 13:58:56.000000000 -0700
++++ 25/arch/ia64/mm/numa.c     2003-10-05 00:34:41.000000000 -0700
+@@ -15,7 +15,6 @@
+ #include <linux/mm.h>
+ #include <linux/init.h>
+ #include <linux/bootmem.h>
+-#include <linux/mmzone.h>
+ #include <asm/numa.h>
+ /*
+@@ -29,7 +28,7 @@ struct node_cpuid_s node_cpuid[NR_CPUS];
+  * This is a matrix with "distances" between nodes, they should be
+  * proportional to the memory access latency ratios.
+  */
+-u8 numa_slit[NR_NODES * NR_NODES];
++u8 numa_slit[MAX_NUMNODES * MAX_NUMNODES];
+ /* Identify which cnode a physical address resides on */
+ int
+--- linux-2.6.0-test6/arch/ia64/sn/io/sn2/module.c     2003-07-10 18:50:30.000000000 -0700
++++ 25/arch/ia64/sn/io/sn2/module.c    2003-10-05 00:33:23.000000000 -0700
+@@ -166,7 +166,6 @@ int module_probe_snum(module_t *m, nasid
+ {
+     lboard_t         *board;
+     klmod_serial_num_t *comp;
+-    char * bcopy(const char * src, char * dest, int count);
+     char serial_number[16];
+     /*
+@@ -215,9 +214,9 @@ int module_probe_snum(module_t *m, nasid
+ #endif
+           if (comp->snum.snum_str[0] != '\0') {
+-              bcopy(comp->snum.snum_str,
+-                    m->sys_snum,
+-                    MAX_SERIAL_NUM_SIZE);
++              memcpy(m->sys_snum,
++                     comp->snum.snum_str,
++                     MAX_SERIAL_NUM_SIZE);
+               m->sys_snum_valid = 1;
+           }
+     }
+--- linux-2.6.0-test6/arch/ia64/sn/io/sn2/pic.c        2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/ia64/sn/io/sn2/pic.c       2003-10-05 00:33:23.000000000 -0700
+@@ -29,8 +29,6 @@
+ #include <asm/sn/io.h>
+ #include <asm/sn/sn_private.h>
+-extern char *bcopy(const char * src, char * dest, int count);
+-
+ #define PCI_BUS_NO_1 1
+@@ -51,7 +49,7 @@ pic_bus1_inventory_dup(vertex_hdl_t conn
+                               (arbitrary_info_t *)&pinv) == GRAPH_SUCCESS)
+  {
+               NEW(peer_pinv);
+-              bcopy((const char *)pinv, (char *)peer_pinv, sizeof(inventory_t));
++              memcpy(peer_pinv, pinv, sizeof(inventory_t));
+               if (hwgraph_info_add_LBL(peer_conn_v, INFO_LBL_INVENT,
+                           (arbitrary_info_t)peer_pinv) != GRAPH_SUCCESS) {
+                       DEL(peer_pinv);
+--- linux-2.6.0-test6/arch/m68k/atari/stram.c  2003-09-08 13:58:56.000000000 -0700
++++ 25/arch/m68k/atari/stram.c 2003-10-05 00:33:23.000000000 -0700
+@@ -22,6 +22,7 @@
+ #include <linux/shm.h>
+ #include <linux/bootmem.h>
+ #include <linux/mount.h>
++#include <linux/blkdev.h>
+ #include <asm/setup.h>
+ #include <asm/machdep.h>
+--- linux-2.6.0-test6/arch/m68k/Kconfig        2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/m68k/Kconfig       2003-10-05 00:33:23.000000000 -0700
+@@ -87,7 +87,7 @@ config ATARI
+ config HADES
+       bool "Hades support"
+-      depends on ATARI
++      depends on ATARI && BROKEN
+       help
+         This option enables support for the Hades Atari clone. If you plan
+         to use this kernel on a Hades, say Y here; otherwise say N.
+@@ -361,7 +361,7 @@ config AMIGA_PCMCIA
+ config STRAM_SWAP
+       bool "Support for ST-RAM as swap space"
+-      depends on ATARI
++      depends on ATARI && BROKEN
+       ---help---
+         Some Atari 68k macines (including the 520STF and 1020STE) divide
+         their addressible memory into ST and TT sections.  The TT section
+@@ -961,7 +961,7 @@ config MVME147_SCC
+ config SERIAL167
+       bool "CD2401 support for MVME166/7 serial ports"
+-      depends on MVME16x
++      depends on MVME16x && BROKEN
+       help
+         This is the driver for the serial ports on the Motorola MVME166,
+         167, and 172 boards.  Everyone using one of these boards should say
+--- linux-2.6.0-test6/arch/m68k/kernel/time.c  2003-07-13 21:44:34.000000000 -0700
++++ 25/arch/m68k/kernel/time.c 2003-10-05 00:33:23.000000000 -0700
+@@ -171,3 +171,12 @@ int do_settimeofday(struct timespec *tv)
+       write_sequnlock_irq(&xtime_lock);
+       return 0;
+ }
++
++/*
++ * Scheduler clock - returns current time in ns units.
++ */
++unsigned long long sched_clock(void)
++{
++       return (unsigned long long)jiffies*(1000000000/HZ);
++}
++
+--- linux-2.6.0-test6/arch/m68k/Makefile       2003-07-27 12:14:38.000000000 -0700
++++ 25/arch/m68k/Makefile      2003-10-05 00:33:23.000000000 -0700
+@@ -76,6 +76,8 @@ core-$(CONFIG_M68040)                += arch/m68k/fpsp
+ core-$(CONFIG_M68060)         += arch/m68k/ifpsp060/
+ core-$(CONFIG_M68KFPU_EMU)    += arch/m68k/math-emu/
++all:  zImage
++
+ lilo: vmlinux
+       if [ -f $(INSTALL_PATH)/vmlinux ]; then mv -f $(INSTALL_PATH)/vmlinux $(INSTALL_PATH)/vmlinux.old; fi
+       if [ -f $(INSTALL_PATH)/System.map ]; then mv -f $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi
+--- linux-2.6.0-test6/arch/m68k/q40/q40ints.c  2003-07-27 12:14:38.000000000 -0700
++++ 25/arch/m68k/q40/q40ints.c 2003-10-05 00:33:23.000000000 -0700
+@@ -200,7 +200,9 @@ void q40_free_irq(unsigned int irq, void
+ irqreturn_t q40_process_int (int level, struct pt_regs *fp)
+ {
+-  printk("unexpected interrupt %x\n",level);
++  printk("unexpected interrupt vec=%x, pc=%lx, d0=%lx, d0_orig=%lx, d1=%lx, d2=%lx\n",
++          level, fp->pc, fp->d0, fp->orig_d0, fp->d1, fp->d2);
++  printk("\tIIRQ_REG = %x, EIRQ_REG = %x\n",master_inb(IIRQ_REG),master_inb(EIRQ_REG));
+   return IRQ_HANDLED;
+ }
+@@ -378,7 +380,7 @@ irqreturn_t q40_irq2_handler (int vec, v
+                                 /*printk("reenabling irq %d\n",irq); */
+ #endif
+                         }
+-// used to do 'goto repeat;' her, this delayed bh processing too long
++// used to do 'goto repeat;' here, this delayed bh processing too long
+                         return IRQ_HANDLED;
+                 }
+         }
+@@ -387,6 +389,7 @@ irqreturn_t q40_irq2_handler (int vec, v
+   } 
+  iirq:
+   mir=master_inb(IIRQ_REG);
++  /* should test whether keyboard irq is really enabled, doing it in defhand */
+   if (mir&Q40_IRQ_KEYB_MASK) {
+         irq_tab[Q40_IRQ_KEYBOARD].count++;
+         irq_tab[Q40_IRQ_KEYBOARD].handler(Q40_IRQ_KEYBOARD,irq_tab[Q40_IRQ_KEYBOARD].dev_id,fp);
+@@ -413,7 +416,9 @@ int show_q40_interrupts (struct seq_file
+ static irqreturn_t q40_defhand (int irq, void *dev_id, struct pt_regs *fp)
+ {
+-      printk ("Unknown q40 interrupt 0x%02x\n", irq);
++        if (irq!=Q40_IRQ_KEYBOARD)
++           printk ("Unknown q40 interrupt %d\n", irq);
++      else master_outb(-1,KEYBOARD_UNLOCK_REG);
+       return IRQ_NONE;
+ }
+ static irqreturn_t sys_default_handler(int lev, void *dev_id, struct pt_regs *regs)
+--- linux-2.6.0-test6/arch/m68k/sun3/config.c  2003-06-14 12:18:25.000000000 -0700
++++ 25/arch/m68k/sun3/config.c 2003-10-05 00:33:23.000000000 -0700
+@@ -129,7 +129,7 @@ void __init sun3_bootmem_alloc(unsigned 
+       high_memory = (void *)memory_end;
+       availmem = memory_start;
+-      availmem += init_bootmem(start_page, num_pages);
++      availmem += init_bootmem_node(NODE_DATA(0), start_page, 0, num_pages);
+       availmem = (availmem + (PAGE_SIZE-1)) & PAGE_MASK;
+       free_bootmem(__pa(availmem), memory_end - (availmem));
+--- linux-2.6.0-test6/arch/mips/mm/ioremap.c   2003-08-08 22:55:11.000000000 -0700
++++ 25/arch/mips/mm/ioremap.c  2003-10-05 00:33:23.000000000 -0700
+@@ -162,7 +162,7 @@ void * __ioremap(phys_t phys_addr, phys_
+       if (!area)
+               return NULL;
+       addr = area->addr;
+-      if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size, flags)) {
++      if (remap_area_pages((unsigned long) addr, phys_addr, size, flags)) {
+               vunmap(addr);
+               return NULL;
+       }
+--- linux-2.6.0-test6/arch/parisc/Kconfig      2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/parisc/Kconfig     2003-10-05 00:33:23.000000000 -0700
+@@ -150,6 +150,7 @@ config COMPAT
+ config HPUX
+       bool "Support for HP-UX binaries"
++      depends on !PARISC64
+ config NR_CPUS
+       int "Maximum number of CPUs (2-32)"
+@@ -190,6 +191,8 @@ source drivers/message/fusion/Kconfig
+ #source drivers/message/i2o/Kconfig
++source "net/Kconfig"
++
+ #source "drivers/isdn/Kconfig"
+ #source "drivers/telephony/Kconfig"
+--- linux-2.6.0-test6/arch/parisc/kernel/asm-offsets.c 2003-06-14 12:17:58.000000000 -0700
++++ 25/arch/parisc/kernel/asm-offsets.c        2003-10-05 00:33:23.000000000 -0700
+@@ -8,6 +8,7 @@
+ #include <linux/sched.h>
+ #include <linux/thread_info.h>
+ #include <linux/version.h>
++#include <linux/ptrace.h>
+ #include <asm/ptrace.h>
+ #include <asm/processor.h>
+@@ -249,5 +250,8 @@ int main(void)
+       DEFINE(DTLB_OFF_COUNT, offsetof(struct pdc_cache_info, dt_off_count));
+       DEFINE(DTLB_LOOP, offsetof(struct pdc_cache_info, dt_loop));
+       BLANK();
++      DEFINE(PA_BLOCKSTEP_BIT, 31-PT_BLOCKSTEP_BIT);
++      DEFINE(PA_SINGLESTEP_BIT, 31-PT_SINGLESTEP_BIT);
++      BLANK();
+       return 0;
+ }
+--- linux-2.6.0-test6/arch/parisc/kernel/binfmt_elf32.c        2003-06-14 12:18:07.000000000 -0700
++++ 25/arch/parisc/kernel/binfmt_elf32.c       2003-10-05 00:33:23.000000000 -0700
+@@ -88,7 +88,9 @@ struct elf_prpsinfo32
+  */
+ #define SET_PERSONALITY(ex, ibcs2) \
+-      current->personality = PER_LINUX_32BIT
++      current->personality = PER_LINUX32; \
++      current->thread.map_base = DEFAULT_MAP_BASE32; \
++      current->thread.task_size = DEFAULT_TASK_SIZE32 \
+ #define jiffies_to_timeval jiffies_to_compat_timeval 
+ static __inline__ void
+@@ -99,3 +101,25 @@ jiffies_to_compat_timeval(unsigned long 
+ }
+ #include "../../../fs/binfmt_elf.c"
++
++/* Set up a separate execution domain for ELF32 binaries running
++ * on an ELF64 kernel */
++
++static struct exec_domain parisc32_exec_domain = { 
++      .name = "Linux/ELF32",
++      .pers_low = PER_LINUX32,
++      .pers_high = PER_LINUX32,
++};      
++
++static int __init parisc32_exec_init(void)
++{
++      /* steal the identity signal mappings from the default domain */
++      parisc32_exec_domain.signal_map = default_exec_domain.signal_map;
++      parisc32_exec_domain.signal_invmap = default_exec_domain.signal_invmap;
++
++      register_exec_domain(&parisc32_exec_domain);
++
++      return 0;
++}
++
++__initcall(parisc32_exec_init);
+--- linux-2.6.0-test6/arch/parisc/kernel/drivers.c     2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/parisc/kernel/drivers.c    2003-10-05 00:33:23.000000000 -0700
+@@ -28,6 +28,7 @@
+ /* See comments in include/asm-parisc/pci.h */
+ struct hppa_dma_ops *hppa_dma_ops;
++EXPORT_SYMBOL(hppa_dma_ops);
+ static struct parisc_device root;
+@@ -155,6 +156,7 @@ int register_parisc_driver(struct parisc
+       return driver_register(&driver->drv);
+ }
++EXPORT_SYMBOL(register_parisc_driver);
+ /**
+  * count_parisc_driver - count # of devices this driver would match
+@@ -187,6 +189,7 @@ int unregister_parisc_driver(struct pari
+       driver_unregister(&driver->drv);
+       return 0;
+ }
++EXPORT_SYMBOL(unregister_parisc_driver);
+ static struct parisc_device *find_device_by_addr(unsigned long hpa)
+ {
+@@ -257,7 +260,7 @@ char *print_pa_hwpath(struct parisc_devi
+       path.mod = dev->hw_path;
+       return print_hwpath(&path, output);
+ }
+-
++EXPORT_SYMBOL(print_pa_hwpath);
+ #if defined(CONFIG_PCI) || defined(CONFIG_ISA)
+ /**
+@@ -289,6 +292,7 @@ void get_pci_node_path(struct pci_dev *d
+               padev = padev->parent;
+       }
+ }
++EXPORT_SYMBOL(get_pci_node_path);
+ /**
+  * print_pci_hwpath - Returns hardware path for PCI devices
+@@ -306,6 +310,8 @@ char *print_pci_hwpath(struct pci_dev *d
+       get_pci_node_path(dev, &path);
+       return print_hwpath(&path, output);
+ }
++EXPORT_SYMBOL(print_pci_hwpath);
++
+ #endif /* defined(CONFIG_PCI) || defined(CONFIG_ISA) */
+--- linux-2.6.0-test6/arch/parisc/kernel/entry.S       2003-06-16 22:32:20.000000000 -0700
++++ 25/arch/parisc/kernel/entry.S      2003-10-05 00:33:23.000000000 -0700
+@@ -2225,18 +2225,23 @@ syscall_exit:
+       LDREG     TI_TASK(%r1),%r1
+       STREG     %r28,TASK_PT_GR28(%r1)
+-      /* Save other hpux returns if personality is PER_HPUX */
++#ifdef CONFIG_HPUX
+ /* <linux/personality.h> cannot be easily included */
+ #define PER_HPUX 0x10
+       LDREG     TASK_PERSONALITY(%r1),%r19
+-#warning the ldo+CMPIB could probably be done better but 0x10 i soutside of range of CMPIB
++
++      /* We can't use "CMPIB<> PER_HPUX" since "im5" field is sign extended */
+       ldo       -PER_HPUX(%r19), %r19
+       CMPIB<>,n 0,%r19,1f
++
++      /* Save other hpux returns if personality is PER_HPUX */
+       STREG     %r22,TASK_PT_GR22(%r1)
+       STREG     %r29,TASK_PT_GR29(%r1)
+ 1:
++#endif /* CONFIG_HPUX */
++
+       /* Seems to me that dp could be wrong here, if the syscall involved
+        * calling a module, and nothing got round to restoring dp on return.
+        */
+@@ -2315,18 +2320,16 @@ syscall_restore:
+       depi    3,31,2,%r31                        /* ensure return to user mode. */
+ #ifdef __LP64__
+-      /* Since we are returning to a 32 bit user process, we always
+-       * clear the W bit. This means that the be (and mtsp) gets
+-       * executed in narrow mode, but that is OK, since we are
+-       * returning to a 32 bit process. When we support 64 bit processes
+-       * we won't clear the W bit, so the be will run in wide mode.
+-       */
+-
+-      be      0(%sr3,%r31)                       /* return to user space */
++      /* decide whether to reset the wide mode bit
++       *
++       * For a syscall, the W bit is stored in the lowest bit
++       * of sp.  Extract it and reset W if it is zero */
++      extrd,u,*<>     %r30,63,1,%r1
+       rsm     PSW_SM_W, %r0
+-#else
+-      be,n    0(%sr3,%r31)                       /* return to user space */
++      /* now reset the lowest bit of sp if it was set */
++      xor     %r30,%r1,%r30
+ #endif
++      be,n    0(%sr3,%r31)                       /* return to user space */
+       /* We have to return via an RFI, so that PSW T and R bits can be set
+        * appropriately.
+@@ -2340,12 +2343,19 @@ syscall_restore_rfi:
+       LDREG   TASK_PT_PSW(%r1),%r2               /* Get old PSW */
+       ldi     0x0b,%r20                          /* Create new PSW */
+       depi    -1,13,1,%r20                       /* C, Q, D, and I bits */
+-      bb,>=,n %r19,15,try_tbit                   /* PT_SINGLESTEP */
++
++      /* The values of PA_SINGLESTEP_BIT and PA_BLOCKSTEP_BIT are
++       * set in include/linux/ptrace.h and converted to PA bitmap
++       * numbers in asm-offsets.c */
++
++      /* if ((%r19.PA_SINGLESTEP_BIT)) { %r20.27=1} */
++      extru,= %r19,PA_SINGLESTEP_BIT,1,%r0
+       depi    -1,27,1,%r20                       /* R bit */
+-try_tbit:
+-      bb,>=,n %r19,14,psw_setup                  /* PT_BLOCKSTEP, see ptrace.c */
++
++      /* if ((%r19.PA_BLOCKSTEP_BIT)) { %r20.7=1} */
++      extru,= %r19,PA_BLOCKSTEP_BIT,1,%r0
+       depi    -1,7,1,%r20                        /* T bit */
+-psw_setup:
++
+       STREG   %r20,TASK_PT_PSW(%r1)
+       /* Always store space registers, since sr3 can be changed (e.g. fork) */
+--- linux-2.6.0-test6/arch/parisc/kernel/firmware.c    2003-06-14 12:17:57.000000000 -0700
++++ 25/arch/parisc/kernel/firmware.c   2003-10-05 00:33:23.000000000 -0700
+@@ -41,19 +41,20 @@
+  *                                    prumpf  991016  
+  */
++#include <stdarg.h>
++
++#include <linux/delay.h>
++#include <linux/init.h>
+ #include <linux/kernel.h>
++#include <linux/module.h>
+ #include <linux/string.h>
+ #include <linux/spinlock.h>
+-#include <linux/init.h>
+-#include <linux/delay.h>
+ #include <asm/page.h>
+ #include <asm/pdc.h>
+ #include <asm/system.h>
+ #include <asm/processor.h>    /* for boot_cpu_data */
+-#include <stdarg.h>
+-
+ static spinlock_t pdc_lock = SPIN_LOCK_UNLOCKED;
+ static unsigned long pdc_result[32] __attribute__ ((aligned (8)));
+ static unsigned long pdc_result2[32] __attribute__ ((aligned (8)));
+@@ -151,6 +152,7 @@ int pdc_add_valid(unsigned long address)
+         return retval;
+ }
++EXPORT_SYMBOL(pdc_add_valid);
+ /**
+  * pdc_chassis_info - Return chassis information.
+@@ -264,6 +266,7 @@ int pdc_iodc_read(unsigned long *actcnt,
+       return retval;
+ }
++EXPORT_SYMBOL(pdc_iodc_read);
+ /**
+  * pdc_system_map_find_mods - Locate unarchitected modules.
+@@ -518,6 +521,7 @@ int pdc_lan_station_id(char *lan_addr, u
+       return retval;
+ }
++EXPORT_SYMBOL(pdc_lan_station_id);
+ /**
+@@ -594,6 +598,7 @@ int pdc_get_initiator( struct hardware_p
+       spin_unlock_irq(&pdc_lock);
+       return retval >= PDC_OK;
+ }
++EXPORT_SYMBOL(pdc_get_initiator);
+ /**
+@@ -660,6 +665,7 @@ int pdc_tod_read(struct pdc_tod *tod)
+         return retval;
+ }
++EXPORT_SYMBOL(pdc_tod_read);
+ /**
+  * pdc_tod_set - Set the Time-Of-Day clock.
+@@ -678,6 +684,7 @@ int pdc_tod_set(unsigned long sec, unsig
+         return retval;
+ }
++EXPORT_SYMBOL(pdc_tod_set);
+ #ifdef __LP64__
+ int pdc_mem_mem_table(struct pdc_memory_table_raddr *r_addr,
+@@ -772,20 +779,34 @@ int pdc_soft_power_button(int sw_control
+ }
+ /*
+- * pdc_suspend_usb - Stop USB controller
++ * pdc_io_reset - Hack to avoid overlapping range registers of Bridges devices.
++ * Primarily a problem on T600 (which parisc-linux doesn't support) but
++ * who knows what other platform firmware might do with this OS "hook".
++ */
++void pdc_io_reset(void)
++{
++      spin_lock_irq(&pdc_lock);  
++      mem_pdc_call(PDC_IO, PDC_IO_RESET, 0);
++      spin_unlock_irq(&pdc_lock);
++}
++
++/*
++ * pdc_io_reset_devices - Hack to Stop USB controller
+  *
+  * If PDC used the usb controller, the usb controller
+  * is still running and will crash the machines during iommu 
+  * setup, because of still running DMA. This PDC call
+- * stops the USB controller
++ * stops the USB controller.
++ * Normally called after calling pdc_io_reset().
+  */
+-void pdc_suspend_usb(void)
++void pdc_io_reset_devices(void)
+ {
+       spin_lock_irq(&pdc_lock);  
+-      mem_pdc_call(PDC_IO, PDC_IO_SUSPEND_USB, 0);
++      mem_pdc_call(PDC_IO, PDC_IO_RESET_DEVICES, 0);
+       spin_unlock_irq(&pdc_lock);
+ }
++
+ /**
+  * pdc_iodc_putc - Console character print using IODC.
+  * @c: the character to output.
+@@ -905,6 +926,7 @@ int pdc_sti_call(unsigned long func, uns
+         return retval;
+ }
++EXPORT_SYMBOL(pdc_sti_call);
+ #ifdef __LP64__
+ /**
+--- linux-2.6.0-test6/arch/parisc/kernel/inventory.c   2003-06-14 12:17:57.000000000 -0700
++++ 25/arch/parisc/kernel/inventory.c  2003-10-05 00:33:23.000000000 -0700
+@@ -526,12 +526,14 @@ static void __init system_map_inventory(
+       int i;
+       long status = PDC_OK;
+     
++#if defined(CONFIG_IOMMU_SBA) && defined(CONFIG_SUPERIO)
+       /*
+-       * first stop the usb controller, otherwise the machine
+-       * might crash during iommu setup
++       * Stop the suckyio usb controller on Astro based systems.
++       * Otherwise the machine might crash during iommu setup.
+        */
+-#warning We still probably need to worry about USB here, but how?
+-        /* pdc_suspend_usb(); */
++      pdc_io_reset();
++      pdc_io_reset_devices();
++#endif
+       for (i = 0; status != PDC_BAD_PROC && status != PDC_NE_MOD; i++) {
+               struct parisc_device *dev;
+--- linux-2.6.0-test6/arch/parisc/kernel/irq.c 2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/parisc/kernel/irq.c        2003-10-05 00:33:23.000000000 -0700
+@@ -193,6 +193,7 @@ void disable_irq(int irq)
+       else
+               BUG();
+ }
++EXPORT_SYMBOL(disable_irq);
+ void enable_irq(int irq)
+ {
+@@ -208,6 +209,7 @@ void enable_irq(int irq)
+       else
+               BUG();
+ }
++EXPORT_SYMBOL(enable_irq);
+ int show_interrupts(struct seq_file *p, void *v)
+ {
+@@ -698,6 +700,7 @@ void synchronize_irq(unsigned int irqnum
+ {
+       while (in_irq()) ;
+ }
++EXPORT_SYMBOL(synchronize_irq);
+ #endif
+@@ -847,6 +850,7 @@ unsigned int probe_irq_mask(unsigned lon
+ {
+       return 0;
+ }
++EXPORT_SYMBOL(probe_irq_mask);
+ void __init init_IRQ(void)
+ {
+--- linux-2.6.0-test6/arch/parisc/kernel/module.c      2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/parisc/kernel/module.c     2003-10-05 00:33:23.000000000 -0700
+@@ -73,10 +73,7 @@ struct got_entry {
+       Elf32_Addr addr;
+ };
+-struct fdesc_entry {
+-      Elf32_Addr addr;
+-      Elf32_Addr gp;
+-};
++#define Elf_Fdesc     Elf32_Fdesc
+ struct stub_entry {
+       Elf32_Word insns[2]; /* each stub entry has two insns */
+@@ -86,11 +83,7 @@ struct got_entry {
+       Elf64_Addr addr;
+ };
+-struct fdesc_entry {
+-      Elf64_Addr dummy[2];
+-      Elf64_Addr addr;
+-      Elf64_Addr gp;
+-};
++#define Elf_Fdesc     Elf64_Fdesc
+ struct stub_entry {
+       Elf64_Word insns[4]; /* each stub entry has four insns */
+@@ -276,7 +269,7 @@ int module_frob_arch_sections(CONST Elf_
+       me->core_size = ALIGN(me->core_size, 16);
+       me->arch.fdesc_offset = me->core_size;
+-      me->core_size += fdescs * sizeof(struct fdesc_entry);
++      me->core_size += fdescs * sizeof(Elf_Fdesc);
+       me->core_size = ALIGN(me->core_size, 16);
+       me->arch.stub_offset = me->core_size;
+@@ -322,7 +315,7 @@ static Elf64_Word get_got(struct module 
+ #ifdef __LP64__
+ static Elf_Addr get_fdesc(struct module *me, unsigned long value)
+ {
+-      struct fdesc_entry *fdesc = me->module_core + me->arch.fdesc_offset;
++      Elf_Fdesc *fdesc = me->module_core + me->arch.fdesc_offset;
+       if (!value) {
+               printk(KERN_ERR "%s: zero OPD requested!\n", me->name);
+@@ -664,7 +657,7 @@ int apply_relocate_add(Elf_Shdr *sechdrs
+                               *loc64 = get_fdesc(me, val+addend);
+                               DEBUGP("FDESC for %s at %p points to %lx\n",
+                                      strtab + sym->st_name, *loc64,
+-                                     ((struct fdesc_entry *)*loc64)->addr);
++                                     ((Elf_Fdesc *)*loc64)->addr);
+                       } else {
+                               /* if the symbol is not local to this
+                                * module then val+addend is a pointer
+@@ -696,10 +689,10 @@ int module_finalize(const Elf_Ehdr *hdr,
+       Elf_Sym *newptr, *oldptr;
+       Elf_Shdr *symhdr = NULL;
+ #ifdef DEBUG
+-      struct fdesc_entry *entry;
++      Elf_Fdesc *entry;
+       u32 *addr;
+-      entry = (struct fdesc_entry *)me->init;
++      entry = (Elf_Fdesc *)me->init;
+       printk("FINALIZE, ->init FPTR is %p, GP %lx ADDR %lx\n", entry,
+              entry->gp, entry->addr);
+       addr = (u32 *)entry->addr;
+--- linux-2.6.0-test6/arch/parisc/kernel/parisc_ksyms.c        2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/parisc/kernel/parisc_ksyms.c       2003-10-05 00:33:23.000000000 -0700
+@@ -26,19 +26,6 @@ EXPORT_SYMBOL(strrchr);
+ EXPORT_SYMBOL(strstr);
+ EXPORT_SYMBOL(strpbrk);
+-#include <asm/hardware.h>     /* struct parisc_device for asm/pci.h */
+-#include <linux/pci.h>
+-EXPORT_SYMBOL(hppa_dma_ops);
+-#if defined(CONFIG_PCI) || defined(CONFIG_ISA)
+-EXPORT_SYMBOL(get_pci_node_path);
+-#endif
+-
+-#include <linux/sched.h>
+-#include <asm/irq.h>
+-EXPORT_SYMBOL(enable_irq);
+-EXPORT_SYMBOL(disable_irq);
+-EXPORT_SYMBOL(probe_irq_mask);
+-
+ #include <asm/processor.h>
+ EXPORT_SYMBOL(kernel_thread);
+ EXPORT_SYMBOL(boot_cpu_data);
+@@ -46,10 +33,6 @@ EXPORT_SYMBOL(boot_cpu_data);
+ #include <linux/pm.h>
+ EXPORT_SYMBOL(pm_power_off);
+-#ifdef CONFIG_SMP
+-EXPORT_SYMBOL(synchronize_irq);
+-#endif /* CONFIG_SMP */
+-
+ #include <asm/atomic.h>
+ EXPORT_SYMBOL(__xchg8);
+ EXPORT_SYMBOL(__xchg32);
+@@ -74,14 +57,6 @@ extern int $global$;
+ EXPORT_SYMBOL($global$);
+ #endif
+-EXPORT_SYMBOL(register_parisc_driver);
+-EXPORT_SYMBOL(unregister_parisc_driver);
+-EXPORT_SYMBOL(print_pci_hwpath);
+-EXPORT_SYMBOL(print_pa_hwpath);
+-EXPORT_SYMBOL(pdc_iodc_read);
+-EXPORT_SYMBOL(pdc_tod_read);
+-EXPORT_SYMBOL(pdc_tod_set);
+-
+ #include <asm/io.h>
+ EXPORT_SYMBOL(__ioremap);
+ EXPORT_SYMBOL(iounmap);
+@@ -89,22 +64,6 @@ EXPORT_SYMBOL(__memcpy_toio);
+ EXPORT_SYMBOL(__memcpy_fromio);
+ EXPORT_SYMBOL(__memset_io);
+-#if defined(CONFIG_PCI) || defined(CONFIG_ISA)
+-EXPORT_SYMBOL(inb);
+-EXPORT_SYMBOL(inw);
+-EXPORT_SYMBOL(inl);
+-EXPORT_SYMBOL(outb);
+-EXPORT_SYMBOL(outw);
+-EXPORT_SYMBOL(outl);
+-
+-EXPORT_SYMBOL(insb);
+-EXPORT_SYMBOL(insw);
+-EXPORT_SYMBOL(insl);
+-EXPORT_SYMBOL(outsb);
+-EXPORT_SYMBOL(outsw);
+-EXPORT_SYMBOL(outsl);
+-#endif
+-
+ #include <asm/cache.h>
+ EXPORT_SYMBOL(flush_kernel_dcache_range_asm);
+ EXPORT_SYMBOL(flush_kernel_dcache_page);
+@@ -130,17 +89,6 @@ EXPORT_SYMBOL(__up);
+ EXPORT_SYMBOL(__down_interruptible);
+ EXPORT_SYMBOL(__down);
+-#include <linux/in6.h>
+-#include <asm/checksum.h>
+-EXPORT_SYMBOL(csum_partial_copy_nocheck);
+-EXPORT_SYMBOL(csum_partial_copy_from_user);
+-
+-#include <asm/pdc.h>
+-EXPORT_SYMBOL(pdc_add_valid);
+-EXPORT_SYMBOL(pdc_lan_station_id);
+-EXPORT_SYMBOL(pdc_get_initiator);
+-EXPORT_SYMBOL(pdc_sti_call);
+-
+ extern void $$divI(void);
+ extern void $$divU(void);
+ extern void $$remI(void);
+@@ -218,6 +166,3 @@ EXPORT_SYMBOL(__moddi3);
+ extern void $$dyncall(void);
+ EXPORT_SYMBOL($$dyncall);
+ #endif
+-
+-#include <asm/pgtable.h>
+-EXPORT_SYMBOL(vmalloc_start);
+--- linux-2.6.0-test6/arch/parisc/kernel/pci.c 2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/parisc/kernel/pci.c        2003-10-05 00:33:23.000000000 -0700
+@@ -88,7 +88,8 @@ u##size in##type (int addr) \
+       EISA_IN(size); \
+       if (!parisc_pci_hba[b]) return (u##size) -1; \
+       return pci_port->in##type(parisc_pci_hba[b], PCI_PORT_ADDR(addr)); \
+-}
++} \
++EXPORT_SYMBOL(in##type);
+ PCI_PORT_IN(b,  8)
+ PCI_PORT_IN(w, 16)
+@@ -102,7 +103,8 @@ void out##type (u##size d, int addr) \
+       EISA_OUT(size); \
+       if (!parisc_pci_hba[b]) return; \
+       pci_port->out##type(parisc_pci_hba[b], PCI_PORT_ADDR(addr), d); \
+-}
++} \
++EXPORT_SYMBOL(out##type);
+ PCI_PORT_OUT(b,  8)
+ PCI_PORT_OUT(w, 16)
+--- linux-2.6.0-test6/arch/parisc/kernel/ptrace.c      2003-06-14 12:17:58.000000000 -0700
++++ 25/arch/parisc/kernel/ptrace.c     2003-10-05 00:33:23.000000000 -0700
+@@ -23,16 +23,6 @@
+ #include <asm/processor.h>
+ #include <asm/offsets.h>
+-/* These are used in entry.S, syscall_restore_rfi.  We need to record the
+- * current stepping mode somewhere other than in PSW, because there is no
+- * concept of saving and restoring the users PSW over a syscall.  We choose
+- * to use these two bits in task->ptrace.  These bits must not clash with
+- * any PT_* defined in include/linux/sched.h, and must match with the bit
+- * tests in entry.S
+- */
+-#define PT_SINGLESTEP 0x10000
+-#define PT_BLOCKSTEP  0x20000
+-
+ /* PSW bits we allow the debugger to modify */
+ #define USER_PSW_BITS (PSW_N | PSW_V | PSW_CB)
+--- linux-2.6.0-test6/arch/parisc/kernel/setup.c       2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/parisc/kernel/setup.c      2003-10-05 00:33:23.000000000 -0700
+@@ -43,6 +43,7 @@
+ #include <asm/led.h>
+ #include <asm/machdep.h>      /* for pa7300lc_init() proto */
+ #include <asm/pdc_chassis.h>
++#include <asm/io.h>
+ #define COMMAND_LINE_SIZE 1024
+ char  saved_command_line[COMMAND_LINE_SIZE];
+@@ -208,27 +209,32 @@ static void __init parisc_proc_mkdir(voi
+                         proc_runway_root = proc_mkdir("bus/runway", 0);
+                 }
+                 break;
++      default:
++              /* FIXME: this was added to prevent the compiler 
++               * complaining about missing pcx, pcxs and pcxt
++               * I'm assuming they have neither gsc nor runway */
++              break;
+       }
+ }
+ static struct resource central_bus = {
+       .name   = "Central Bus",
+-      .start  = (unsigned long)0xfffffffffff80000,
+-      .end    = (unsigned long)0xfffffffffffaffff,
++      .start  = F_EXTEND(0xfff80000),
++      .end    = F_EXTEND(0xfffaffff),
+       .flags  = IORESOURCE_MEM,
+ };
+ static struct resource local_broadcast = {
+       .name   = "Local Broadcast",
+-      .start  = (unsigned long)0xfffffffffffb0000,
+-      .end    = (unsigned long)0xfffffffffffdffff,
++      .start  = F_EXTEND(0xfffb0000),
++      .end    = F_EXTEND(0xfffdffff),
+       .flags  = IORESOURCE_MEM,
+ };
+ static struct resource global_broadcast = {
+       .name   = "Global Broadcast",
+-      .start  = (unsigned long)0xfffffffffffe0000,
+-      .end    = (unsigned long)0xffffffffffffffff,
++      .start  = F_EXTEND(0xfffe0000),
++      .end    = F_EXTEND(0xffffffff),
+       .flags  = IORESOURCE_MEM,
+ };
+--- linux-2.6.0-test6/arch/parisc/kernel/signal.c      2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/parisc/kernel/signal.c     2003-10-05 00:33:23.000000000 -0700
+@@ -25,6 +25,8 @@
+ #include <linux/unistd.h>
+ #include <linux/stddef.h>
+ #include <linux/compat.h>
++#include <linux/elf.h>
++#include <linux/personality.h>
+ #include <asm/ucontext.h>
+ #include <asm/rt_sigframe.h>
+ #include <asm/uaccess.h>
+@@ -41,8 +43,11 @@
+ #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+-/* Use this to get at 32-bit user passed pointers. 
+- *    See sys_sparc32.c for description about these. */
++/* gcc will complain if a pointer is cast to an integer of different
++ * size.  If you really need to do this (and we do for an ELF32 user
++ * application in an ELF64 kernel) then you have to do a cast to an
++ * integer of the same size first.  The A() macro accomplishes
++ * this. */
+ #define A(__x)        ((unsigned long)(__x))
+ int do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall);
+@@ -166,11 +171,17 @@ sys_rt_sigreturn(struct pt_regs *regs, i
+       struct rt_sigframe *frame;
+       struct siginfo si;
+       sigset_t set;
+-      unsigned long usp = regs->gr[30];
++      unsigned long usp = (regs->gr[30] & ~(0x01UL));
++      unsigned long sigframe_size = PARISC_RT_SIGFRAME_SIZE;
++#ifdef __LP64__
++      if(personality(current->personality) == PER_LINUX32)
++              sigframe_size = PARISC_RT_SIGFRAME_SIZE32;
++#endif
++
+       /* Unwind the user stack to get the rt_sigframe structure. */
+       frame = (struct rt_sigframe *)
+-              (usp - PARISC_RT_SIGFRAME_SIZE);
++              (usp - sigframe_size);
+       DBG(("in sys_rt_sigreturn, frame is %p\n", frame));
+       if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+@@ -271,11 +282,12 @@ setup_rt_frame(int sig, struct k_sigacti
+              sigset_t *set, struct pt_regs *regs, int in_syscall)
+ {
+       struct rt_sigframe *frame;
+-      unsigned long rp, usp, haddr;
++      unsigned long rp, usp;
++      unsigned long haddr, sigframe_size;
+       struct siginfo si;
+       int err = 0;
+-      usp = regs->gr[30];
++      usp = (regs->gr[30] & ~(0x01UL));
+       frame = get_sigframe(ka, usp, sizeof(*frame));
+       DBG(("setup_rt_frame 1: frame %p info %p\n", frame, info));
+@@ -308,64 +320,86 @@ setup_rt_frame(int sig, struct k_sigacti
+       }
+ #endif
+-#undef CACHE_FLUSHING_IS_NOT_BROKEN
+-#ifdef CACHE_FLUSHING_IS_NOT_BROKEN
++      flush_user_dcache_range((unsigned long) &frame->tramp[0],
++                         (unsigned long) &frame->tramp[4]);
+       flush_user_icache_range((unsigned long) &frame->tramp[0],
+                          (unsigned long) &frame->tramp[4]);
+-#else
+-      /* It should *always* be cache line-aligned, but the compiler
+-      sometimes screws up. */
+-      asm volatile("fdc 0(%%sr3,%0)\n\t"
+-                   "fdc %1(%%sr3,%0)\n\t"
+-                   "sync\n\t"
+-                   "fic 0(%%sr3,%0)\n\t"
+-                   "fic %1(%%sr3,%0)\n\t"
+-                   "sync\n\t"
+-                    : : "r" (frame->tramp), "r" (L1_CACHE_BYTES));
+-#endif
+       rp = (unsigned long) frame->tramp;
+       if (err)
+               goto give_sigsegv;
+-/* Much more has to happen with signals than this -- but it'll at least */
+-/* provide a pointer to some places which definitely need a look. */
+-#define HACK u32
+-
+-      haddr = (HACK)A(ka->sa.sa_handler);
+-      /* ARGH!  Fucking brain damage.  You don't want to know. */
+-      if (haddr & 2) {
+-              HACK *plabel;
+-              HACK ltp;
+-
+-              plabel = (HACK *) (haddr & ~3);
+-              err |= __get_user(haddr, plabel);
+-              err |= __get_user(ltp, plabel + 1);
++      haddr = A(ka->sa.sa_handler);
++      /* The sa_handler may be a pointer to a function descriptor */
++#ifdef __LP64__
++      if(personality(current->personality) == PER_LINUX32) {
++#endif
++              if (haddr & PA_PLABEL_FDESC) {
++                      Elf32_Fdesc fdesc;
++                      Elf32_Fdesc *ufdesc = (Elf32_Fdesc *)A(haddr & ~3);
++
++                      err = __copy_from_user(&fdesc, ufdesc, sizeof(fdesc));
++
++                      if (err)
++                              goto give_sigsegv;
++
++                      haddr = fdesc.addr;
++                      regs->gr[19] = fdesc.gp;
++              }
++#ifdef __LP64__
++      } else {
++              Elf64_Fdesc fdesc;
++              Elf64_Fdesc *ufdesc = (Elf64_Fdesc *)A(haddr & ~3);
++              
++              err = __copy_from_user(&fdesc, ufdesc, sizeof(fdesc));
++              
+               if (err)
+                       goto give_sigsegv;
+-              regs->gr[19] = ltp;
++              
++              haddr = fdesc.addr;
++              regs->gr[19] = fdesc.gp;
++              DBG(("64 bit signal, exe=%#lx, r19=%#lx, in_syscall=%d\n",
++                   haddr, regs->gr[19], in_syscall));
+       }
++#endif
+       /* The syscall return path will create IAOQ values from r31.
+        */
+-      if (in_syscall)
+-              regs->gr[31] = (HACK) haddr;
+-      else {
+-              regs->gr[0] = USER_PSW;
+-              regs->iaoq[0] = (HACK) haddr | 3;
++      sigframe_size = PARISC_RT_SIGFRAME_SIZE;
++#ifdef __LP64__
++      if(personality(current->personality) == PER_LINUX32)
++              sigframe_size = PARISC_RT_SIGFRAME_SIZE32;
++#endif
++      if (in_syscall) {
++              regs->gr[31] = haddr;
++#ifdef __LP64__
++              if(personality(current->personality) == PER_LINUX)
++                      sigframe_size |= 1;
++#endif
++      } else {
++              unsigned long psw = USER_PSW;
++#ifdef __LP64__
++              if(personality(current->personality) == PER_LINUX)
++                      psw |= PSW_W;
++#endif
++
++              regs->gr[0] = psw;
++              regs->iaoq[0] = haddr | 3;
+               regs->iaoq[1] = regs->iaoq[0] + 4;
+       }
+       regs->gr[2]  = rp;                /* userland return pointer */
+       regs->gr[26] = sig;               /* signal number */
+-      regs->gr[25] = (HACK)A(&frame->info); /* siginfo pointer */
+-      regs->gr[24] = (HACK)A(&frame->uc);   /* ucontext pointer */
++      regs->gr[25] = A(&frame->info); /* siginfo pointer */
++      regs->gr[24] = A(&frame->uc);   /* ucontext pointer */
++      
+       DBG(("making sigreturn frame: %#lx + %#x = %#lx\n",
+-             regs->gr[30], PARISC_RT_SIGFRAME_SIZE,
+-             regs->gr[30] + PARISC_RT_SIGFRAME_SIZE));
++             regs->gr[30], sigframe_size,
++             regs->gr[30] + sigframe_size));
+       /* Raise the user stack pointer to make a proper call frame. */
+-      regs->gr[30] = ((HACK)A(frame) + PARISC_RT_SIGFRAME_SIZE);
++      regs->gr[30] = (A(frame) + sigframe_size);
++
+       DBG(("SIG deliver (%s:%d): frame=0x%p sp=%#lx iaoq=%#lx/%#lx rp=%#lx\n",
+              current->comm, current->pid, frame, regs->gr[30],
+--- linux-2.6.0-test6/arch/parisc/kernel/syscall.S     2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/parisc/kernel/syscall.S    2003-10-05 00:33:23.000000000 -0700
+@@ -69,9 +69,14 @@ linux_gateway_entry:
+        * exit from the syscall, and also use that value to know
+        * whether to do narrow or wide syscalls. -PB
+        */
+-      ssm     PSW_SM_W, %r0
++      ssm     PSW_SM_W, %r1
++      extrd,u %r1,PSW_W_BIT,1,%r1
++      /* sp must be aligned on 4, so deposit the W bit setting into
++       * the bottom of sp temporarily */
++      or,ev   %r1,%r30,%r30
++      b,n     1f
+       /* The top halves of argument registers must be cleared on syscall
+-       * entry.
++       * entry from narrow executable.
+        */
+       depdi   0, 31, 32, %r26
+       depdi   0, 31, 32, %r25
+@@ -79,11 +84,13 @@ linux_gateway_entry:
+       depdi   0, 31, 32, %r23
+       depdi   0, 31, 32, %r22
+       depdi   0, 31, 32, %r21
++1:    
+ #endif
+       mfctl   %cr30,%r1
+       xor     %r1,%r30,%r30                   /* ye olde xor trick */
+       xor     %r1,%r30,%r1
+       xor     %r1,%r30,%r30
++      
+       ldo     THREAD_SZ_ALGN+FRAME_SIZE(%r30),%r30  /* set up kernel stack */
+       /* N.B.: It is critical that we don't set sr7 to 0 until r30
+@@ -104,9 +111,19 @@ linux_gateway_entry:
+          PSW value is stored.  This is needed for gdb and sys_ptrace. */
+       STREG   %r0,  TASK_PT_PSW(%r1)
+       STREG   %r2,  TASK_PT_GR2(%r1)          /* preserve rp */
++      STREG   %r19, TASK_PT_GR19(%r1)
++
+       LDREGM  -FRAME_SIZE(%r30), %r2          /* get users sp back */
++#ifdef __LP64__
++      extrd,u %r2,63,1,%r19                   /* W hidden in bottom bit */
++#if 0
++      xor     %r19,%r2,%r2                    /* clear bottom bit */
++      depd,z  %r19,1,1,%r19
++      std     %r19,TASK_PT_PSW(%r1)
++#endif
++#endif
+       STREG   %r2,  TASK_PT_GR30(%r1)         /* ... and save it */
+-      STREG   %r19, TASK_PT_GR19(%r1)
++      
+       STREG   %r20, TASK_PT_GR20(%r1)
+       STREG   %r21, TASK_PT_GR21(%r1)
+       STREG   %r22, TASK_PT_GR22(%r1)
+@@ -130,6 +147,7 @@ linux_gateway_entry:
+ #ifdef __LP64__
+       ldo     -16(%r30),%r29                  /* Reference param save area */
++      copy    %r19,%r2                        /* W bit back to r2 */
+ #else
+       /* no need to save these on stack in wide mode because the first 8
+        * args are passed in registers */
+@@ -144,9 +162,17 @@ linux_gateway_entry:
+       /* Note!  We cannot use the syscall table that is mapped
+       nearby since the gateway page is mapped execute-only. */
++#ifdef __LP64__
++      ldil    L%sys_call_table, %r1
++      or,=    %r2,%r2,%r2
++      addil   L%(sys_call_table64-sys_call_table), %r1
++      ldo     R%sys_call_table(%r1), %r19
++      or,=    %r2,%r2,%r2
++      ldo     R%sys_call_table64(%r1), %r19
++#else
+       ldil    L%sys_call_table, %r1
+       ldo     R%sys_call_table(%r1), %r19
+-      
++#endif        
+       comiclr,>>=     __NR_Linux_syscalls, %r20, %r0
+       b,n     .Lsyscall_nosys
+       
+@@ -317,304 +343,21 @@ tracesys_sigexit:
+       ldil    L%syscall_exit_rfi,%r1
+       be,n    R%syscall_exit_rfi(%sr7,%r1)
+-#ifdef __LP64__
+-/* Use ENTRY_SAME for 32-bit syscalls which are the same on wide and
+- * narrow palinux.  Use ENTRY_DIFF for those where a 32-bit specific
+- * implementation is required on wide palinux.  Use ENTRY_COMP where
+- * the compatability layer has a useful 32-bit implementation.
+- */
+-#define ENTRY_SAME(_name_) .dword sys_##_name_
+-#define ENTRY_DIFF(_name_) .dword sys32_##_name_
+-#define ENTRY_UHOH(_name_) .dword sys32_##unimplemented
+-#define ENTRY_OURS(_name_) .dword parisc_##_name_
+-#define ENTRY_COMP(_name_) .dword compat_sys_##_name_
+-#else
+-#define ENTRY_SAME(_name_) .word sys_##_name_
+-#define ENTRY_DIFF(_name_) .word sys_##_name_
+-#define ENTRY_UHOH(_name_) .word sys_##_name_
+-#define ENTRY_OURS(_name_) .word parisc_##_name_
+-#define ENTRY_COMP(_name_) .word sys_##_name_
+-#endif
+-
+-      .align 8
++      .align 4096
+       .export sys_call_table
+ .Lsys_call_table:
+ sys_call_table:
+-      ENTRY_SAME(ni_syscall)  /* 0  -  old "setup()" system call*/
+-      ENTRY_SAME(exit)
+-      ENTRY_SAME(fork_wrapper)
+-      ENTRY_SAME(read)
+-      ENTRY_SAME(write)
+-      ENTRY_SAME(open)                /* 5 */
+-      ENTRY_SAME(close)
+-      ENTRY_SAME(waitpid)
+-      ENTRY_SAME(creat)
+-      ENTRY_SAME(link)
+-      ENTRY_SAME(unlink)              /* 10 */
+-      ENTRY_DIFF(execve_wrapper)
+-      ENTRY_SAME(chdir)
+-      /* See comments in kernel/time.c!!! Maybe we don't need this? */
+-      ENTRY_DIFF(time)
+-      ENTRY_SAME(mknod)
+-      ENTRY_SAME(chmod)               /* 15 */
+-      ENTRY_SAME(lchown)
+-      ENTRY_SAME(socket)
+-      /* struct stat is MAYBE identical wide and narrow ?? */
+-      ENTRY_COMP(newstat)
+-      ENTRY_DIFF(lseek)
+-      ENTRY_SAME(getpid)              /* 20 */
+-      /* the 'void * data' parameter may need re-packing in wide */
+-      ENTRY_DIFF(mount)
+-      /* concerned about struct sockaddr in wide/narrow */
+-      /* ---> I think sockaddr is OK unless the compiler packs the struct */
+-      /*      differently to align the char array */
+-      ENTRY_SAME(bind)
+-      ENTRY_SAME(setuid)
+-      ENTRY_SAME(getuid)
+-      ENTRY_SAME(stime)               /* 25 */
+-      ENTRY_SAME(ptrace)
+-      ENTRY_SAME(alarm)
+-      /* see stat comment */
+-      ENTRY_COMP(newfstat)
+-      ENTRY_SAME(pause)
+-      /* struct utimbuf uses time_t which might vary */
+-      ENTRY_COMP(utime)               /* 30 */
+-      /* struct sockaddr... */
+-      ENTRY_SAME(connect)
+-      ENTRY_SAME(listen)
+-      ENTRY_SAME(access)
+-      ENTRY_SAME(nice)
+-      /* struct sockaddr... */
+-      ENTRY_SAME(accept)              /* 35 */
+-      ENTRY_SAME(sync)
+-      ENTRY_SAME(kill)
+-      ENTRY_SAME(rename)
+-      ENTRY_SAME(mkdir)
+-      ENTRY_SAME(rmdir)               /* 40 */
+-      ENTRY_SAME(dup)
+-      ENTRY_SAME(pipe)
+-      ENTRY_COMP(times)
+-      /* struct sockaddr... */
+-      ENTRY_SAME(getsockname)
+-      /* it seems possible brk() could return a >4G pointer... */
+-      ENTRY_SAME(brk)                 /* 45 */
+-      ENTRY_SAME(setgid)
+-      ENTRY_SAME(getgid)
+-      ENTRY_SAME(signal)
+-      ENTRY_SAME(geteuid)
+-      ENTRY_SAME(getegid)             /* 50 */
+-      ENTRY_SAME(acct)
+-      ENTRY_SAME(umount)
+-      /* struct sockaddr... */
+-      ENTRY_SAME(getpeername)
+-      ENTRY_COMP(ioctl)
+-      ENTRY_COMP(fcntl)               /* 55 */
+-      ENTRY_SAME(socketpair)
+-      ENTRY_SAME(setpgid)
+-      ENTRY_SAME(send)
+-      ENTRY_SAME(newuname)
+-      ENTRY_SAME(umask)               /* 60 */
+-      ENTRY_SAME(chroot)
+-      ENTRY_SAME(ustat)
+-      ENTRY_SAME(dup2)
+-      ENTRY_SAME(getppid)
+-      ENTRY_SAME(getpgrp)             /* 65 */
+-      ENTRY_SAME(setsid)
+-      ENTRY_SAME(pivot_root)
+-      /* I don't like this */
+-      ENTRY_UHOH(sgetmask)
+-      ENTRY_UHOH(ssetmask)
+-      ENTRY_SAME(setreuid)            /* 70 */
+-      ENTRY_SAME(setregid)
+-      ENTRY_SAME(mincore)
+-      ENTRY_COMP(sigpending)
+-      ENTRY_SAME(sethostname)
+-      /* Following 3 have linux-common-code structs containing longs -( */
+-      ENTRY_COMP(setrlimit)           /* 75 */
+-      ENTRY_COMP(getrlimit)
+-      ENTRY_COMP(getrusage)
+-      /* struct timeval and timezone are maybe?? consistent wide and narrow */
+-      ENTRY_DIFF(gettimeofday)
+-      ENTRY_DIFF(settimeofday)
+-      ENTRY_SAME(getgroups)           /* 80 */
+-      ENTRY_SAME(setgroups)
+-      /* struct socketaddr... */
+-      ENTRY_SAME(sendto)
+-      ENTRY_SAME(symlink)
+-      /* see stat comment */
+-      ENTRY_COMP(newlstat)
+-      ENTRY_SAME(readlink)            /* 85 */
+-      ENTRY_SAME(ni_syscall)  /* was uselib */
+-      ENTRY_SAME(swapon)
+-      ENTRY_SAME(reboot)
+-      ENTRY_SAME(mmap2)
+-      ENTRY_SAME(mmap)                /* 90 */
+-      ENTRY_SAME(munmap)
+-      ENTRY_SAME(truncate)
+-      ENTRY_SAME(ftruncate)
+-      ENTRY_SAME(fchmod)
+-      ENTRY_SAME(fchown)              /* 95 */
+-      ENTRY_SAME(getpriority)
+-      ENTRY_SAME(setpriority)
+-      ENTRY_SAME(recv)
+-      ENTRY_COMP(statfs)
+-      ENTRY_COMP(fstatfs)             /* 100 */
+-      ENTRY_SAME(stat64)
+-      ENTRY_SAME(ni_syscall)  /* was socketcall */
+-      ENTRY_SAME(syslog)
+-      /* even though manpage says struct timeval contains longs, ours has
+-       * time_t and suseconds_t -- both of which are safe wide/narrow */
+-      ENTRY_COMP(setitimer)
+-      ENTRY_COMP(getitimer)           /* 105 */
+-      ENTRY_SAME(capget)
+-      ENTRY_SAME(capset)
+-      ENTRY_OURS(pread64)
+-      ENTRY_OURS(pwrite64)
+-      ENTRY_SAME(getcwd)              /* 110 */
+-      ENTRY_SAME(vhangup)
+-      ENTRY_SAME(fstat64)
+-      ENTRY_SAME(vfork_wrapper)
+-      /* struct rusage contains longs... */
+-      ENTRY_COMP(wait4)
+-      ENTRY_SAME(swapoff)             /* 115 */
+-      ENTRY_DIFF(sysinfo)
+-      ENTRY_SAME(shutdown)
+-      ENTRY_SAME(fsync)
+-      ENTRY_SAME(madvise)
+-      ENTRY_SAME(clone_wrapper)       /* 120 */
+-      ENTRY_SAME(setdomainname)
+-      ENTRY_DIFF(sendfile)
+-      /* struct sockaddr... */
+-      ENTRY_SAME(recvfrom)
+-      /* struct timex contains longs */
+-      ENTRY_DIFF(adjtimex)
+-      ENTRY_SAME(mprotect)            /* 125 */
+-      /* old_sigset_t forced to 32 bits.  Beware glibc sigset_t */
+-      ENTRY_COMP(sigprocmask)
+-      ENTRY_SAME(ni_syscall)  /* create_module */
+-      ENTRY_SAME(init_module)
+-      ENTRY_SAME(delete_module)
+-      ENTRY_SAME(ni_syscall)          /* 130: get_kernel_syms */
+-      /* time_t inside struct dqblk */
+-      ENTRY_SAME(quotactl)
+-      ENTRY_SAME(getpgid)
+-      ENTRY_SAME(fchdir)
+-      ENTRY_SAME(bdflush)
+-      ENTRY_SAME(sysfs)               /* 135 */
+-      ENTRY_SAME(personality)
+-      ENTRY_SAME(ni_syscall)  /* for afs_syscall */
+-      ENTRY_SAME(setfsuid)
+-      ENTRY_SAME(setfsgid)
+-      /* I think this might work */
+-      ENTRY_SAME(llseek)              /* 140 */
+-      /* struct linux_dirent has longs, like 'unsigned long d_ino' which
+-       * almost definitely should be 'ino_t d_ino' but it's too late now */
+-      ENTRY_DIFF(getdents)
+-      /* it is POSSIBLE that select will be OK because even though fd_set
+-       * contains longs, the macros and sizes are clever. */
+-      ENTRY_DIFF(select)
+-      ENTRY_SAME(flock)
+-      ENTRY_SAME(msync)
+-      /* struct iovec contains pointers */
+-      ENTRY_DIFF(readv)               /* 145 */
+-      ENTRY_DIFF(writev)
+-      ENTRY_SAME(getsid)
+-      ENTRY_SAME(fdatasync)
+-      /* struct __sysctl_args is a mess */
+-      ENTRY_DIFF(sysctl)
+-      ENTRY_SAME(mlock)               /* 150 */
+-      ENTRY_SAME(munlock)
+-      ENTRY_SAME(mlockall)
+-      ENTRY_SAME(munlockall)
+-      /* struct sched_param is ok for now */
+-      ENTRY_SAME(sched_setparam)
+-      ENTRY_SAME(sched_getparam)      /* 155 */
+-      ENTRY_SAME(sched_setscheduler)
+-      ENTRY_SAME(sched_getscheduler)
+-      ENTRY_SAME(sched_yield)
+-      ENTRY_SAME(sched_get_priority_max)
+-      ENTRY_SAME(sched_get_priority_min)      /* 160 */
+-      /* These 2 would've worked if someone had defined struct timespec
+-       * carefully, like timeval for example (which is about the same).
+-       * Unfortunately it contains a long :-( */
+-      ENTRY_DIFF(sched_rr_get_interval)
+-      ENTRY_COMP(nanosleep)
+-      ENTRY_SAME(mremap)
+-      ENTRY_SAME(setresuid)
+-      ENTRY_SAME(getresuid)           /* 165 */
+-      ENTRY_DIFF(sigaltstack_wrapper)
+-      ENTRY_SAME(ni_syscall)          /* query_module */
+-      ENTRY_SAME(poll)
+-      /* structs contain pointers and an in_addr... */
+-      ENTRY_DIFF(nfsservctl)
+-      ENTRY_SAME(setresgid)           /* 170 */
+-      ENTRY_SAME(getresgid)
+-      ENTRY_SAME(prctl)
+-      /* signals need a careful review */
+-      ENTRY_SAME(rt_sigreturn_wrapper)
+-      ENTRY_DIFF(rt_sigaction)
+-      ENTRY_DIFF(rt_sigprocmask)      /* 175 */
+-      ENTRY_DIFF(rt_sigpending)
+-      ENTRY_UHOH(rt_sigtimedwait)
+-      /* even though the struct siginfo_t is different, it appears like
+-       * all the paths use values which should be same wide and narrow.
+-       * Also the struct is padded to 128 bytes which means we don't have
+-       * to worry about faulting trying to copy in a larger 64-bit
+-       * struct from a 32-bit user-space app.
+-       */
+-      ENTRY_SAME(rt_sigqueueinfo)
+-      ENTRY_SAME(rt_sigsuspend_wrapper) /* not really SAME -- see the code */
+-      ENTRY_SAME(chown)               /* 180 */
+-      /* setsockopt() used by iptables: SO_SET_REPLACE/SO_SET_ADD_COUNTERS */
+-      ENTRY_COMP(setsockopt)
+-      ENTRY_SAME(getsockopt)
+-      ENTRY_COMP(sendmsg)
+-      ENTRY_COMP(recvmsg)
+-      ENTRY_SAME(semop)               /* 185 */
+-      ENTRY_SAME(semget)
+-      ENTRY_DIFF(semctl_broken)
+-      ENTRY_DIFF(msgsnd)
+-      ENTRY_DIFF(msgrcv)
+-      ENTRY_SAME(msgget)              /* 190 */
+-      ENTRY_SAME(msgctl_broken)
+-      ENTRY_SAME(shmat_wrapper)
+-      ENTRY_SAME(shmdt)
+-      ENTRY_SAME(shmget)
+-      ENTRY_SAME(shmctl_broken)       /* 195 */
+-      ENTRY_SAME(ni_syscall)          /* streams1 */
+-      ENTRY_SAME(ni_syscall)          /* streams2 */
+-      ENTRY_SAME(lstat64)
+-      ENTRY_OURS(truncate64)
+-      ENTRY_OURS(ftruncate64)         /* 200 */
+-      ENTRY_SAME(getdents64)
+-      ENTRY_COMP(fcntl64)
+-      ENTRY_SAME(ni_syscall)
+-      ENTRY_SAME(ni_syscall)
+-      ENTRY_SAME(ni_syscall)          /* 205 */
+-      ENTRY_SAME(gettid)             
+-      ENTRY_OURS(readahead)          
+-      ENTRY_SAME(ni_syscall)          /* tkill */
+-
+-      ENTRY_SAME(sendfile64)
+-      ENTRY_COMP(futex)               /* 210 */
+-      ENTRY_COMP(sched_setaffinity)
+-      ENTRY_COMP(sched_getaffinity)
+-      ENTRY_SAME(ni_syscall)
+-      ENTRY_SAME(ni_syscall)
+-      ENTRY_SAME(io_setup)            /* 215 */
+-      ENTRY_SAME(io_destroy)
+-      ENTRY_SAME(io_getevents)
+-      ENTRY_SAME(io_submit)
+-      ENTRY_SAME(io_cancel)
+-      ENTRY_SAME(alloc_hugepages)     /* 220 */
+-      ENTRY_SAME(free_hugepages)
+-      ENTRY_SAME(exit_group)
+-      ENTRY_DIFF(lookup_dcookie)
+-      ENTRY_SAME(epoll_create)
+-      ENTRY_SAME(epoll_ctl)           /* 225 */
+-      ENTRY_SAME(epoll_wait)
+-      ENTRY_SAME(remap_file_pages)
++#include "syscall_table.S"
+ .end
++#ifdef __LP64__
++      .align 4096
++      .export sys_call_table64
++.Lsys_call_table64:
++sys_call_table64:
++#define SYSCALL_TABLE_64BIT
++#include "syscall_table.S"
++#endif
++
+       /* Make sure nothing else is placed on this page */
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/arch/parisc/kernel/syscall_table.S      2003-10-05 00:33:23.000000000 -0700
+@@ -0,0 +1,304 @@
++#undef ENTRY_SAME
++#undef ENTRY_DIFF
++#undef ENTRY_UHOH
++#undef ENTRY_COMP
++#undef ENTRY_OURS
++#if defined(__LP64__) && !defined(SYSCALL_TABLE_64BIT)
++/* Use ENTRY_SAME for 32-bit syscalls which are the same on wide and
++ * narrow palinux.  Use ENTRY_DIFF for those where a 32-bit specific
++ * implementation is required on wide palinux.  Use ENTRY_COMP where
++ * the compatability layer has a useful 32-bit implementation.
++ */
++#define ENTRY_SAME(_name_) .dword sys_##_name_
++#define ENTRY_DIFF(_name_) .dword sys32_##_name_
++#define ENTRY_UHOH(_name_) .dword sys32_##unimplemented
++#define ENTRY_OURS(_name_) .dword parisc_##_name_
++#define ENTRY_COMP(_name_) .dword compat_sys_##_name_
++#elif defined(__LP64__) && defined(SYSCALL_TABLE_64BIT)
++#define ENTRY_SAME(_name_) .dword sys_##_name_
++#define ENTRY_DIFF(_name_) .dword sys_##_name_
++#define ENTRY_UHOH(_name_) .dword sys_##_name_
++#define ENTRY_OURS(_name_) .dword sys_##_name_
++#define ENTRY_COMP(_name_) .dword sys_##_name_
++#else
++#define ENTRY_SAME(_name_) .word sys_##_name_
++#define ENTRY_DIFF(_name_) .word sys_##_name_
++#define ENTRY_UHOH(_name_) .word sys_##_name_
++#define ENTRY_OURS(_name_) .word parisc_##_name_
++#define ENTRY_COMP(_name_) .word sys_##_name_
++#endif
++
++      ENTRY_SAME(ni_syscall)  /* 0  -  old "setup()" system call*/
++      ENTRY_SAME(exit)
++      ENTRY_SAME(fork_wrapper)
++      ENTRY_SAME(read)
++      ENTRY_SAME(write)
++      ENTRY_SAME(open)                /* 5 */
++      ENTRY_SAME(close)
++      ENTRY_SAME(waitpid)
++      ENTRY_SAME(creat)
++      ENTRY_SAME(link)
++      ENTRY_SAME(unlink)              /* 10 */
++      ENTRY_DIFF(execve_wrapper)
++      ENTRY_SAME(chdir)
++      /* See comments in kernel/time.c!!! Maybe we don't need this? */
++      ENTRY_DIFF(time)
++      ENTRY_SAME(mknod)
++      ENTRY_SAME(chmod)               /* 15 */
++      ENTRY_SAME(lchown)
++      ENTRY_SAME(socket)
++      /* struct stat is MAYBE identical wide and narrow ?? */
++      ENTRY_COMP(newstat)
++      ENTRY_DIFF(lseek)
++      ENTRY_SAME(getpid)              /* 20 */
++      /* the 'void * data' parameter may need re-packing in wide */
++      ENTRY_DIFF(mount)
++      /* concerned about struct sockaddr in wide/narrow */
++      /* ---> I think sockaddr is OK unless the compiler packs the struct */
++      /*      differently to align the char array */
++      ENTRY_SAME(bind)
++      ENTRY_SAME(setuid)
++      ENTRY_SAME(getuid)
++      ENTRY_SAME(stime)               /* 25 */
++      ENTRY_SAME(ptrace)
++      ENTRY_SAME(alarm)
++      /* see stat comment */
++      ENTRY_COMP(newfstat)
++      ENTRY_SAME(pause)
++      /* struct utimbuf uses time_t which might vary */
++      ENTRY_COMP(utime)               /* 30 */
++      /* struct sockaddr... */
++      ENTRY_SAME(connect)
++      ENTRY_SAME(listen)
++      ENTRY_SAME(access)
++      ENTRY_SAME(nice)
++      /* struct sockaddr... */
++      ENTRY_SAME(accept)              /* 35 */
++      ENTRY_SAME(sync)
++      ENTRY_SAME(kill)
++      ENTRY_SAME(rename)
++      ENTRY_SAME(mkdir)
++      ENTRY_SAME(rmdir)               /* 40 */
++      ENTRY_SAME(dup)
++      ENTRY_SAME(pipe)
++      ENTRY_COMP(times)
++      /* struct sockaddr... */
++      ENTRY_SAME(getsockname)
++      /* it seems possible brk() could return a >4G pointer... */
++      ENTRY_SAME(brk)                 /* 45 */
++      ENTRY_SAME(setgid)
++      ENTRY_SAME(getgid)
++      ENTRY_SAME(signal)
++      ENTRY_SAME(geteuid)
++      ENTRY_SAME(getegid)             /* 50 */
++      ENTRY_SAME(acct)
++      ENTRY_SAME(umount)
++      /* struct sockaddr... */
++      ENTRY_SAME(getpeername)
++      ENTRY_COMP(ioctl)
++      ENTRY_COMP(fcntl)               /* 55 */
++      ENTRY_SAME(socketpair)
++      ENTRY_SAME(setpgid)
++      ENTRY_SAME(send)
++      ENTRY_SAME(newuname)
++      ENTRY_SAME(umask)               /* 60 */
++      ENTRY_SAME(chroot)
++      ENTRY_SAME(ustat)
++      ENTRY_SAME(dup2)
++      ENTRY_SAME(getppid)
++      ENTRY_SAME(getpgrp)             /* 65 */
++      ENTRY_SAME(setsid)
++      ENTRY_SAME(pivot_root)
++      /* I don't like this */
++      ENTRY_UHOH(sgetmask)
++      ENTRY_UHOH(ssetmask)
++      ENTRY_SAME(setreuid)            /* 70 */
++      ENTRY_SAME(setregid)
++      ENTRY_SAME(mincore)
++      ENTRY_COMP(sigpending)
++      ENTRY_SAME(sethostname)
++      /* Following 3 have linux-common-code structs containing longs -( */
++      ENTRY_COMP(setrlimit)           /* 75 */
++      ENTRY_COMP(getrlimit)
++      ENTRY_COMP(getrusage)
++      /* struct timeval and timezone are maybe?? consistent wide and narrow */
++      ENTRY_DIFF(gettimeofday)
++      ENTRY_DIFF(settimeofday)
++      ENTRY_SAME(getgroups)           /* 80 */
++      ENTRY_SAME(setgroups)
++      /* struct socketaddr... */
++      ENTRY_SAME(sendto)
++      ENTRY_SAME(symlink)
++      /* see stat comment */
++      ENTRY_COMP(newlstat)
++      ENTRY_SAME(readlink)            /* 85 */
++      ENTRY_SAME(ni_syscall)  /* was uselib */
++      ENTRY_SAME(swapon)
++      ENTRY_SAME(reboot)
++      ENTRY_SAME(mmap2)
++      ENTRY_SAME(mmap)                /* 90 */
++      ENTRY_SAME(munmap)
++      ENTRY_SAME(truncate)
++      ENTRY_SAME(ftruncate)
++      ENTRY_SAME(fchmod)
++      ENTRY_SAME(fchown)              /* 95 */
++      ENTRY_SAME(getpriority)
++      ENTRY_SAME(setpriority)
++      ENTRY_SAME(recv)
++      ENTRY_COMP(statfs)
++      ENTRY_COMP(fstatfs)             /* 100 */
++      ENTRY_SAME(stat64)
++      ENTRY_SAME(ni_syscall)  /* was socketcall */
++      ENTRY_SAME(syslog)
++      /* even though manpage says struct timeval contains longs, ours has
++       * time_t and suseconds_t -- both of which are safe wide/narrow */
++      ENTRY_COMP(setitimer)
++      ENTRY_COMP(getitimer)           /* 105 */
++      ENTRY_SAME(capget)
++      ENTRY_SAME(capset)
++      ENTRY_OURS(pread64)
++      ENTRY_OURS(pwrite64)
++      ENTRY_SAME(getcwd)              /* 110 */
++      ENTRY_SAME(vhangup)
++      ENTRY_SAME(fstat64)
++      ENTRY_SAME(vfork_wrapper)
++      /* struct rusage contains longs... */
++      ENTRY_COMP(wait4)
++      ENTRY_SAME(swapoff)             /* 115 */
++      ENTRY_DIFF(sysinfo)
++      ENTRY_SAME(shutdown)
++      ENTRY_SAME(fsync)
++      ENTRY_SAME(madvise)
++      ENTRY_SAME(clone_wrapper)       /* 120 */
++      ENTRY_SAME(setdomainname)
++      ENTRY_DIFF(sendfile)
++      /* struct sockaddr... */
++      ENTRY_SAME(recvfrom)
++      /* struct timex contains longs */
++      ENTRY_DIFF(adjtimex)
++      ENTRY_SAME(mprotect)            /* 125 */
++      /* old_sigset_t forced to 32 bits.  Beware glibc sigset_t */
++      ENTRY_COMP(sigprocmask)
++      ENTRY_SAME(ni_syscall)  /* create_module */
++      ENTRY_SAME(init_module)
++      ENTRY_SAME(delete_module)
++      ENTRY_SAME(ni_syscall)          /* 130: get_kernel_syms */
++      /* time_t inside struct dqblk */
++      ENTRY_SAME(quotactl)
++      ENTRY_SAME(getpgid)
++      ENTRY_SAME(fchdir)
++      ENTRY_SAME(bdflush)
++      ENTRY_SAME(sysfs)               /* 135 */
++      ENTRY_SAME(personality)
++      ENTRY_SAME(ni_syscall)  /* for afs_syscall */
++      ENTRY_SAME(setfsuid)
++      ENTRY_SAME(setfsgid)
++      /* I think this might work */
++      ENTRY_SAME(llseek)              /* 140 */
++      /* struct linux_dirent has longs, like 'unsigned long d_ino' which
++       * almost definitely should be 'ino_t d_ino' but it's too late now */
++      ENTRY_DIFF(getdents)
++      /* it is POSSIBLE that select will be OK because even though fd_set
++       * contains longs, the macros and sizes are clever. */
++      ENTRY_DIFF(select)
++      ENTRY_SAME(flock)
++      ENTRY_SAME(msync)
++      /* struct iovec contains pointers */
++      ENTRY_DIFF(readv)               /* 145 */
++      ENTRY_DIFF(writev)
++      ENTRY_SAME(getsid)
++      ENTRY_SAME(fdatasync)
++      /* struct __sysctl_args is a mess */
++      ENTRY_DIFF(sysctl)
++      ENTRY_SAME(mlock)               /* 150 */
++      ENTRY_SAME(munlock)
++      ENTRY_SAME(mlockall)
++      ENTRY_SAME(munlockall)
++      /* struct sched_param is ok for now */
++      ENTRY_SAME(sched_setparam)
++      ENTRY_SAME(sched_getparam)      /* 155 */
++      ENTRY_SAME(sched_setscheduler)
++      ENTRY_SAME(sched_getscheduler)
++      ENTRY_SAME(sched_yield)
++      ENTRY_SAME(sched_get_priority_max)
++      ENTRY_SAME(sched_get_priority_min)      /* 160 */
++      /* These 2 would've worked if someone had defined struct timespec
++       * carefully, like timeval for example (which is about the same).
++       * Unfortunately it contains a long :-( */
++      ENTRY_DIFF(sched_rr_get_interval)
++      ENTRY_COMP(nanosleep)
++      ENTRY_SAME(mremap)
++      ENTRY_SAME(setresuid)
++      ENTRY_SAME(getresuid)           /* 165 */
++      ENTRY_DIFF(sigaltstack_wrapper)
++      ENTRY_SAME(ni_syscall)          /* query_module */
++      ENTRY_SAME(poll)
++      /* structs contain pointers and an in_addr... */
++      ENTRY_DIFF(nfsservctl)
++      ENTRY_SAME(setresgid)           /* 170 */
++      ENTRY_SAME(getresgid)
++      ENTRY_SAME(prctl)
++      /* signals need a careful review */
++      ENTRY_SAME(rt_sigreturn_wrapper)
++      ENTRY_DIFF(rt_sigaction)
++      ENTRY_DIFF(rt_sigprocmask)      /* 175 */
++      ENTRY_DIFF(rt_sigpending)
++      ENTRY_UHOH(rt_sigtimedwait)
++      /* even though the struct siginfo_t is different, it appears like
++       * all the paths use values which should be same wide and narrow.
++       * Also the struct is padded to 128 bytes which means we don't have
++       * to worry about faulting trying to copy in a larger 64-bit
++       * struct from a 32-bit user-space app.
++       */
++      ENTRY_SAME(rt_sigqueueinfo)
++      ENTRY_SAME(rt_sigsuspend_wrapper) /* not really SAME -- see the code */
++      ENTRY_SAME(chown)               /* 180 */
++      /* setsockopt() used by iptables: SO_SET_REPLACE/SO_SET_ADD_COUNTERS */
++      ENTRY_COMP(setsockopt)
++      ENTRY_SAME(getsockopt)
++      ENTRY_COMP(sendmsg)
++      ENTRY_COMP(recvmsg)
++      ENTRY_SAME(semop)               /* 185 */
++      ENTRY_SAME(semget)
++      ENTRY_DIFF(semctl_broken)
++      ENTRY_DIFF(msgsnd)
++      ENTRY_DIFF(msgrcv)
++      ENTRY_SAME(msgget)              /* 190 */
++      ENTRY_SAME(msgctl_broken)
++      ENTRY_SAME(shmat_wrapper)
++      ENTRY_SAME(shmdt)
++      ENTRY_SAME(shmget)
++      ENTRY_SAME(shmctl_broken)       /* 195 */
++      ENTRY_SAME(ni_syscall)          /* streams1 */
++      ENTRY_SAME(ni_syscall)          /* streams2 */
++      ENTRY_SAME(lstat64)
++      ENTRY_OURS(truncate64)
++      ENTRY_OURS(ftruncate64)         /* 200 */
++      ENTRY_SAME(getdents64)
++      ENTRY_COMP(fcntl64)
++      ENTRY_SAME(ni_syscall)
++      ENTRY_SAME(ni_syscall)
++      ENTRY_SAME(ni_syscall)          /* 205 */
++      ENTRY_SAME(gettid)             
++      ENTRY_OURS(readahead)          
++      ENTRY_SAME(ni_syscall)          /* tkill */
++
++      ENTRY_SAME(sendfile64)
++      ENTRY_COMP(futex)               /* 210 */
++      ENTRY_COMP(sched_setaffinity)
++      ENTRY_COMP(sched_getaffinity)
++      ENTRY_SAME(ni_syscall)
++      ENTRY_SAME(ni_syscall)
++      ENTRY_SAME(io_setup)            /* 215 */
++      ENTRY_SAME(io_destroy)
++      ENTRY_SAME(io_getevents)
++      ENTRY_SAME(io_submit)
++      ENTRY_SAME(io_cancel)
++      ENTRY_SAME(alloc_hugepages)     /* 220 */
++      ENTRY_SAME(free_hugepages)
++      ENTRY_SAME(exit_group)
++      ENTRY_DIFF(lookup_dcookie)
++      ENTRY_SAME(epoll_create)
++      ENTRY_SAME(epoll_ctl)           /* 225 */
++      ENTRY_SAME(epoll_wait)
++      ENTRY_SAME(remap_file_pages)
+--- linux-2.6.0-test6/arch/parisc/kernel/sys_parisc.c  2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/parisc/kernel/sys_parisc.c 2003-10-05 00:34:08.000000000 -0700
+@@ -65,7 +65,7 @@ static int get_offset(struct address_spa
+  */
+ static int get_offset(struct address_space *mapping)
+ {
+-      int offset = (int) mapping << (PAGE_SHIFT - 8);
++      int offset = (unsigned long) mapping << (PAGE_SHIFT - 8);
+       return offset & 0x3FF000;
+ }
+ #endif
+@@ -93,17 +93,13 @@ static unsigned long get_shared_area(str
+ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
+               unsigned long len, unsigned long pgoff, unsigned long flags)
+ {
+-      struct inode *inode;
+-
+       if (len > TASK_SIZE)
+               return -ENOMEM;
+       if (!addr)
+               addr = TASK_UNMAPPED_BASE;
+-      inode = filp ? filp->f_dentry->d_inode : NULL;
+-
+-      if (inode && (flags & MAP_SHARED)) {
+-              addr = get_shared_area(inode->i_mapping, addr, len, pgoff);
++      if (filp && (flags & MAP_SHARED)) {
++              addr = get_shared_area(filp->f_mapping, addr, len, pgoff);
+       } else {
+               addr = get_unshared_area(addr, len);
+       }
+@@ -165,12 +161,13 @@ long sys_shmat_wrapper(int shmid, char *
+       return raddr;
+ }
+-
+ /* Fucking broken ABI */
+ #ifdef CONFIG_PARISC64
+ extern asmlinkage long sys_truncate(const char *, unsigned long);
+ extern asmlinkage long sys_ftruncate(unsigned int, unsigned long);
++extern asmlinkage long sys_fcntl(unsigned int, unsigned int, unsigned long);
++
+ asmlinkage long parisc_truncate64(const char * path,
+                                       unsigned int high, unsigned int low)
+ {
+@@ -182,6 +179,21 @@ asmlinkage long parisc_ftruncate64(unsig
+ {
+       return sys_ftruncate(fd, (long)high << 32 | low);
+ }
++
++/* stubs for the benefit of the syscall_table since truncate64 and truncate 
++ * are identical on LP64 */
++asmlinkage long sys_truncate64(const char * path, unsigned long length)
++{
++      return sys_truncate(path, length);
++}
++asmlinkage long sys_ftruncate64(unsigned int fd, unsigned long length)
++{
++      return sys_ftruncate(fd, length);
++}
++asmlinkage long sys_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg)
++{
++      return sys_fcntl(fd, cmd, arg);
++}
+ #else
+ extern asmlinkage long sys_truncate64(const char *, loff_t);
+--- linux-2.6.0-test6/arch/parisc/kernel/time.c        2003-07-13 21:44:34.000000000 -0700
++++ 25/arch/parisc/kernel/time.c       2003-10-05 00:33:23.000000000 -0700
+@@ -48,7 +48,9 @@ static inline void
+ parisc_do_profile(struct pt_regs *regs)
+ {
+       unsigned long pc = regs->iaoq[0];
++#if 0
+       extern unsigned long prof_cpu_mask;
++#endif
+       extern char _stext;
+       profile_hook(regs);
+@@ -60,6 +62,10 @@ parisc_do_profile(struct pt_regs *regs)
+               return;
+ #if 0
++      /* FIXME: when we have irq affinity to cpu, we need to
++       * only look at the cpus specified in this mask 
++       */
++
+       if (!((1 << smp_processor_id()) & prof_cpu_mask))
+               return;
+ #endif
+@@ -206,7 +212,6 @@ do_settimeofday (struct timespec *tv)
+                * done, and then undo it!
+                */
+               nsec -= gettimeoffset() * 1000;
+-              nsec -= (jiffies - wall_jiffies) * (NSEC_PER_SEC / HZ);
+               wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
+               wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
+@@ -223,6 +228,16 @@ do_settimeofday (struct timespec *tv)
+       return 0;
+ }
++/*
++ * XXX: We can do better than this.
++ * Returns nanoseconds
++ */
++
++unsigned long long sched_clock(void)
++{
++      return (unsigned long long)jiffies * (1000000000 / HZ);
++}
++
+ void __init time_init(void)
+ {
+--- linux-2.6.0-test6/arch/parisc/kernel/traps.c       2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/parisc/kernel/traps.c      2003-10-05 00:33:23.000000000 -0700
+@@ -678,12 +678,13 @@ void handle_interruption(int code, struc
+       }
+       if (user_mode(regs)) {
+-          if (fault_space != regs->sr[7]) {
++          if ((fault_space>>SPACEID_SHIFT) != (regs->sr[7] >> SPACEID_SHIFT)) {
+ #ifdef PRINT_USER_FAULTS
+               if (fault_space == 0)
+                       printk(KERN_DEBUG "User Fault on Kernel Space ");
+               else
+-                      printk(KERN_DEBUG "User Fault (long pointer) ");
++                      printk(KERN_DEBUG "User Fault (long pointer) (fault %d) ",
++                             code);
+               printk("pid=%d command='%s'\n", current->pid, current->comm);
+               show_regs(regs);
+ #endif
+--- linux-2.6.0-test6/arch/parisc/kernel/unaligned.c   2003-07-13 21:44:34.000000000 -0700
++++ 25/arch/parisc/kernel/unaligned.c  2003-10-05 00:33:23.000000000 -0700
+@@ -369,8 +369,8 @@ static int emulate_std(struct pt_regs *r
+ void handle_unaligned(struct pt_regs *regs)
+ {
+-      unsigned long unaligned_count = 0;
+-      unsigned long last_time = 0;
++      static unsigned long unaligned_count = 0;
++      static unsigned long last_time = 0;
+       unsigned long newbase = R1(regs->iir)?regs->gr[R1(regs->iir)]:0;
+       int modify = 0;
+       int ret = -1;
+@@ -380,7 +380,6 @@ void handle_unaligned(struct pt_regs *re
+       /* if the unaligned access is inside the kernel:
+        *   if the access is caused by a syscall, then we fault the calling
+        *     user process
+-       *   otherwise we halt the kernel
+        */
+       if (!user_mode(regs))
+       {
+@@ -427,10 +426,10 @@ void handle_unaligned(struct pt_regs *re
+                       show_regs(regs);
+ #endif                
+               }
+-      }
+-      if (!unaligned_enabled)
+-              goto force_sigbus;
++              if (!unaligned_enabled)
++                      goto force_sigbus;
++      }
+       /* handle modification - OK, it's ugly, see the instruction manual */
+       switch (MAJOR_OP(regs->iir))
+--- linux-2.6.0-test6/arch/parisc/lib/checksum.c       2003-06-14 12:18:24.000000000 -0700
++++ 25/arch/parisc/lib/checksum.c      2003-10-05 00:33:23.000000000 -0700
+@@ -16,8 +16,10 @@
+  *
+  * $Id: 2.6.0-test6-mm4.patch,v 1.1.4.1 2003/10/10 09:31:08 ericm Exp $
+  */
+-#include <net/checksum.h>
++#include <linux/module.h>
+ #include <linux/types.h>
++
++#include <net/checksum.h>
+ #include <asm/byteorder.h>
+ #include <asm/string.h>
+ #include <asm/uaccess.h>
+@@ -109,6 +111,7 @@ unsigned int csum_partial_copy_nocheck(c
+       return sum;
+ }
++EXPORT_SYMBOL(csum_partial_copy_nocheck);
+ /*
+  * Copy from userspace and compute checksum.  If we catch an exception
+@@ -128,3 +131,4 @@ unsigned int csum_partial_copy_from_user
+               
+       return csum_partial(dst, len, sum);
+ }
++EXPORT_SYMBOL(csum_partial_copy_from_user);
+--- linux-2.6.0-test6/arch/parisc/lib/io.c     2003-06-14 12:17:58.000000000 -0700
++++ 25/arch/parisc/lib/io.c    2003-10-05 00:33:23.000000000 -0700
+@@ -8,6 +8,7 @@
+  */
+ #include <linux/kernel.h>
++#include <linux/module.h>
+ #include <asm/io.h>
+ /* Copies a block of memory to a device in an efficient manner.
+@@ -457,3 +458,10 @@ void outsl (unsigned long port, const vo
+               break;
+       }
+ }
++
++EXPORT_SYMBOL(insb);
++EXPORT_SYMBOL(insw);
++EXPORT_SYMBOL(insl);
++EXPORT_SYMBOL(outsb);
++EXPORT_SYMBOL(outsw);
++EXPORT_SYMBOL(outsl);
+--- linux-2.6.0-test6/arch/parisc/math-emu/denormal.c  2003-06-14 12:18:09.000000000 -0700
++++ 25/arch/parisc/math-emu/denormal.c 2003-10-05 00:33:23.000000000 -0700
+@@ -47,7 +47,7 @@
+ #include "sgl_float.h"
+ #include "dbl_float.h"
+ #include "hppa.h"
+-#include "types.h"
++#include <linux/kernel.h>
+ /* #include <machine/sys/mdep_private.h> */
+ #undef Fpustatus_register
+--- linux-2.6.0-test6/arch/parisc/math-emu/fpudispatch.c       2003-06-14 12:17:56.000000000 -0700
++++ 25/arch/parisc/math-emu/fpudispatch.c      2003-10-05 00:33:23.000000000 -0700
+@@ -50,7 +50,7 @@
+ #define FPUDEBUG 0
+ #include "float.h"
+-#include "types.h"
++#include <linux/kernel.h>
+ #include <asm/processor.h>
+ /* #include <sys/debug.h> */
+ /* #include <machine/sys/mdep_private.h> */
+--- linux-2.6.0-test6/arch/parisc/math-emu/Makefile    2003-06-14 12:18:09.000000000 -0700
++++ 25/arch/parisc/math-emu/Makefile   2003-10-05 00:33:23.000000000 -0700
+@@ -2,6 +2,11 @@
+ # Makefile for the linux/parisc floating point code
+ #
++# See arch/parisc/math-emu/README
++CFLAGS += -Wno-parentheses -Wno-implicit-function-declaration \
++      -Wno-uninitialized -Wno-strict-prototypes -Wno-return-type \
++      -Wno-implicit-int
++
+ obj-y  := frnd.o driver.o decode_exc.o fpudispatch.o denormal.o \
+               dfmpy.o sfmpy.o sfsqrt.o dfsqrt.o dfadd.o fmpyfadd.o \
+               sfadd.o dfsub.o sfsub.o fcnvfxt.o fcnvff.o fcnvxf.o \
+--- linux-2.6.0-test6/arch/parisc/math-emu/types.h     2003-06-14 12:18:00.000000000 -0700
++++ /dev/null  2002-08-30 16:31:37.000000000 -0700
+@@ -1,25 +0,0 @@
+-/*
+- * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+- *
+- * Floating-point emulation code
+- *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+- *
+- *    This program is free software; you can redistribute it and/or modify
+- *    it under the terms of the GNU General Public License as published by
+- *    the Free Software Foundation; either version 2, or (at your option)
+- *    any later version.
+- *
+- *    This program is distributed in the hope that it will be useful,
+- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- *    GNU General Public License for more details.
+- *
+- *    You should have received a copy of the GNU General Public License
+- *    along with this program; if not, write to the Free Software
+- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+- */
+-
+-#include <linux/kernel.h>
+-#define BUG() do { \
+-        printk(KERN_ERR "floating-pt emulation BUG at %s:%d!\n", __FILE__, __LINE__); \
+-} while (0)
+--- linux-2.6.0-test6/arch/parisc/mm/init.c    2003-06-16 22:32:20.000000000 -0700
++++ 25/arch/parisc/mm/init.c   2003-10-05 00:33:23.000000000 -0700
+@@ -430,6 +430,8 @@ void free_initmem(void)
+                                    & ~(VM_MAP_OFFSET-1)))
+ void *vmalloc_start;
++EXPORT_SYMBOL(vmalloc_start);
++
+ #ifdef CONFIG_PA11
+ unsigned long pcxl_dma_start;
+ #endif
+@@ -618,8 +620,6 @@ static void __init pagetable_init(void)
+ {
+       int range;
+-      printk("pagetable_init\n");
+-
+       /* Map each physical memory range to its kernel vaddr */
+       for (range = 0; range < npmem_ranges; range++) {
+--- linux-2.6.0-test6/arch/parisc/mm/ioremap.c 2003-06-14 12:18:07.000000000 -0700
++++ 25/arch/parisc/mm/ioremap.c        2003-10-05 00:33:23.000000000 -0700
+@@ -159,7 +159,7 @@ void * __ioremap(unsigned long phys_addr
+       if (!area)
+               return NULL;
+       addr = area->addr;
+-      if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size, flags)) {
++      if (remap_area_pages((unsigned long) addr, phys_addr, size, flags)) {
+               vfree(addr);
+               return NULL;
+       }
+--- linux-2.6.0-test6/arch/ppc64/kernel/ioctl32.c      2003-09-08 13:58:56.000000000 -0700
++++ 25/arch/ppc64/kernel/ioctl32.c     2003-10-05 00:34:44.000000000 -0700
+@@ -328,396 +328,6 @@ static int do_ncp_setprivatedata(unsigne
+       return err;
+ }
+-struct usbdevfs_ctrltransfer32 {
+-      __u8 bRequestType;
+-      __u8 bRequest;
+-      __u16 wValue;
+-      __u16 wIndex;
+-      __u16 wLength;
+-      __u32 timeout;  /* in milliseconds */
+-      __u32 data;
+-};
+-
+-#define USBDEVFS_CONTROL32           _IOWR('U', 0, struct usbdevfs_ctrltransfer32)
+-
+-static int do_usbdevfs_control(unsigned int fd, unsigned int cmd, unsigned long arg)
+-{
+-      struct usbdevfs_ctrltransfer kctrl;
+-      struct usbdevfs_ctrltransfer32 *uctrl;
+-      mm_segment_t old_fs;
+-      __u32 udata;
+-      void *uptr, *kptr;
+-      int err;
+-
+-      uctrl = (struct usbdevfs_ctrltransfer32 *) arg;
+-
+-      if (copy_from_user(&kctrl, uctrl,
+-                         (sizeof(struct usbdevfs_ctrltransfer) -
+-                          sizeof(void *))))
+-              return -EFAULT;
+-
+-      if (get_user(udata, &uctrl->data))
+-              return -EFAULT;
+-      uptr = (void *) A(udata);
+-
+-      /* In usbdevice_fs, it limits the control buffer to a page,
+-       * for simplicity so do we.
+-       */
+-      if (!uptr || kctrl.wLength > PAGE_SIZE)
+-              return -EINVAL;
+-
+-      kptr = (void *)__get_free_page(GFP_KERNEL);
+-
+-      if ((kctrl.bRequestType & 0x80) == 0) {
+-              err = -EFAULT;
+-              if (copy_from_user(kptr, uptr, kctrl.wLength))
+-                      goto out;
+-      }
+-
+-      kctrl.data = kptr;
+-
+-      old_fs = get_fs();
+-      set_fs(KERNEL_DS);
+-      err = sys_ioctl(fd, USBDEVFS_CONTROL, (unsigned long)&kctrl);
+-      set_fs(old_fs);
+-
+-      if (err >= 0 &&
+-          ((kctrl.bRequestType & 0x80) != 0)) {
+-              if (copy_to_user(uptr, kptr, kctrl.wLength))
+-                      err = -EFAULT;
+-      }
+-
+-out:
+-      free_page((unsigned long) kptr);
+-      return err;
+-}
+-
+-struct usbdevfs_bulktransfer32 {
+-      unsigned int ep;
+-      unsigned int len;
+-      unsigned int timeout; /* in milliseconds */
+-      __u32 data;
+-};
+-
+-#define USBDEVFS_BULK32              _IOWR('U', 2, struct usbdevfs_bulktransfer32)
+-
+-static int do_usbdevfs_bulk(unsigned int fd, unsigned int cmd, unsigned long arg)
+-{
+-      struct usbdevfs_bulktransfer kbulk;
+-      struct usbdevfs_bulktransfer32 *ubulk;
+-      mm_segment_t old_fs;
+-      __u32 udata;
+-      void *uptr, *kptr;
+-      int err;
+-
+-      ubulk = (struct usbdevfs_bulktransfer32 *) arg;
+-
+-      if (get_user(kbulk.ep, &ubulk->ep) ||
+-          get_user(kbulk.len, &ubulk->len) ||
+-          get_user(kbulk.timeout, &ubulk->timeout) ||
+-          get_user(udata, &ubulk->data))
+-              return -EFAULT;
+-
+-      uptr = (void *) A(udata);
+-
+-      /* In usbdevice_fs, it limits the control buffer to a page,
+-       * for simplicity so do we.
+-       */
+-      if (!uptr || kbulk.len > PAGE_SIZE)
+-              return -EINVAL;
+-
+-      kptr = (void *) __get_free_page(GFP_KERNEL);
+-
+-      if ((kbulk.ep & 0x80) == 0) {
+-              err = -EFAULT;
+-              if (copy_from_user(kptr, uptr, kbulk.len))
+-                      goto out;
+-      }
+-
+-      kbulk.data = kptr;
+-
+-      old_fs = get_fs();
+-      set_fs(KERNEL_DS);
+-      err = sys_ioctl(fd, USBDEVFS_BULK, (unsigned long) &kbulk);
+-      set_fs(old_fs);
+-
+-      if (err >= 0 &&
+-          ((kbulk.ep & 0x80) != 0)) {
+-              if (copy_to_user(uptr, kptr, kbulk.len))
+-                      err = -EFAULT;
+-      }
+-
+-out:
+-      free_page((unsigned long) kptr);
+-      return err;
+-}
+-
+-/* This needs more work before we can enable it.  Unfortunately
+- * because of the fancy asynchronous way URB status/error is written
+- * back to userspace, we'll need to fiddle with USB devio internals
+- * and/or reimplement entirely the frontend of it ourselves. -DaveM
+- *
+- * The issue is:
+- *
+- *    When an URB is submitted via usbdevicefs it is put onto an
+- *    asynchronous queue.  When the URB completes, it may be reaped
+- *    via another ioctl.  During this reaping the status is written
+- *    back to userspace along with the length of the transfer.
+- *
+- *    We must translate into 64-bit kernel types so we pass in a kernel
+- *    space copy of the usbdevfs_urb structure.  This would mean that we
+- *    must do something to deal with the async entry reaping.  First we
+- *    have to deal somehow with this transitory memory we've allocated.
+- *    This is problematic since there are many call sites from which the
+- *    async entries can be destroyed (and thus when we'd need to free up
+- *    this kernel memory).  One of which is the close() op of usbdevicefs.
+- *    To handle that we'd need to make our own file_operations struct which
+- *    overrides usbdevicefs's release op with our own which runs usbdevicefs's
+- *    real release op then frees up the kernel memory.
+- *
+- *    But how to keep track of these kernel buffers?  We'd need to either
+- *    keep track of them in some table _or_ know about usbdevicefs internals
+- *    (ie. the exact layout of its file private, which is actually defined
+- *    in linux/usbdevice_fs.h, the layout of the async queues are private to
+- *    devio.c)
+- *
+- * There is one possible other solution I considered, also involving knowledge
+- * of usbdevicefs internals:
+- *
+- *    After an URB is submitted, we "fix up" the address back to the user
+- *    space one.  This would work if the status/length fields written back
+- *    by the async URB completion lines up perfectly in the 32-bit type with
+- *    the 64-bit kernel type.  Unfortunately, it does not because the iso
+- *    frame descriptors, at the end of the struct, can be written back.
+- *
+- * I think we'll just need to simply duplicate the devio URB engine here.
+- */
+-#if 0
+-struct usbdevfs_urb32 {
+-      __u8 type;
+-      __u8 endpoint;
+-      __s32 status;
+-      __u32 flags;
+-      __u32 buffer;
+-      __s32 buffer_length;
+-      __s32 actual_length;
+-      __s32 start_frame;
+-      __s32 number_of_packets;
+-      __s32 error_count;
+-      __u32 signr;
+-      __u32 usercontext; /* unused */
+-      struct usbdevfs_iso_packet_desc iso_frame_desc[0];
+-};
+-
+-#define USBDEVFS_SUBMITURB32       _IOR('U', 10, struct usbdevfs_urb32)
+-
+-static int get_urb32(struct usbdevfs_urb *kurb,
+-                   struct usbdevfs_urb32 *uurb)
+-{
+-      if (get_user(kurb->type, &uurb->type) ||
+-          __get_user(kurb->endpoint, &uurb->endpoint) ||
+-          __get_user(kurb->status, &uurb->status) ||
+-          __get_user(kurb->flags, &uurb->flags) ||
+-          __get_user(kurb->buffer_length, &uurb->buffer_length) ||
+-          __get_user(kurb->actual_length, &uurb->actual_length) ||
+-          __get_user(kurb->start_frame, &uurb->start_frame) ||
+-          __get_user(kurb->number_of_packets, &uurb->number_of_packets) ||
+-          __get_user(kurb->error_count, &uurb->error_count) ||
+-          __get_user(kurb->signr, &uurb->signr))
+-              return -EFAULT;
+-
+-      kurb->usercontext = 0; /* unused currently */
+-
+-      return 0;
+-}
+-
+-/* Just put back the values which usbdevfs actually changes. */
+-static int put_urb32(struct usbdevfs_urb *kurb,
+-                   struct usbdevfs_urb32 *uurb)
+-{
+-      if (put_user(kurb->status, &uurb->status) ||
+-          __put_user(kurb->actual_length, &uurb->actual_length) ||
+-          __put_user(kurb->error_count, &uurb->error_count))
+-              return -EFAULT;
+-
+-      if (kurb->number_of_packets != 0) {
+-              int i;
+-
+-              for (i = 0; i < kurb->number_of_packets; i++) {
+-                      if (__put_user(kurb->iso_frame_desc[i].actual_length,
+-                                     &uurb->iso_frame_desc[i].actual_length) ||
+-                          __put_user(kurb->iso_frame_desc[i].status,
+-                                     &uurb->iso_frame_desc[i].status))
+-                              return -EFAULT;
+-              }
+-      }
+-
+-      return 0;
+-}
+-
+-static int get_urb32_isoframes(struct usbdevfs_urb *kurb,
+-                             struct usbdevfs_urb32 *uurb)
+-{
+-      unsigned int totlen;
+-      int i;
+-
+-      if (kurb->type != USBDEVFS_URB_TYPE_ISO) {
+-              kurb->number_of_packets = 0;
+-              return 0;
+-      }
+-
+-      if (kurb->number_of_packets < 1 ||
+-          kurb->number_of_packets > 128)
+-              return -EINVAL;
+-
+-      if (copy_from_user(&kurb->iso_frame_desc[0],
+-                         &uurb->iso_frame_desc[0],
+-                         sizeof(struct usbdevfs_iso_packet_desc) *
+-                         kurb->number_of_packets))
+-              return -EFAULT;
+-
+-      totlen = 0;
+-      for (i = 0; i < kurb->number_of_packets; i++) {
+-              unsigned int this_len;
+-
+-              this_len = kurb->iso_frame_desc[i].length;
+-              if (this_len > 1023)
+-                      return -EINVAL;
+-
+-              totlen += this_len;
+-      }
+-
+-      if (totlen > 32768)
+-              return -EINVAL;
+-
+-      kurb->buffer_length = totlen;
+-
+-      return 0;
+-}
+-
+-static int do_usbdevfs_urb(unsigned int fd, unsigned int cmd, unsigned long arg)
+-{
+-      struct usbdevfs_urb *kurb;
+-      struct usbdevfs_urb32 *uurb;
+-      mm_segment_t old_fs;
+-      __u32 udata;
+-      void *uptr, *kptr;
+-      unsigned int buflen;
+-      int err;
+-
+-      uurb = (struct usbdevfs_urb32 *) arg;
+-
+-      err = -ENOMEM;
+-      kurb = kmalloc(sizeof(struct usbdevfs_urb) +
+-                     (sizeof(struct usbdevfs_iso_packet_desc) * 128),
+-                     GFP_KERNEL);
+-      if (!kurb)
+-              goto out;
+-
+-      err = -EFAULT;
+-      if (get_urb32(kurb, uurb))
+-              goto out;
+-
+-      err = get_urb32_isoframes(kurb, uurb);
+-      if (err)
+-              goto out;
+-
+-      err = -EFAULT;
+-      if (__get_user(udata, &uurb->buffer))
+-              goto out;
+-      uptr = (void *) A(udata);
+-
+-      err = -ENOMEM;
+-      buflen = kurb->buffer_length;
+-      kptr = kmalloc(buflen, GFP_KERNEL);
+-      if (!kptr)
+-              goto out;
+-
+-      kurb->buffer = kptr;
+-
+-      err = -EFAULT;
+-      if (copy_from_user(kptr, uptr, buflen))
+-              goto out_kptr;
+-
+-      old_fs = get_fs();
+-      set_fs(KERNEL_DS);
+-      err = sys_ioctl(fd, USBDEVFS_SUBMITURB, (unsigned long) kurb);
+-      set_fs(old_fs);
+-
+-      if (err >= 0) {
+-              /* XXX Shit, this doesn't work for async URBs :-( XXX */
+-              if (put_urb32(kurb, uurb)) {
+-                      err = -EFAULT;
+-              } else if ((kurb->endpoint & USB_DIR_IN) != 0) {
+-                      if (copy_to_user(uptr, kptr, buflen))
+-                              err = -EFAULT;
+-              }
+-      }
+-
+-out_kptr:
+-      kfree(kptr);
+-
+-out:
+-      kfree(kurb);
+-      return err;
+-}
+-#endif
+-
+-#define USBDEVFS_REAPURB32         _IOW('U', 12, u32)
+-#define USBDEVFS_REAPURBNDELAY32   _IOW('U', 13, u32)
+-
+-static int do_usbdevfs_reapurb(unsigned int fd, unsigned int cmd, unsigned long arg)
+-{
+-      mm_segment_t old_fs;
+-      void *kptr;
+-      int err;
+-
+-      old_fs = get_fs();
+-      set_fs(KERNEL_DS);
+-      err = sys_ioctl(fd,
+-                      (cmd == USBDEVFS_REAPURB32 ?
+-                       USBDEVFS_REAPURB :
+-                       USBDEVFS_REAPURBNDELAY),
+-                      (unsigned long) &kptr);
+-      set_fs(old_fs);
+-
+-      if (err >= 0 &&
+-          put_user(((u32)(long)kptr), (u32 *) A(arg)))
+-              err = -EFAULT;
+-
+-      return err;
+-}
+-
+-struct usbdevfs_disconnectsignal32 {
+-      unsigned int signr;
+-      u32 context;
+-};
+-
+-#define USBDEVFS_DISCSIGNAL32      _IOR('U', 14, struct usbdevfs_disconnectsignal32)
+-
+-static int do_usbdevfs_discsignal(unsigned int fd, unsigned int cmd, unsigned long arg)
+-{
+-      struct usbdevfs_disconnectsignal kdis;
+-      struct usbdevfs_disconnectsignal32 *udis;
+-      mm_segment_t old_fs;
+-      u32 uctx;
+-      int err;
+-
+-      udis = (struct usbdevfs_disconnectsignal32 *) arg;
+-
+-      if (get_user(kdis.signr, &udis->signr) ||
+-          __get_user(uctx, &udis->context))
+-              return -EFAULT;
+-
+-      kdis.context = (void *) (long)uctx;
+-
+-      old_fs = get_fs();
+-      set_fs(KERNEL_DS);
+-      err = sys_ioctl(fd, USBDEVFS_DISCSIGNAL, (unsigned long) &kdis);
+-      set_fs(old_fs);
+-
+-      return err;
+-}
+ #define HANDLE_IOCTL(cmd,handler) { cmd, (ioctl_trans_handler_t)handler, 0 },
+ #define COMPATIBLE_IOCTL(cmd) HANDLE_IOCTL(cmd,sys_ioctl)
+@@ -734,8 +344,6 @@ IOCTL_TABLE_START
+ COMPATIBLE_IOCTL(TCSBRKP)
+ COMPATIBLE_IOCTL(TIOCSTART)
+ COMPATIBLE_IOCTL(TIOCSTOP)
+-COMPATIBLE_IOCTL(TIOCGSERIAL)
+-COMPATIBLE_IOCTL(TIOCSSERIAL)
+ COMPATIBLE_IOCTL(TIOCSLTC)
+ #if 0
+ COMPATIBLE_IOCTL(FBIOBLANK)
+@@ -755,13 +363,6 @@ HANDLE_IOCTL(NCP_IOC_SETOBJECTNAME_32, d
+ HANDLE_IOCTL(NCP_IOC_GETPRIVATEDATA_32, do_ncp_getprivatedata)
+ HANDLE_IOCTL(NCP_IOC_SETPRIVATEDATA_32, do_ncp_setprivatedata)
+-/* USB devfs */
+-HANDLE_IOCTL(USBDEVFS_CONTROL32, do_usbdevfs_control)
+-HANDLE_IOCTL(USBDEVFS_BULK32, do_usbdevfs_bulk)
+-/*HANDLE_IOCTL(USBDEVFS_SUBMITURB32, do_usbdevfs_urb)*/
+-HANDLE_IOCTL(USBDEVFS_REAPURB32, do_usbdevfs_reapurb)
+-HANDLE_IOCTL(USBDEVFS_REAPURBNDELAY32, do_usbdevfs_reapurb)
+-HANDLE_IOCTL(USBDEVFS_DISCSIGNAL32, do_usbdevfs_discsignal)
+ IOCTL_TABLE_END
+ int ioctl_table_size = ARRAY_SIZE(ioctl_start);
+--- linux-2.6.0-test6/arch/ppc64/kernel/process.c      2003-09-27 18:57:44.000000000 -0700
++++ 25/arch/ppc64/kernel/process.c     2003-10-05 00:33:23.000000000 -0700
+@@ -70,23 +70,6 @@ enable_kernel_fp(void)
+ #endif /* CONFIG_SMP */
+ }
+-#ifdef CONFIG_SMP
+-static void smp_unlazy_onefpu(void *arg)
+-{
+-      struct pt_regs *regs = current->thread.regs;
+-
+-      if (!regs)
+-              return;
+-      if (regs->msr & MSR_FP)
+-              giveup_fpu(current);
+-}
+-
+-void dump_smp_unlazy_fpu(void)
+-{
+-      smp_call_function(smp_unlazy_onefpu, NULL, 1, 1);
+-}
+-#endif
+-
+ int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs)
+ {
+       struct pt_regs *regs = tsk->thread.regs;
+--- linux-2.6.0-test6/arch/ppc64/kernel/semaphore.c    2003-09-27 18:57:44.000000000 -0700
++++ 25/arch/ppc64/kernel/semaphore.c   2003-10-05 00:34:19.000000000 -0700
+@@ -21,6 +21,7 @@
+ #include <asm/semaphore.h>
+ #include <asm/errno.h>
++#if 0
+ /*
+  * Atomically update sem->count.
+  * This does the equivalent of the following:
+@@ -128,3 +129,140 @@ int __down_interruptible(struct semaphor
+       wake_up(&sem->wait);
+       return retval;
+ }
++#else
++
++static __inline__ int atomic_add_negative(int i, atomic_t *v)
++{
++      if (atomic_add_return(i, v) < 0)
++              return 1;
++      else
++              return 0;
++}
++
++void __up(struct semaphore *sem)
++{
++      wake_up(&sem->wait);
++}
++
++void __down(struct semaphore * sem)
++{
++      struct task_struct *tsk = current;
++      DECLARE_WAITQUEUE(wait, tsk);
++      unsigned long flags;
++
++      tsk->state = TASK_UNINTERRUPTIBLE;
++      spin_lock_irqsave(&sem->wait.lock, flags);
++      add_wait_queue_exclusive_locked(&sem->wait, &wait);
++
++      sem->sleepers++;
++      for (;;) {
++              int sleepers = sem->sleepers;
++
++              /*
++               * Add "everybody else" into it. They aren't
++               * playing, because we own the spinlock in
++               * the wait_queue_head.
++               */
++              if (!atomic_add_negative(sleepers - 1, &sem->count)) {
++                      sem->sleepers = 0;
++                      break;
++              }
++              sem->sleepers = 1;      /* us - see -1 above */
++              spin_unlock_irqrestore(&sem->wait.lock, flags);
++
++              schedule();
++
++              spin_lock_irqsave(&sem->wait.lock, flags);
++              tsk->state = TASK_UNINTERRUPTIBLE;
++      }
++      remove_wait_queue_locked(&sem->wait, &wait);
++      wake_up_locked(&sem->wait);
++      spin_unlock_irqrestore(&sem->wait.lock, flags);
++      tsk->state = TASK_RUNNING;
++}
++
++int __down_interruptible(struct semaphore * sem)
++{
++      int retval = 0;
++      struct task_struct *tsk = current;
++      DECLARE_WAITQUEUE(wait, tsk);
++      unsigned long flags;
++
++      tsk->state = TASK_INTERRUPTIBLE;
++      spin_lock_irqsave(&sem->wait.lock, flags);
++      add_wait_queue_exclusive_locked(&sem->wait, &wait);
++
++      sem->sleepers++;
++      for (;;) {
++              int sleepers = sem->sleepers;
++
++              /*
++               * With signals pending, this turns into
++               * the trylock failure case - we won't be
++               * sleeping, and we* can't get the lock as
++               * it has contention. Just correct the count
++               * and exit.
++               */
++              if (signal_pending(current)) {
++                      retval = -EINTR;
++                      sem->sleepers = 0;
++                      atomic_add(sleepers, &sem->count);
++                      break;
++              }
++
++              /*
++               * Add "everybody else" into it. They aren't
++               * playing, because we own the spinlock in
++               * wait_queue_head. The "-1" is because we're
++               * still hoping to get the semaphore.
++               */
++              if (!atomic_add_negative(sleepers - 1, &sem->count)) {
++                      sem->sleepers = 0;
++                      break;
++              }
++              sem->sleepers = 1;      /* us - see -1 above */
++              spin_unlock_irqrestore(&sem->wait.lock, flags);
++
++              schedule();
++
++              spin_lock_irqsave(&sem->wait.lock, flags);
++              tsk->state = TASK_INTERRUPTIBLE;
++      }
++      remove_wait_queue_locked(&sem->wait, &wait);
++      wake_up_locked(&sem->wait);
++      spin_unlock_irqrestore(&sem->wait.lock, flags);
++
++      tsk->state = TASK_RUNNING;
++      return retval;
++}
++
++/*
++ * Trylock failed - make sure we correct for
++ * having decremented the count.
++ *
++ * We could have done the trylock with a
++ * single "cmpxchg" without failure cases,
++ * but then it wouldn't work on a 386.
++ */
++int __down_trylock(struct semaphore * sem)
++{
++      int sleepers;
++      unsigned long flags;
++
++      spin_lock_irqsave(&sem->wait.lock, flags);
++      sleepers = sem->sleepers + 1;
++      sem->sleepers = 0;
++
++      /*
++       * Add "everybody else" and us into it. They aren't
++       * playing, because we own the spinlock in the
++       * wait_queue_head.
++       */
++      if (!atomic_add_negative(sleepers, &sem->count)) {
++              wake_up_locked(&sem->wait);
++      }
++
++      spin_unlock_irqrestore(&sem->wait.lock, flags);
++      return 1;
++}
++#endif
+--- linux-2.6.0-test6/arch/ppc/boot/ld.script  2003-09-08 13:58:56.000000000 -0700
++++ 25/arch/ppc/boot/ld.script 2003-10-05 00:36:51.000000000 -0700
+@@ -82,6 +82,7 @@ SECTIONS
+     *(__ksymtab)
+     *(__ksymtab_strings)
+     *(__bug_table)
++    *(__kcrctab)
+   }
+ }
+--- linux-2.6.0-test6/arch/ppc/mm/cachemap.c   2003-09-08 13:58:56.000000000 -0700
++++ 25/arch/ppc/mm/cachemap.c  2003-10-05 00:33:23.000000000 -0700
+@@ -101,7 +101,7 @@ void *consistent_alloc(int gfp, size_t s
+       if (! area)
+               goto out;
+-      va = VMALLOC_VMADDR(area->addr);
++      va = (unsigned long) area->addr;
+       flags = _PAGE_KERNEL | _PAGE_NO_CACHE;
+       
+--- linux-2.6.0-test6/arch/ppc/mm/pgtable.c    2003-09-27 18:57:43.000000000 -0700
++++ 25/arch/ppc/mm/pgtable.c   2003-10-05 00:33:23.000000000 -0700
+@@ -195,7 +195,7 @@ __ioremap(phys_addr_t addr, unsigned lon
+               area = get_vm_area(size, VM_IOREMAP);
+               if (area == 0)
+                       return NULL;
+-              v = VMALLOC_VMADDR(area->addr);
++              v = (unsigned long) area->addr;
+       } else {
+               v = (ioremap_bot -= size);
+       }
+--- linux-2.6.0-test6/arch/s390/mm/ioremap.c   2003-06-14 12:17:58.000000000 -0700
++++ 25/arch/s390/mm/ioremap.c  2003-10-05 00:33:23.000000000 -0700
+@@ -124,7 +124,7 @@ void * __ioremap(unsigned long phys_addr
+       if (!area)
+               return NULL;
+       addr = area->addr;
+-      if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size, flags)) {
++      if (remap_area_pages((unsigned long) addr, phys_addr, size, flags)) {
+               vfree(addr);
+               return NULL;
+       }
+--- linux-2.6.0-test6/arch/sh/mm/init.c        2003-07-27 12:14:38.000000000 -0700
++++ 25/arch/sh/mm/init.c       2003-10-05 00:34:40.000000000 -0700
+@@ -51,8 +51,8 @@ unsigned long mmu_context_cache = NO_CON
+ #endif
+ #ifdef CONFIG_DISCONTIGMEM
+-pg_data_t discontig_page_data[NR_NODES];
+-bootmem_data_t discontig_node_bdata[NR_NODES];
++pg_data_t discontig_page_data[MAX_NUMNODES];
++bootmem_data_t discontig_node_bdata[MAX_NUMNODES];
+ #endif
+ void show_mem(void)
+--- linux-2.6.0-test6/arch/sh/mm/ioremap.c     2003-07-02 14:53:14.000000000 -0700
++++ 25/arch/sh/mm/ioremap.c    2003-10-05 00:33:23.000000000 -0700
+@@ -149,7 +149,7 @@ void * p3_ioremap(unsigned long phys_add
+       if (!area)
+               return NULL;
+       addr = area->addr;
+-      if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size, flags)) {
++      if (remap_area_pages((unsigned long) addr, phys_addr, size, flags)) {
+               vfree(addr);
+               return NULL;
+       }
+--- linux-2.6.0-test6/arch/sparc64/defconfig   2003-09-27 18:57:44.000000000 -0700
++++ 25/arch/sparc64/defconfig  2003-10-05 00:33:23.000000000 -0700
+@@ -571,6 +571,7 @@ CONFIG_BRIDGE_EBT_T_NAT=m
+ CONFIG_BRIDGE_EBT_802_3=m
+ CONFIG_BRIDGE_EBT_ARP=m
+ CONFIG_BRIDGE_EBT_IP=m
++CONFIG_BRIDGE_EBT_LIMIT=m
+ CONFIG_BRIDGE_EBT_MARK=m
+ CONFIG_BRIDGE_EBT_PKTTYPE=m
+ CONFIG_BRIDGE_EBT_STP=m
+@@ -665,7 +666,7 @@ CONFIG_TUN=m
+ # Ethernet (10 or 100Mbit)
+ #
+ CONFIG_NET_ETHERNET=y
+-# CONFIG_MII is not set
++CONFIG_MII=m
+ CONFIG_SUNLANCE=y
+ CONFIG_HAPPYMEAL=y
+ CONFIG_SUNBMAC=m
+@@ -729,15 +730,6 @@ CONFIG_YELLOWFIN=m
+ CONFIG_R8169=m
+ # CONFIG_SIS190 is not set
+ CONFIG_SK98LIN=m
+-CONFIG_CONFIG_SK98LIN_T1=y
+-CONFIG_CONFIG_SK98LIN_T2=y
+-CONFIG_CONFIG_SK98LIN_T3=y
+-CONFIG_CONFIG_SK98LIN_T4=y
+-CONFIG_CONFIG_SK98LIN_T5=y
+-CONFIG_CONFIG_SK98LIN_T6=y
+-CONFIG_CONFIG_SK98LIN_T7=y
+-CONFIG_CONFIG_SK98LIN_T8=y
+-CONFIG_CONFIG_SK98LIN_T9=y
+ CONFIG_TIGON3=m
+ #
+@@ -895,6 +887,30 @@ CONFIG_IRDA_FAST_RR=y
+ # CONFIG_VLSI_FIR is not set
+ #
++# Bluetooth support
++#
++CONFIG_BT=m
++CONFIG_BT_L2CAP=m
++CONFIG_BT_SCO=m
++CONFIG_BT_RFCOMM=m
++CONFIG_BT_RFCOMM_TTY=y
++CONFIG_BT_BNEP=m
++CONFIG_BT_BNEP_MC_FILTER=y
++CONFIG_BT_BNEP_PROTO_FILTER=y
++
++#
++# Bluetooth device drivers
++#
++CONFIG_BT_HCIUSB=m
++CONFIG_BT_USB_SCO=y
++# CONFIG_BT_USB_ZERO_PACKET is not set
++CONFIG_BT_HCIUART=m
++CONFIG_BT_HCIUART_H4=y
++CONFIG_BT_HCIUART_BCSP=y
++CONFIG_BT_HCIUART_BCSP_TXCRC=y
++CONFIG_BT_HCIVHCI=m
++
++#
+ # ISDN subsystem
+ #
+ CONFIG_ISDN_BOOL=y
+@@ -1517,30 +1533,6 @@ CONFIG_USB_TEST=m
+ # CONFIG_USB_GADGET is not set
+ #
+-# Bluetooth support
+-#
+-CONFIG_BT=m
+-CONFIG_BT_L2CAP=m
+-CONFIG_BT_SCO=m
+-CONFIG_BT_RFCOMM=m
+-CONFIG_BT_RFCOMM_TTY=y
+-CONFIG_BT_BNEP=m
+-CONFIG_BT_BNEP_MC_FILTER=y
+-CONFIG_BT_BNEP_PROTO_FILTER=y
+-
+-#
+-# Bluetooth device drivers
+-#
+-CONFIG_BT_HCIUSB=m
+-CONFIG_BT_USB_SCO=y
+-# CONFIG_BT_USB_ZERO_PACKET is not set
+-CONFIG_BT_HCIUART=m
+-CONFIG_BT_HCIUART_H4=y
+-CONFIG_BT_HCIUART_BCSP=y
+-CONFIG_BT_HCIUART_BCSP_TXCRC=y
+-CONFIG_BT_HCIVHCI=m
+-
+-#
+ # Watchdog
+ #
+ # CONFIG_SOFT_WATCHDOG is not set
+--- linux-2.6.0-test6/arch/sparc64/Kconfig     2003-09-27 18:57:44.000000000 -0700
++++ 25/arch/sparc64/Kconfig    2003-10-05 00:36:40.000000000 -0700
+@@ -787,12 +787,19 @@ config DEBUG_SPINLOCK
+         best used in conjunction with the NMI watchdog so that spinlock
+         deadlocks are also debuggable.
++config LOCKMETER
++      bool "Kernel lock metering"
++      depends on SMP && !PREEMPT
++      help
++        Say Y to enable kernel lock metering, which adds overhead to SMP locks,
++        but allows you to see various statistics using the lockstat command.
++
+ # We have a custom atomic_dec_and_lock() implementation but it's not
+ # compatible with spinlock debugging so we need to fall back on
+ # the generic version in that case.
+ config HAVE_DEC_LOCK
+       bool
+-      depends on !DEBUG_SPINLOCK
++      depends on !DEBUG_SPINLOCK && !LOCKMETER
+       default y
+ config DEBUG_SPINLOCK_SLEEP
+--- linux-2.6.0-test6/arch/sparc64/kernel/entry.S      2003-09-08 13:58:56.000000000 -0700
++++ 25/arch/sparc64/kernel/entry.S     2003-10-05 00:33:23.000000000 -0700
+@@ -26,7 +26,7 @@
+ #define curptr      g6
+-#define NR_SYSCALLS 267      /* Each OS is different... */
++#define NR_SYSCALLS 268      /* Each OS is different... */
+       .text
+       .align          32
+--- linux-2.6.0-test6/arch/sparc64/kernel/ioctl32.c    2003-09-08 13:58:56.000000000 -0700
++++ 25/arch/sparc64/kernel/ioctl32.c   2003-10-05 00:34:44.000000000 -0700
+@@ -985,402 +985,6 @@ static int drm32_res_ctx(unsigned int fd
+ #endif
+-/* HERE! */
+-
+-struct usbdevfs_ctrltransfer32 {
+-      __u8 bRequestType;
+-      __u8 bRequest;
+-      __u16 wValue;
+-      __u16 wIndex;
+-      __u16 wLength;
+-      __u32 timeout;  /* in milliseconds */
+-      __u32 data;
+-};
+-
+-#define USBDEVFS_CONTROL32           _IOWR('U', 0, struct usbdevfs_ctrltransfer32)
+-
+-static int do_usbdevfs_control(unsigned int fd, unsigned int cmd, unsigned long arg)
+-{
+-      struct usbdevfs_ctrltransfer kctrl;
+-      struct usbdevfs_ctrltransfer32 *uctrl;
+-      mm_segment_t old_fs;
+-      __u32 udata;
+-      void __user *uptr;
+-      void *kptr;
+-      int err;
+-
+-      uctrl = (struct usbdevfs_ctrltransfer32 *) arg;
+-
+-      if (copy_from_user(&kctrl, uctrl,
+-                         (sizeof(struct usbdevfs_ctrltransfer) -
+-                          sizeof(void *))))
+-              return -EFAULT;
+-
+-      if (get_user(udata, &uctrl->data))
+-              return -EFAULT;
+-      uptr = A(udata);
+-
+-      /* In usbdevice_fs, it limits the control buffer to a page,
+-       * for simplicity so do we.
+-       */
+-      if (!uptr || kctrl.wLength > PAGE_SIZE)
+-              return -EINVAL;
+-
+-      kptr = (void *)__get_free_page(GFP_KERNEL);
+-
+-      if ((kctrl.bRequestType & 0x80) == 0) {
+-              err = -EFAULT;
+-              if (copy_from_user(kptr, uptr, kctrl.wLength))
+-                      goto out;
+-      }
+-
+-      kctrl.data = kptr;
+-
+-      old_fs = get_fs();
+-      set_fs(KERNEL_DS);
+-      err = sys_ioctl(fd, USBDEVFS_CONTROL, (unsigned long)&kctrl);
+-      set_fs(old_fs);
+-
+-      if (err >= 0 &&
+-          ((kctrl.bRequestType & 0x80) != 0)) {
+-              if (copy_to_user(uptr, kptr, kctrl.wLength))
+-                      err = -EFAULT;
+-      }
+-
+-out:
+-      free_page((unsigned long) kptr);
+-      return err;
+-}
+-
+-struct usbdevfs_bulktransfer32 {
+-      unsigned int ep;
+-      unsigned int len;
+-      unsigned int timeout; /* in milliseconds */
+-      __u32 data;
+-};
+-
+-#define USBDEVFS_BULK32              _IOWR('U', 2, struct usbdevfs_bulktransfer32)
+-
+-static int do_usbdevfs_bulk(unsigned int fd, unsigned int cmd, unsigned long arg)
+-{
+-      struct usbdevfs_bulktransfer kbulk;
+-      struct usbdevfs_bulktransfer32 *ubulk;
+-      mm_segment_t old_fs;
+-      __u32 udata;
+-      void __user *uptr;
+-      void *kptr;
+-      int err;
+-
+-      ubulk = (struct usbdevfs_bulktransfer32 *) arg;
+-
+-      if (get_user(kbulk.ep, &ubulk->ep) ||
+-          get_user(kbulk.len, &ubulk->len) ||
+-          get_user(kbulk.timeout, &ubulk->timeout) ||
+-          get_user(udata, &ubulk->data))
+-              return -EFAULT;
+-
+-      uptr = A(udata);
+-
+-      /* In usbdevice_fs, it limits the control buffer to a page,
+-       * for simplicity so do we.
+-       */
+-      if (!uptr || kbulk.len > PAGE_SIZE)
+-              return -EINVAL;
+-
+-      kptr = (void *) __get_free_page(GFP_KERNEL);
+-
+-      if ((kbulk.ep & 0x80) == 0) {
+-              err = -EFAULT;
+-              if (copy_from_user(kptr, uptr, kbulk.len))
+-                      goto out;
+-      }
+-
+-      kbulk.data = kptr;
+-
+-      old_fs = get_fs();
+-      set_fs(KERNEL_DS);
+-      err = sys_ioctl(fd, USBDEVFS_BULK, (unsigned long) &kbulk);
+-      set_fs(old_fs);
+-
+-      if (err >= 0 &&
+-          ((kbulk.ep & 0x80) != 0)) {
+-              if (copy_to_user(uptr, kptr, kbulk.len))
+-                      err = -EFAULT;
+-      }
+-
+-out:
+-      free_page((unsigned long) kptr);
+-      return err;
+-}
+-
+-/* This needs more work before we can enable it.  Unfortunately
+- * because of the fancy asynchronous way URB status/error is written
+- * back to userspace, we'll need to fiddle with USB devio internals
+- * and/or reimplement entirely the frontend of it ourselves. -DaveM
+- *
+- * The issue is:
+- *
+- *    When an URB is submitted via usbdevicefs it is put onto an
+- *    asynchronous queue.  When the URB completes, it may be reaped
+- *    via another ioctl.  During this reaping the status is written
+- *    back to userspace along with the length of the transfer.
+- *
+- *    We must translate into 64-bit kernel types so we pass in a kernel
+- *    space copy of the usbdevfs_urb structure.  This would mean that we
+- *    must do something to deal with the async entry reaping.  First we
+- *    have to deal somehow with this transitory memory we've allocated.
+- *    This is problematic since there are many call sites from which the
+- *    async entries can be destroyed (and thus when we'd need to free up
+- *    this kernel memory).  One of which is the close() op of usbdevicefs.
+- *    To handle that we'd need to make our own file_operations struct which
+- *    overrides usbdevicefs's release op with our own which runs usbdevicefs's
+- *    real release op then frees up the kernel memory.
+- *
+- *    But how to keep track of these kernel buffers?  We'd need to either
+- *    keep track of them in some table _or_ know about usbdevicefs internals
+- *    (ie. the exact layout of its file private, which is actually defined
+- *    in linux/usbdevice_fs.h, the layout of the async queues are private to
+- *    devio.c)
+- *
+- * There is one possible other solution I considered, also involving knowledge
+- * of usbdevicefs internals:
+- *
+- *    After an URB is submitted, we "fix up" the address back to the user
+- *    space one.  This would work if the status/length fields written back
+- *    by the async URB completion lines up perfectly in the 32-bit type with
+- *    the 64-bit kernel type.  Unfortunately, it does not because the iso
+- *    frame descriptors, at the end of the struct, can be written back.
+- *
+- * I think we'll just need to simply duplicate the devio URB engine here.
+- */
+-#if 0
+-struct usbdevfs_urb32 {
+-      __u8 type;
+-      __u8 endpoint;
+-      __s32 status;
+-      __u32 flags;
+-      __u32 buffer;
+-      __s32 buffer_length;
+-      __s32 actual_length;
+-      __s32 start_frame;
+-      __s32 number_of_packets;
+-      __s32 error_count;
+-      __u32 signr;
+-      __u32 usercontext; /* unused */
+-      struct usbdevfs_iso_packet_desc iso_frame_desc[0];
+-};
+-
+-#define USBDEVFS_SUBMITURB32       _IOR('U', 10, struct usbdevfs_urb32)
+-
+-static int get_urb32(struct usbdevfs_urb *kurb,
+-                   struct usbdevfs_urb32 *uurb)
+-{
+-      if (get_user(kurb->type, &uurb->type) ||
+-          __get_user(kurb->endpoint, &uurb->endpoint) ||
+-          __get_user(kurb->status, &uurb->status) ||
+-          __get_user(kurb->flags, &uurb->flags) ||
+-          __get_user(kurb->buffer_length, &uurb->buffer_length) ||
+-          __get_user(kurb->actual_length, &uurb->actual_length) ||
+-          __get_user(kurb->start_frame, &uurb->start_frame) ||
+-          __get_user(kurb->number_of_packets, &uurb->number_of_packets) ||
+-          __get_user(kurb->error_count, &uurb->error_count) ||
+-          __get_user(kurb->signr, &uurb->signr))
+-              return -EFAULT;
+-
+-      kurb->usercontext = 0; /* unused currently */
+-
+-      return 0;
+-}
+-
+-/* Just put back the values which usbdevfs actually changes. */
+-static int put_urb32(struct usbdevfs_urb *kurb,
+-                   struct usbdevfs_urb32 *uurb)
+-{
+-      if (put_user(kurb->status, &uurb->status) ||
+-          __put_user(kurb->actual_length, &uurb->actual_length) ||
+-          __put_user(kurb->error_count, &uurb->error_count))
+-              return -EFAULT;
+-
+-      if (kurb->number_of_packets != 0) {
+-              int i;
+-
+-              for (i = 0; i < kurb->number_of_packets; i++) {
+-                      if (__put_user(kurb->iso_frame_desc[i].actual_length,
+-                                     &uurb->iso_frame_desc[i].actual_length) ||
+-                          __put_user(kurb->iso_frame_desc[i].status,
+-                                     &uurb->iso_frame_desc[i].status))
+-                              return -EFAULT;
+-              }
+-      }
+-
+-      return 0;
+-}
+-
+-static int get_urb32_isoframes(struct usbdevfs_urb *kurb,
+-                             struct usbdevfs_urb32 *uurb)
+-{
+-      unsigned int totlen;
+-      int i;
+-
+-      if (kurb->type != USBDEVFS_URB_TYPE_ISO) {
+-              kurb->number_of_packets = 0;
+-              return 0;
+-      }
+-
+-      if (kurb->number_of_packets < 1 ||
+-          kurb->number_of_packets > 128)
+-              return -EINVAL;
+-
+-      if (copy_from_user(&kurb->iso_frame_desc[0],
+-                         &uurb->iso_frame_desc[0],
+-                         sizeof(struct usbdevfs_iso_packet_desc) *
+-                         kurb->number_of_packets))
+-              return -EFAULT;
+-
+-      totlen = 0;
+-      for (i = 0; i < kurb->number_of_packets; i++) {
+-              unsigned int this_len;
+-
+-              this_len = kurb->iso_frame_desc[i].length;
+-              if (this_len > 1023)
+-                      return -EINVAL;
+-
+-              totlen += this_len;
+-      }
+-
+-      if (totlen > 32768)
+-              return -EINVAL;
+-
+-      kurb->buffer_length = totlen;
+-
+-      return 0;
+-}
+-
+-static int do_usbdevfs_urb(unsigned int fd, unsigned int cmd, unsigned long arg)
+-{
+-      struct usbdevfs_urb *kurb;
+-      struct usbdevfs_urb32 *uurb;
+-      mm_segment_t old_fs;
+-      __u32 udata;
+-      void __user *uptr;
+-      void *kptr;
+-      unsigned int buflen;
+-      int err;
+-
+-      uurb = (struct usbdevfs_urb32 *) arg;
+-
+-      err = -ENOMEM;
+-      kurb = kmalloc(sizeof(struct usbdevfs_urb) +
+-                     (sizeof(struct usbdevfs_iso_packet_desc) * 128),
+-                     GFP_KERNEL);
+-      if (!kurb)
+-              goto out;
+-
+-      err = -EFAULT;
+-      if (get_urb32(kurb, uurb))
+-              goto out;
+-
+-      err = get_urb32_isoframes(kurb, uurb);
+-      if (err)
+-              goto out;
+-
+-      err = -EFAULT;
+-      if (__get_user(udata, &uurb->buffer))
+-              goto out;
+-      uptr = A(udata);
+-
+-      err = -ENOMEM;
+-      buflen = kurb->buffer_length;
+-      kptr = kmalloc(buflen, GFP_KERNEL);
+-      if (!kptr)
+-              goto out;
+-
+-      kurb->buffer = kptr;
+-
+-      err = -EFAULT;
+-      if (copy_from_user(kptr, uptr, buflen))
+-              goto out_kptr;
+-
+-      old_fs = get_fs();
+-      set_fs(KERNEL_DS);
+-      err = sys_ioctl(fd, USBDEVFS_SUBMITURB, (unsigned long) kurb);
+-      set_fs(old_fs);
+-
+-      if (err >= 0) {
+-              /* XXX Shit, this doesn't work for async URBs :-( XXX */
+-              if (put_urb32(kurb, uurb)) {
+-                      err = -EFAULT;
+-              } else if ((kurb->endpoint & USB_DIR_IN) != 0) {
+-                      if (copy_to_user(uptr, kptr, buflen))
+-                              err = -EFAULT;
+-              }
+-      }
+-
+-out_kptr:
+-      kfree(kptr);
+-
+-out:
+-      kfree(kurb);
+-      return err;
+-}
+-#endif
+-
+-#define USBDEVFS_REAPURB32         _IOW('U', 12, u32)
+-#define USBDEVFS_REAPURBNDELAY32   _IOW('U', 13, u32)
+-
+-static int do_usbdevfs_reapurb(unsigned int fd, unsigned int cmd, unsigned long arg)
+-{
+-      mm_segment_t old_fs;
+-      void *kptr;
+-      int err;
+-
+-      old_fs = get_fs();
+-      set_fs(KERNEL_DS);
+-      err = sys_ioctl(fd,
+-                      (cmd == USBDEVFS_REAPURB32 ?
+-                       USBDEVFS_REAPURB :
+-                       USBDEVFS_REAPURBNDELAY),
+-                      (unsigned long) &kptr);
+-      set_fs(old_fs);
+-
+-      if (err >= 0 &&
+-          put_user(((u32)(long)kptr), (u32 __user *) A(arg)))
+-              err = -EFAULT;
+-
+-      return err;
+-}
+-
+-struct usbdevfs_disconnectsignal32 {
+-      unsigned int signr;
+-      u32 context;
+-};
+-
+-#define USBDEVFS_DISCSIGNAL32      _IOR('U', 14, struct usbdevfs_disconnectsignal32)
+-
+-static int do_usbdevfs_discsignal(unsigned int fd, unsigned int cmd, unsigned long arg)
+-{
+-      struct usbdevfs_disconnectsignal kdis;
+-      struct usbdevfs_disconnectsignal32 *udis;
+-      mm_segment_t old_fs;
+-      u32 uctx;
+-      int err;
+-
+-      udis = (struct usbdevfs_disconnectsignal32 *) arg;
+-
+-      if (get_user(kdis.signr, &udis->signr) ||
+-          __get_user(uctx, &udis->context))
+-              return -EFAULT;
+-
+-      kdis.context = (void *) (long)uctx;
+-
+-      old_fs = get_fs();
+-      set_fs(KERNEL_DS);
+-      err = sys_ioctl(fd, USBDEVFS_DISCSIGNAL, (unsigned long) &kdis);
+-      set_fs(old_fs);
+-
+-      return err;
+-}
+-
+ typedef int (* ioctl32_handler_t)(unsigned int, unsigned int, unsigned long, struct file *);
+ #define COMPATIBLE_IOCTL(cmd)         HANDLE_IOCTL((cmd),sys_ioctl)
+@@ -1397,8 +1001,6 @@ IOCTL_TABLE_START
+ COMPATIBLE_IOCTL(TCSBRKP)
+ COMPATIBLE_IOCTL(TIOCSTART)
+ COMPATIBLE_IOCTL(TIOCSTOP)
+-COMPATIBLE_IOCTL(TIOCGSERIAL)
+-COMPATIBLE_IOCTL(TIOCSSERIAL)
+ COMPATIBLE_IOCTL(TIOCSLTC)
+ COMPATIBLE_IOCTL(FBIOGTYPE)
+ COMPATIBLE_IOCTL(FBIOSATTR)
+@@ -1467,9 +1069,6 @@ COMPATIBLE_IOCTL(AUDIO_GETDEV)
+ COMPATIBLE_IOCTL(AUDIO_GETDEV_SUNOS)
+ COMPATIBLE_IOCTL(AUDIO_FLUSH)
+ COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE_MULTI)
+-/* Raw devices */
+-COMPATIBLE_IOCTL(RAW_SETBIND)
+-COMPATIBLE_IOCTL(RAW_GETBIND)
+ /* NCP ioctls which do not need any translations */
+ COMPATIBLE_IOCTL(NCP_IOC_CONN_LOGGED_IN)
+ COMPATIBLE_IOCTL(NCP_IOC_SIGN_INIT)
+@@ -1575,12 +1174,6 @@ HANDLE_IOCTL(RTC32_IRQP_SET, do_rtc_ioct
+ HANDLE_IOCTL(RTC32_EPOCH_READ, do_rtc_ioctl)
+ HANDLE_IOCTL(RTC32_EPOCH_SET, do_rtc_ioctl)
+ #endif
+-HANDLE_IOCTL(USBDEVFS_CONTROL32, do_usbdevfs_control)
+-HANDLE_IOCTL(USBDEVFS_BULK32, do_usbdevfs_bulk)
+-/*HANDLE_IOCTL(USBDEVFS_SUBMITURB32, do_usbdevfs_urb)*/
+-HANDLE_IOCTL(USBDEVFS_REAPURB32, do_usbdevfs_reapurb)
+-HANDLE_IOCTL(USBDEVFS_REAPURBNDELAY32, do_usbdevfs_reapurb)
+-HANDLE_IOCTL(USBDEVFS_DISCSIGNAL32, do_usbdevfs_discsignal)
+ /* take care of sizeof(sizeof()) breakage */
+ IOCTL_TABLE_END
+--- linux-2.6.0-test6/arch/sparc64/kernel/module.c     2003-09-27 18:57:44.000000000 -0700
++++ 25/arch/sparc64/kernel/module.c    2003-10-05 00:33:23.000000000 -0700
+@@ -14,6 +14,9 @@
+ #include <linux/vmalloc.h>
+ #include <linux/mm.h>
++#include <asm/processor.h>
++#include <asm/spitfire.h>
++
+ static struct vm_struct * modvmlist = NULL;
+ static void module_unmap(void * addr)
+@@ -279,6 +282,16 @@ int module_finalize(const Elf_Ehdr *hdr,
+                   const Elf_Shdr *sechdrs,
+                   struct module *me)
+ {
++      /* Cheetah's I-cache is fully coherent.  */
++      if (tlb_type == spitfire) {
++              unsigned long va;
++
++              flushw_all();
++              for (va =  0; va < (PAGE_SIZE << 1); va += 32)
++                      spitfire_put_icache_tag(va, 0x0);
++              __asm__ __volatile__("flush %g6");
++      }
++
+       return 0;
+ }
+--- linux-2.6.0-test6/arch/sparc64/kernel/smp.c        2003-08-22 19:23:40.000000000 -0700
++++ 25/arch/sparc64/kernel/smp.c       2003-10-05 00:33:23.000000000 -0700
+@@ -118,7 +118,6 @@ void __init smp_callin(void)
+       inherit_locked_prom_mappings(0);
+-      __flush_cache_all();
+       __flush_tlb_all();
+       smp_setup_percpu_timer();
+@@ -661,7 +660,6 @@ extern unsigned long xcall_flush_tlb_ran
+ extern unsigned long xcall_flush_tlb_kernel_range;
+ extern unsigned long xcall_flush_tlb_all_spitfire;
+ extern unsigned long xcall_flush_tlb_all_cheetah;
+-extern unsigned long xcall_flush_cache_all_spitfire;
+ extern unsigned long xcall_report_regs;
+ extern unsigned long xcall_receive_signal;
+ extern unsigned long xcall_flush_dcache_page_cheetah;
+@@ -776,15 +774,6 @@ void smp_report_regs(void)
+       smp_cross_call(&xcall_report_regs, 0, 0, 0);
+ }
+-void smp_flush_cache_all(void)
+-{
+-      /* Cheetah need do nothing. */
+-      if (tlb_type == spitfire) {
+-              smp_cross_call(&xcall_flush_cache_all_spitfire, 0, 0, 0);
+-              __flush_cache_all();
+-      }
+-}
+-
+ void smp_flush_tlb_all(void)
+ {
+       if (tlb_type == spitfire)
+--- linux-2.6.0-test6/arch/sparc64/kernel/systbls.S    2003-09-08 13:58:56.000000000 -0700
++++ 25/arch/sparc64/kernel/systbls.S   2003-10-05 00:33:23.000000000 -0700
+@@ -72,7 +72,7 @@ sys_call_table32:
+ /*250*/       .word sys32_mremap, sys32_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl
+       .word sys_ni_syscall, compat_clock_settime, compat_clock_gettime, compat_clock_getres, compat_clock_nanosleep
+ /*260*/       .word compat_sys_sched_getaffinity, compat_sys_sched_setaffinity, compat_timer_settime, compat_timer_gettime, sys_timer_getoverrun
+-      .word sys_timer_delete, sys32_timer_create, sys_ni_syscall
++      .word sys_timer_delete, sys32_timer_create, sys_ni_syscall, sys_ni_syscall
+       /* Now the 64-bit native Linux syscall table. */
+@@ -133,7 +133,7 @@ sys_call_table:
+ /*250*/       .word sys64_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
+       .word sys_ni_syscall, sys_clock_settime, sys_clock_gettime, sys_clock_getres, sys_clock_nanosleep
+ /*260*/       .word sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun
+-      .word sys_timer_delete, sys_timer_create, sys_ni_syscall
++      .word sys_timer_delete, sys_timer_create, sys_ni_syscall, sys_ni_syscall
+ #if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \
+     defined(CONFIG_SOLARIS_EMUL_MODULE)
+@@ -233,5 +233,6 @@ sunos_sys_table:
+       .word sunos_nosys, sunos_nosys, sunos_nosys
+       .word sunos_nosys, sunos_nosys, sunos_nosys
+       .word sunos_nosys, sunos_nosys, sunos_nosys
++      .word sunos_nosys
+ #endif
+--- linux-2.6.0-test6/arch/sparc64/lib/rwlock.S        2003-06-26 22:07:24.000000000 -0700
++++ 25/arch/sparc64/lib/rwlock.S       2003-10-05 00:36:40.000000000 -0700
+@@ -63,5 +63,33 @@ __write_lock: /* %o0 = lock_ptr */
+       be,pt           %icc, 99b
+        membar         #StoreLoad | #StoreStore
+       ba,a,pt         %xcc, 1b
++
++      .globl  __read_trylock
++__read_trylock: /* %o0 = lock_ptr */
++      ldsw            [%o0], %g5
++      brlz,pn         %g5, 100f
++       add            %g5, 1, %g7
++      cas             [%o0], %g5, %g7
++      cmp             %g5, %g7
++      bne,pn          %icc, __read_trylock
++       membar         #StoreLoad | #StoreStore
++      retl
++       mov            1, %o0
++
++      .globl          __write_trylock
++__write_trylock: /* %o0 = lock_ptr */
++      sethi           %hi(0x80000000), %g2
++1:    lduw            [%o0], %g5
++4:    brnz,pn         %g5, 100f
++       or             %g5, %g2, %g7
++      cas             [%o0], %g5, %g7
++      cmp             %g5, %g7
++      bne,pn          %icc, 1b
++       membar         #StoreLoad | #StoreStore
++      retl
++       mov            1, %o0
++100:  retl
++       mov            0, %o0
++
+ rwlock_impl_end:
+--- linux-2.6.0-test6/arch/sparc64/mm/init.c   2003-09-27 18:57:44.000000000 -0700
++++ 25/arch/sparc64/mm/init.c  2003-10-05 00:33:23.000000000 -0700
+@@ -1025,19 +1025,6 @@ void __flush_dcache_range(unsigned long 
+       }
+ }
+-void __flush_cache_all(void)
+-{
+-      /* Cheetah should be fine here too. */
+-      if (tlb_type == spitfire) {
+-              unsigned long va;
+-
+-              flushw_all();
+-              for (va =  0; va < (PAGE_SIZE << 1); va += 32)
+-                      spitfire_put_icache_tag(va, 0x0);
+-              __asm__ __volatile__("flush %g6");
+-      }
+-}
+-
+ /* If not locked, zap it. */
+ void __flush_tlb_all(void)
+ {
+--- linux-2.6.0-test6/arch/sparc64/mm/ultra.S  2003-06-14 12:18:28.000000000 -0700
++++ 25/arch/sparc64/mm/ultra.S 2003-10-05 00:33:23.000000000 -0700
+@@ -721,20 +721,6 @@ xcall_flush_tlb_all_cheetah:
+       stxa            %g0, [%g2] ASI_IMMU_DEMAP
+       retry
+-      .globl          xcall_flush_cache_all_spitfire
+-xcall_flush_cache_all_spitfire:
+-      sethi           %hi(16383), %g2
+-      or              %g2, %lo(16383), %g2
+-      clr             %g3
+-1:    stxa            %g0, [%g3] ASI_IC_TAG
+-      membar          #Sync
+-      add             %g3, 32, %g3
+-      cmp             %g3, %g2
+-      bleu,pt         %xcc, 1b
+-       nop
+-      flush           %g6
+-      retry
+-
+       /* These just get rescheduled to PIL vectors. */
+       .globl          xcall_call_function
+ xcall_call_function:
+--- linux-2.6.0-test6/arch/sparc/kernel/entry.S        2003-09-08 13:58:56.000000000 -0700
++++ 25/arch/sparc/kernel/entry.S       2003-10-05 00:33:23.000000000 -0700
+@@ -38,7 +38,7 @@
+ #define curptr      g6
+-#define NR_SYSCALLS 267      /* Each OS is different... */
++#define NR_SYSCALLS 268      /* Each OS is different... */
+ /* These are just handy. */
+ #define _SV   save    %sp, -STACKFRAME_SZ, %sp
+--- linux-2.6.0-test6/arch/sparc/kernel/systbls.S      2003-09-08 13:58:56.000000000 -0700
++++ 25/arch/sparc/kernel/systbls.S     2003-10-05 00:33:23.000000000 -0700
+@@ -72,7 +72,7 @@ sys_call_table:
+ /*250*/       .long sparc_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
+ /*255*/       .long sys_nis_syscall, sys_clock_settime, sys_clock_gettime, sys_clock_getres, sys_clock_nanosleep
+ /*260*/       .long sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun
+-/*265*/       .long sys_timer_delete, sys_timer_create, sys_nis_syscall
++/*265*/       .long sys_timer_delete, sys_timer_create, sys_nis_syscall, sys_nis_syscall
+ #ifdef CONFIG_SUNOS_EMUL
+       /* Now the SunOS syscall table. */
+@@ -171,6 +171,6 @@ sunos_sys_table:
+       .long sunos_nosys
+ /*260*/       .long sunos_nosys, sunos_nosys, sunos_nosys
+       .long sunos_nosys, sunos_nosys, sunos_nosys
+-      .long sunos_nosys, sunos_nosys
++      .long sunos_nosys, sunos_nosys, sunos_nosys
+ #endif
+--- linux-2.6.0-test6/arch/sparc/kernel/time.c 2003-07-13 21:44:34.000000000 -0700
++++ 25/arch/sparc/kernel/time.c        2003-10-05 00:36:33.000000000 -0700
+@@ -617,3 +617,12 @@ static int set_rtc_mmss(unsigned long no
+               return -1;
+       }
+ }
++
++/*
++ * Returns nanoseconds
++  */
++
++unsigned long long sched_clock(void)
++{
++      return (unsigned long long)jiffies * (1000000000 / HZ);
++}
+--- linux-2.6.0-test6/arch/um/config.release   2003-08-08 22:55:11.000000000 -0700
++++ 25/arch/um/config.release  2003-10-05 00:34:32.000000000 -0700
+@@ -228,7 +228,6 @@ CONFIG_ROMFS_FS=m
+ CONFIG_EXT2_FS=y
+ CONFIG_SYSV_FS=m
+ CONFIG_UDF_FS=m
+-# CONFIG_UDF_RW is not set
+ CONFIG_UFS_FS=m
+ # CONFIG_UFS_FS_WRITE is not set
+--- linux-2.6.0-test6/arch/um/defconfig        2003-08-08 22:55:11.000000000 -0700
++++ 25/arch/um/defconfig       2003-10-05 00:34:32.000000000 -0700
+@@ -3,29 +3,19 @@
+ #
+ CONFIG_USERMODE=y
+ CONFIG_MMU=y
+-CONFIG_SWAP=y
+ CONFIG_UID16=y
+ CONFIG_RWSEM_GENERIC_SPINLOCK=y
+-CONFIG_CONFIG_LOG_BUF_SHIFT=14
+-
+-#
+-# Code maturity level options
+-#
+-CONFIG_EXPERIMENTAL=y
+ #
+-# General Setup
++# UML-specific options
+ #
+ CONFIG_MODE_TT=y
+ CONFIG_MODE_SKAS=y
+ CONFIG_NET=y
+-CONFIG_SYSVIPC=y
+-CONFIG_BSD_PROCESS_ACCT=y
+-CONFIG_SYSCTL=y
+-CONFIG_BINFMT_AOUT=y
+ CONFIG_BINFMT_ELF=y
+ CONFIG_BINFMT_MISC=y
+ CONFIG_HOSTFS=y
++CONFIG_HPPFS=y
+ CONFIG_MCONSOLE=y
+ CONFIG_MAGIC_SYSRQ=y
+ # CONFIG_HOST_2G_2G is not set
+@@ -38,10 +28,38 @@ CONFIG_PROC_MM=y
+ CONFIG_KERNEL_STACK_ORDER=2
+ #
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_CLEAN_COMPILE=y
++CONFIG_STANDALONE=y
++CONFIG_BROKEN_ON_SMP=y
++
++#
++# General setup
++#
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_SYSCTL=y
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_IKCONFIG is not set
++# CONFIG_EMBEDDED is not set
++CONFIG_KALLSYMS=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_AS=y
++CONFIG_IOSCHED_DEADLINE=y
++
++#
+ # Loadable module support
+ #
+-CONFIG_MODULES=y
+-# CONFIG_KMOD is not set
++# CONFIG_MODULES is not set
++
++#
++# Generic Driver Options
++#
+ #
+ # Character Devices
+@@ -69,6 +87,7 @@ CONFIG_HOSTAUDIO=y
+ #
+ CONFIG_BLK_DEV_UBD=y
+ # CONFIG_BLK_DEV_UBD_SYNC is not set
++CONFIG_BLK_DEV_COW_COMMON=y
+ CONFIG_BLK_DEV_LOOP=y
+ CONFIG_BLK_DEV_NBD=y
+ CONFIG_BLK_DEV_RAM=y
+@@ -78,7 +97,7 @@ CONFIG_BLK_DEV_INITRD=y
+ CONFIG_NETDEVICES=y
+ #
+-# Network Devices
++# UML Network Devices
+ #
+ CONFIG_UML_NET=y
+ CONFIG_UML_NET_ETHERTAP=y
+@@ -88,22 +107,6 @@ CONFIG_UML_NET_DAEMON=y
+ CONFIG_UML_NET_MCAST=y
+ # CONFIG_UML_NET_PCAP is not set
+ CONFIG_UML_NET_SLIRP=y
+-CONFIG_DUMMY=y
+-# CONFIG_BONDING is not set
+-# CONFIG_EQUALIZER is not set
+-CONFIG_TUN=y
+-# CONFIG_ETHERTAP is not set
+-CONFIG_PPP=y
+-# CONFIG_PPP_MULTILINK is not set
+-# CONFIG_PPP_ASYNC is not set
+-# CONFIG_PPP_SYNC_TTY is not set
+-# CONFIG_PPP_DEFLATE is not set
+-# CONFIG_PPP_BSDCOMP is not set
+-# CONFIG_PPPOE is not set
+-CONFIG_SLIP=y
+-# CONFIG_SLIP_COMPRESSED is not set
+-# CONFIG_SLIP_SMART is not set
+-# CONFIG_SLIP_MODE_SLIP6 is not set
+ #
+ # Networking support
+@@ -115,8 +118,6 @@ CONFIG_SLIP=y
+ CONFIG_PACKET=y
+ CONFIG_PACKET_MMAP=y
+ # CONFIG_NETLINK_DEV is not set
+-# CONFIG_NETFILTER is not set
+-# CONFIG_FILTER is not set
+ CONFIG_UNIX=y
+ # CONFIG_NET_KEY is not set
+ CONFIG_INET=y
+@@ -130,8 +131,11 @@ CONFIG_INET=y
+ # CONFIG_SYN_COOKIES is not set
+ # CONFIG_INET_AH is not set
+ # CONFIG_INET_ESP is not set
+-# CONFIG_XFRM_USER is not set
++# CONFIG_INET_IPCOMP is not set
+ # CONFIG_IPV6 is not set
++# CONFIG_DECNET is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_NETFILTER is not set
+ #
+ # SCTP Configuration (EXPERIMENTAL)
+@@ -141,8 +145,6 @@ CONFIG_IPV6_SCTP__=y
+ # CONFIG_ATM is not set
+ # CONFIG_VLAN_8021Q is not set
+ # CONFIG_LLC is not set
+-# CONFIG_DECNET is not set
+-# CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+ # CONFIG_LAPB is not set
+ # CONFIG_NET_DIVERT is not set
+@@ -160,6 +162,10 @@ CONFIG_IPV6_SCTP__=y
+ # Network testing
+ #
+ # CONFIG_NET_PKTGEN is not set
++CONFIG_DUMMY=y
++# CONFIG_BONDING is not set
++# CONFIG_EQUALIZER is not set
++CONFIG_TUN=y
+ #
+ # Ethernet (10 or 100Mbit)
+@@ -171,6 +177,22 @@ CONFIG_IPV6_SCTP__=y
+ #
+ #
++# Ethernet (10000 Mbit)
++#
++CONFIG_PPP=y
++# CONFIG_PPP_MULTILINK is not set
++# CONFIG_PPP_FILTER is not set
++# CONFIG_PPP_ASYNC is not set
++# CONFIG_PPP_SYNC_TTY is not set
++# CONFIG_PPP_DEFLATE is not set
++# CONFIG_PPP_BSDCOMP is not set
++# CONFIG_PPPOE is not set
++CONFIG_SLIP=y
++# CONFIG_SLIP_COMPRESSED is not set
++# CONFIG_SLIP_SMART is not set
++# CONFIG_SLIP_MODE_SLIP6 is not set
++
++#
+ # Wireless LAN (non-hamradio)
+ #
+ # CONFIG_NET_RADIO is not set
+@@ -188,66 +210,82 @@ CONFIG_IPV6_SCTP__=y
+ #
+ # File systems
+ #
++CONFIG_EXT2_FS=y
++# CONFIG_EXT2_FS_XATTR is not set
++# CONFIG_EXT3_FS is not set
++# CONFIG_JBD is not set
++CONFIG_REISERFS_FS=y
++# CONFIG_REISERFS_CHECK is not set
++# CONFIG_REISERFS_PROC_INFO is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++CONFIG_MINIX_FS=y
++# CONFIG_ROMFS_FS is not set
+ CONFIG_QUOTA=y
+ # CONFIG_QFMT_V1 is not set
+ # CONFIG_QFMT_V2 is not set
+ CONFIG_QUOTACTL=y
+-CONFIG_AUTOFS_FS=m
+-CONFIG_AUTOFS4_FS=m
+-CONFIG_REISERFS_FS=m
+-# CONFIG_REISERFS_CHECK is not set
+-# CONFIG_REISERFS_PROC_INFO is not set
++CONFIG_AUTOFS_FS=y
++CONFIG_AUTOFS4_FS=y
++
++#
++# CD-ROM/DVD Filesystems
++#
++CONFIG_ISO9660_FS=y
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_DEVFS_FS=y
++CONFIG_DEVFS_MOUNT=y
++# CONFIG_DEVFS_DEBUG is not set
++CONFIG_DEVPTS_FS=y
++# CONFIG_DEVPTS_FS_XATTR is not set
++# CONFIG_TMPFS is not set
++CONFIG_RAMFS=y
++
++#
++# Miscellaneous filesystems
++#
+ # CONFIG_ADFS_FS is not set
+ # CONFIG_AFFS_FS is not set
+ # CONFIG_HFS_FS is not set
+ # CONFIG_BEFS_FS is not set
+ # CONFIG_BFS_FS is not set
+-# CONFIG_EXT3_FS is not set
+-# CONFIG_JBD is not set
+-CONFIG_FAT_FS=m
+-CONFIG_MSDOS_FS=m
+-CONFIG_VFAT_FS=m
+ # CONFIG_EFS_FS is not set
+ CONFIG_JFFS_FS=y
+ CONFIG_JFFS_FS_VERBOSE=0
+-CONFIG_JFFS_PROC_FS=y
+ # CONFIG_JFFS2_FS is not set
+ # CONFIG_CRAMFS is not set
+-# CONFIG_TMPFS is not set
+-CONFIG_RAMFS=y
+-CONFIG_ISO9660_FS=m
+-# CONFIG_JOLIET is not set
+-# CONFIG_ZISOFS is not set
+-# CONFIG_JFS_FS is not set
+-CONFIG_MINIX_FS=m
+ # CONFIG_VXFS_FS is not set
+-# CONFIG_NTFS_FS is not set
+ # CONFIG_HPFS_FS is not set
+-CONFIG_PROC_FS=y
+-CONFIG_DEVFS_FS=y
+-CONFIG_DEVFS_MOUNT=y
+-# CONFIG_DEVFS_DEBUG is not set
+-CONFIG_DEVPTS_FS=y
+ # CONFIG_QNX4FS_FS is not set
+-# CONFIG_ROMFS_FS is not set
+-CONFIG_EXT2_FS=y
+-# CONFIG_EXT2_FS_XATTR is not set
+ # CONFIG_SYSV_FS is not set
+-# CONFIG_UDF_FS is not set
+ # CONFIG_UFS_FS is not set
+-# CONFIG_XFS_FS is not set
+ #
+ # Network File Systems
+ #
+-# CONFIG_CODA_FS is not set
+-# CONFIG_INTERMEZZO_FS is not set
+ # CONFIG_NFS_FS is not set
+ # CONFIG_NFSD is not set
+ # CONFIG_EXPORTFS is not set
+-# CONFIG_CIFS 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_INTERMEZZO_FS is not set
+ # CONFIG_AFS_FS is not set
+ #
+@@ -317,28 +355,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
+ #
+ # SCSI support
+ #
+-CONFIG_SCSI=y
+-CONFIG_GENERIC_ISA_DMA=y
+-
+-#
+-# SCSI support type (disk, tape, CD-ROM)
+-#
+-CONFIG_BLK_DEV_SD=y
+-CONFIG_SD_EXTRA_DEVS=40
+-CONFIG_CHR_DEV_ST=y
+-CONFIG_BLK_DEV_SR=y
+-CONFIG_BLK_DEV_SR_VENDOR=y
+-CONFIG_SR_EXTRA_DEVS=2
+-CONFIG_CHR_DEV_SG=y
+-
+-#
+-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+-#
+-CONFIG_SCSI_DEBUG_QUEUES=y
+-CONFIG_SCSI_MULTI_LUN=y
+-CONFIG_SCSI_CONSTANTS=y
+-CONFIG_SCSI_LOGGING=y
+-CONFIG_SCSI_DEBUG=y
++# CONFIG_SCSI is not set
+ #
+ # Multi-device support (RAID and LVM)
+@@ -360,6 +377,7 @@ CONFIG_MTD_CHAR=y
+ CONFIG_MTD_BLOCK=y
+ # CONFIG_FTL is not set
+ # CONFIG_NFTL is not set
++# CONFIG_INFTL is not set
+ #
+ # RAM/ROM/Flash chip drivers
+@@ -374,20 +392,21 @@ CONFIG_MTD_BLOCK=y
+ #
+ # Mapping drivers for chip access
+ #
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+ #
+ # Self-contained MTD device drivers
+ #
+ # CONFIG_MTD_SLRAM is not set
+ # CONFIG_MTD_MTDRAM is not set
+-CONFIG_MTD_BLKMTD=m
++CONFIG_MTD_BLKMTD=y
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOC2001PLUS is not set
+ #
+ # NAND Flash Device Drivers
+--- linux-2.6.0-test6/arch/um/drivers/chan_kern.c      2003-06-14 12:18:35.000000000 -0700
++++ 25/arch/um/drivers/chan_kern.c     2003-10-05 00:34:32.000000000 -0700
+@@ -8,6 +8,7 @@
+ #include <linux/list.h>
+ #include <linux/slab.h>
+ #include <linux/tty.h>
++#include <linux/string.h>
+ #include <linux/tty_flip.h>
+ #include <asm/irq.h>
+ #include "chan_kern.h"
+--- linux-2.6.0-test6/arch/um/drivers/chan_user.c      2003-06-14 12:17:56.000000000 -0700
++++ 25/arch/um/drivers/chan_user.c     2003-10-05 00:34:32.000000000 -0700
+@@ -188,8 +188,8 @@ void register_winch(int fd, void *device
+       if(!isatty(fd)) return;
+       pid = tcgetpgrp(fd);
+-      if(!CHOOSE_MODE(is_tracer_winch(pid, fd, device_data), 0) && 
+-         (pid == -1)){
++      if(!CHOOSE_MODE_PROC(is_tracer_winch, is_skas_winch, pid, fd, 
++                           device_data) && (pid == -1)){
+               thread = winch_tramp(fd, device_data, &thread_fd);
+               if(fd != -1){
+                       register_winch_irq(thread_fd, fd, thread, device_data);
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/arch/um/drivers/cow.h   2003-10-05 00:34:32.000000000 -0700
+@@ -0,0 +1,40 @@
++#ifndef __COW_H__
++#define __COW_H__
++
++#include <asm/types.h>
++
++#if __BYTE_ORDER == __BIG_ENDIAN
++# define ntohll(x) (x)
++# define htonll(x) (x)
++#elif __BYTE_ORDER == __LITTLE_ENDIAN
++# define ntohll(x)  bswap_64(x)
++# define htonll(x)  bswap_64(x)
++#else
++#error "__BYTE_ORDER not defined"
++#endif
++
++extern int init_cow_file(int fd, char *cow_file, char *backing_file, 
++                       int sectorsize, int *bitmap_offset_out, 
++                       unsigned long *bitmap_len_out, int *data_offset_out);
++
++extern int file_reader(__u64 offset, char *buf, int len, void *arg);
++extern int read_cow_header(int (*reader)(__u64, char *, int, void *), 
++                         void *arg, __u32 *magic_out, 
++                         char **backing_file_out, time_t *mtime_out, 
++                         __u64 *size_out, int *sectorsize_out, 
++                         int *bitmap_offset_out);
++
++extern int write_cow_header(char *cow_file, int fd, char *backing_file, 
++                          int sectorsize, long long *size);
++
++extern void cow_sizes(__u64 size, int sectorsize, int bitmap_offset, 
++                    unsigned long *bitmap_len_out, int *data_offset_out);
++
++#endif
++
++/*
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/arch/um/drivers/cow_kern.c      2003-10-05 00:34:32.000000000 -0700
+@@ -0,0 +1,628 @@
++#define COW_MAJOR 60
++#define MAJOR_NR COW_MAJOR
++
++#include <linux/stddef.h>
++#include <linux/kernel.h>
++#include <linux/ctype.h>
++#include <linux/stat.h>
++#include <linux/vmalloc.h>
++#include <linux/blkdev.h>
++#include <linux/blk.h>
++#include <linux/fs.h>
++#include <linux/genhd.h>
++#include <linux/devfs_fs.h>
++#include <asm/uaccess.h>
++#include "2_5compat.h"
++#include "cow.h"
++#include "ubd_user.h"
++
++#define COW_SHIFT 4
++
++struct cow {
++      int count;
++      char *cow_path;
++      dev_t cow_dev;
++      struct block_device *cow_bdev;
++      char *backing_path;
++      dev_t backing_dev;
++      struct block_device *backing_bdev;
++      int sectorsize;
++      unsigned long *bitmap;
++      unsigned long bitmap_len;
++      int bitmap_offset;
++      int data_offset;
++      devfs_handle_t devfs;
++      struct semaphore sem;
++      struct semaphore io_sem;
++      atomic_t working;
++      spinlock_t io_lock;
++      struct buffer_head *bh;
++      struct buffer_head *bhtail;
++      void *end_io;
++};
++
++#define DEFAULT_COW { \
++      .count                  = 0, \
++      .cow_path               = NULL, \
++      .cow_dev                = 0, \
++      .backing_path           = NULL, \
++      .backing_dev            = 0, \
++        .bitmap                       = NULL, \
++      .bitmap_len             = 0, \
++      .bitmap_offset          = 0, \
++        .data_offset          = 0, \
++      .devfs                  = NULL, \
++      .working                = ATOMIC_INIT(0), \
++      .io_lock                = SPIN_LOCK_UNLOCKED, \
++}
++
++#define MAX_DEV (8)
++#define MAX_MINOR (MAX_DEV << COW_SHIFT)
++
++struct cow cow_dev[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_COW };
++
++/* Not modified by this driver */
++static int blk_sizes[MAX_MINOR] = { [ 0 ... MAX_MINOR - 1 ] = BLOCK_SIZE };
++static int hardsect_sizes[MAX_MINOR] = { [ 0 ... MAX_MINOR - 1 ] = 512 };
++
++/* Protected by cow_lock */
++static int sizes[MAX_MINOR] = { [ 0 ... MAX_MINOR - 1 ] = 0 };
++
++static struct hd_struct       cow_part[MAX_MINOR] =
++      { [ 0 ... MAX_MINOR - 1 ] = { 0, 0, 0 } };
++
++/* Protected by io_request_lock */
++static request_queue_t *cow_queue;
++
++static int cow_open(struct inode *inode, struct file *filp);
++static int cow_release(struct inode * inode, struct file * file);
++static int cow_ioctl(struct inode * inode, struct file * file,
++                   unsigned int cmd, unsigned long arg);
++static int cow_revalidate(kdev_t rdev);
++
++static struct block_device_operations cow_blops = {
++       .open          = cow_open,
++       .release       = cow_release,
++       .ioctl         = cow_ioctl,
++       .revalidate    = cow_revalidate,
++};
++
++/* Initialized in an initcall, and unchanged thereafter */
++devfs_handle_t cow_dir_handle;
++
++#define INIT_GENDISK(maj, name, parts, shift, bsizes, max, blops) \
++{ \
++      .major          = maj, \
++      .major_name     = name, \
++      .minor_shift    = shift, \
++      .max_p          = 1 << shift, \
++      .part           = parts, \
++      .sizes          = bsizes, \
++      .nr_real        = max, \
++      .real_devices   = NULL, \
++      .next           = NULL, \
++      .fops           = blops, \
++      .de_arr         = NULL, \
++      .flags          = 0 \
++}
++
++static spinlock_t cow_lock = SPIN_LOCK_UNLOCKED;
++
++static struct gendisk cow_gendisk = INIT_GENDISK(MAJOR_NR, "cow", cow_part,
++                                               COW_SHIFT, sizes, MAX_DEV, 
++                                               &cow_blops);
++
++static int cow_add(int n)
++{
++      struct cow *dev = &cow_dev[n];
++      char name[sizeof("nnnnnn\0")];
++      int err = -ENODEV;
++
++      if(dev->cow_path == NULL)
++              goto out;
++
++      sprintf(name, "%d", n);
++      dev->devfs = devfs_register(cow_dir_handle, name, DEVFS_FL_REMOVABLE,
++                                  MAJOR_NR, n << COW_SHIFT, S_IFBLK | 
++                                  S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
++                                  &cow_blops, NULL);
++
++      init_MUTEX_LOCKED(&dev->sem);
++      init_MUTEX(&dev->io_sem);
++
++      return(0);
++
++out:
++      return(err);
++}
++
++/*
++* Add buffer_head to back of pending list
++*/
++static void cow_add_bh(struct cow *cow, struct buffer_head *bh)
++{
++      unsigned long flags;
++
++      spin_lock_irqsave(&cow->io_lock, flags);
++      if(cow->bhtail != NULL){
++              cow->bhtail->b_reqnext = bh;
++              cow->bhtail = bh;
++      }
++      else {
++              cow->bh = bh;
++              cow->bhtail = bh;
++      }
++      spin_unlock_irqrestore(&cow->io_lock, flags);
++}
++
++/*
++* Grab first pending buffer
++*/
++static struct buffer_head *cow_get_bh(struct cow *cow)
++{
++      struct buffer_head *bh;
++
++      spin_lock_irq(&cow->io_lock);
++      bh = cow->bh;
++      if(bh != NULL){
++              if(bh == cow->bhtail)
++                      cow->bhtail = NULL;
++              cow->bh = bh->b_reqnext;
++              bh->b_reqnext = NULL;
++      }
++      spin_unlock_irq(&cow->io_lock);
++
++      return(bh);
++}
++
++static void cow_handle_bh(struct cow *cow, struct buffer_head *bh, 
++                        struct buffer_head **cow_bh, int ncow_bh)
++{
++      int i;
++
++      if(ncow_bh > 0)
++              ll_rw_block(WRITE, ncow_bh, cow_bh);
++
++      for(i = 0; i < ncow_bh ; i++){
++              wait_on_buffer(cow_bh[i]);
++              brelse(cow_bh[i]);
++      }
++
++      ll_rw_block(WRITE, 1, &bh);
++      brelse(bh);
++}
++
++static struct buffer_head *cow_new_bh(struct cow *dev, int sector)
++{
++      struct buffer_head *bh;
++
++      sector = (dev->bitmap_offset + sector / 8) / dev->sectorsize;
++      bh = getblk(dev->cow_dev, sector, dev->sectorsize);
++      memcpy(bh->b_data, dev->bitmap + sector / (8 * sizeof(dev->bitmap[0])),
++             dev->sectorsize);
++      return(bh);
++}
++
++/* Copied from loop.c, needed to avoid deadlocking in make_request. */
++
++static int cow_thread(void *data)
++{
++      struct cow *dev = data;
++      struct buffer_head *bh;
++
++      daemonize();
++      exit_files(current);
++
++      sprintf(current->comm, "cow%d", dev - cow_dev);
++
++      spin_lock_irq(&current->sigmask_lock);
++      sigfillset(&current->blocked);
++      flush_signals(current);
++      spin_unlock_irq(&current->sigmask_lock);
++
++      atomic_inc(&dev->working);
++
++      current->policy = SCHED_OTHER;
++      current->nice = -20;
++
++      current->flags |= PF_NOIO;
++
++      /*
++       * up sem, we are running
++       */
++      up(&dev->sem);
++
++      for(;;){
++              int start, len, nbh, i, update_bitmap = 0;
++              struct buffer_head *cow_bh[2];
++
++              down_interruptible(&dev->io_sem);
++              /*
++               * could be upped because of tear-down, not because of
++               * pending work
++               */
++              if(!atomic_read(&dev->working))
++                      break;
++
++              bh = cow_get_bh(dev);
++              if(bh == NULL){
++                      printk(KERN_ERR "cow: missing bh\n");
++                      continue;
++              }
++
++              start = bh->b_blocknr * bh->b_size / dev->sectorsize;
++              len = bh->b_size / dev->sectorsize;
++              for(i = 0; i < len ; i++){
++                      if(ubd_test_bit(start +ni, 
++                                      (unsigned char *) dev->bitmap))
++                              continue;
++
++                      update_bitmap = 1;
++                      ubd_set_bit(start + i, (unsigned char *) dev->bitmap);
++              }
++
++              cow_bh[0] = NULL;
++              cow_bh[1] = NULL;
++              nbh = 0;
++              if(update_bitmap){
++                      cow_bh[0] = cow_new_bh(dev, start);
++                      nbh++;
++                      if(start / dev->sectorsize != 
++                         (start + len) / dev->sectorsize){
++                              cow_bh[1] = cow_new_bh(dev, start + len);
++                              nbh++;
++                      }
++              }
++              
++              bh->b_dev = dev->cow_dev;
++              bh->b_blocknr += dev->data_offset / dev->sectorsize;
++
++              cow_handle_bh(dev, bh, cow_bh, nbh);
++
++              /*
++               * upped both for pending work and tear-down, lo_pending
++               * will hit zero then
++               */
++              if(atomic_dec_and_test(&dev->working))
++                      break;
++      }
++
++      up(&dev->sem);
++      return(0);
++}
++
++static int cow_make_request(request_queue_t *q, int rw, struct buffer_head *bh)
++{
++      struct cow *dev;
++      int n, minor;
++
++      minor = MINOR(bh->b_rdev);
++      n = minor >> COW_SHIFT;
++      dev = &cow_dev[n];
++
++      dev->end_io = NULL;
++      if(ubd_test_bit(bh->b_rsector, (unsigned char *) dev->bitmap)){
++              bh->b_rdev = dev->cow_dev;
++              bh->b_rsector += dev->data_offset / dev->sectorsize;
++      }
++      else if(rw == WRITE){
++              bh->b_dev = dev->cow_dev;
++              bh->b_blocknr += dev->data_offset / dev->sectorsize;
++
++              cow_add_bh(dev, bh);
++              up(&dev->io_sem);
++              return(0);
++      }
++      else {
++              bh->b_rdev = dev->backing_dev;
++      }
++
++      return(1);
++}
++
++int cow_init(void)
++{
++      int i;
++
++      cow_dir_handle = devfs_mk_dir (NULL, "cow", NULL);
++      if (devfs_register_blkdev(MAJOR_NR, "cow", &cow_blops)) {
++              printk(KERN_ERR "cow: unable to get major %d\n", MAJOR_NR);
++              return -1;
++      }
++      read_ahead[MAJOR_NR] = 8;               /* 8 sector (4kB) read-ahead */
++      blksize_size[MAJOR_NR] = blk_sizes;
++      blk_size[MAJOR_NR] = sizes;
++      INIT_HARDSECT(hardsect_size, MAJOR_NR, hardsect_sizes);
++
++      cow_queue = BLK_DEFAULT_QUEUE(MAJOR_NR);
++      blk_init_queue(cow_queue, NULL);
++      INIT_ELV(cow_queue, &cow_queue->elevator);
++      blk_queue_make_request(cow_queue, cow_make_request);
++
++       add_gendisk(&cow_gendisk);
++
++      for(i=0;i<MAX_DEV;i++) 
++              cow_add(i);
++
++      return(0);
++}
++
++__initcall(cow_init);
++
++static int reader(__u64 start, char *buf, int count, void *arg)
++{
++      dev_t dev = *((dev_t *) arg);
++      struct buffer_head *bh;
++      __u64 block;
++      int cur, offset, left, n, blocksize = get_hardsect_size(dev);
++
++      if(blocksize == 0)
++              panic("Zero blocksize");
++
++      block = start / blocksize;
++      offset = start % blocksize;
++      left = count;
++      cur = 0;
++      while(left > 0){
++              n = (left > blocksize) ? blocksize : left;
++
++              bh = bread(dev, block, (n < 512) ? 512 : n);
++              if(bh == NULL)
++                      return(-EIO);
++
++              n -= offset;
++              memcpy(&buf[cur], bh->b_data + offset, n);
++              block++;
++              left -= n;
++              cur += n;
++              offset = 0;
++              brelse(bh);
++      }
++
++      return(count);
++}
++
++static int cow_open(struct inode *inode, struct file *filp)
++{
++      int (*dev_ioctl)(struct inode *, struct file *, unsigned int, 
++                       unsigned long);
++      mm_segment_t fs;
++      struct cow *dev;
++      __u64 size;
++      __u32 magic;
++      time_t mtime;
++      char *backing_file;
++      int n, offset, err = 0;
++
++      n = DEVICE_NR(inode->i_rdev);
++      if(n >= MAX_DEV)
++              return(-ENODEV);
++      dev = &cow_dev[n];
++      offset = n << COW_SHIFT;
++
++      spin_lock(&cow_lock);
++
++      if(dev->count == 0){
++              dev->cow_dev = name_to_kdev_t(dev->cow_path);
++              if(dev->cow_dev == 0){
++                      printk(KERN_ERR "cow_open - name_to_kdev_t(\"%s\") "
++                             "failed\n", dev->cow_path);
++                      err = -ENODEV;
++              }
++
++              dev->backing_dev = name_to_kdev_t(dev->backing_path);
++              if(dev->backing_dev == 0){
++                      printk(KERN_ERR "cow_open - name_to_kdev_t(\"%s\") "
++                             "failed\n", dev->backing_path);
++                      err = -ENODEV;
++              }
++
++              if(err) 
++                      goto out;
++
++              dev->cow_bdev = bdget(dev->cow_dev);
++              if(dev->cow_bdev == NULL){
++                      printk(KERN_ERR "cow_open - bdget(\"%s\") failed\n", 
++                             dev->cow_path);
++                      err = -ENOMEM;
++              }
++              dev->backing_bdev = bdget(dev->backing_dev);
++              if(dev->backing_bdev == NULL){
++                      printk(KERN_ERR "cow_open - bdget(\"%s\") failed\n", 
++                             dev->backing_path);
++                      err = -ENOMEM;
++              }
++
++              if(err) 
++                      goto out;
++
++              err = blkdev_get(dev->cow_bdev, FMODE_READ|FMODE_WRITE, 0, 
++                               BDEV_RAW);
++              if(err){
++                      printk("cow_open - blkdev_get of COW device failed, "
++                             "error = %d\n", err);
++                      goto out;
++              }
++              
++              err = blkdev_get(dev->backing_bdev, FMODE_READ, 0, BDEV_RAW);
++              if(err){
++                      printk("cow_open - blkdev_get of backing device "
++                             "failed, error = %d\n", err);
++                      goto out;
++              }
++              
++              err = read_cow_header(reader, &dev->cow_dev, &magic, 
++                                    &backing_file, &mtime, &size,
++                                    &dev->sectorsize, &dev->bitmap_offset);
++              if(err){
++                      printk(KERN_ERR "cow_open - read_cow_header failed, "
++                             "err = %d\n", err);
++                      goto out;
++              }
++
++              cow_sizes(size, dev->sectorsize, dev->bitmap_offset, 
++                        &dev->bitmap_len, &dev->data_offset);
++              dev->bitmap = (void *) vmalloc(dev->bitmap_len);
++              if(dev->bitmap == NULL){
++                      err = -ENOMEM;
++                      printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
++                      goto out;
++              }
++              flush_tlb_kernel_vm();
++              
++              err = reader(dev->bitmap_offset, (char *) dev->bitmap, 
++                           dev->bitmap_len, &dev->cow_dev);
++              if(err < 0){
++                      printk(KERN_ERR "Failed to read COW bitmap\n");
++                      vfree(dev->bitmap);
++                      goto out;
++              }
++
++              dev_ioctl = dev->backing_bdev->bd_op->ioctl;
++              fs = get_fs();
++              set_fs(KERNEL_DS);
++              err = (*dev_ioctl)(inode, filp, BLKGETSIZE, 
++                                 (unsigned long) &sizes[offset]);
++              set_fs(fs);
++              if(err){
++                      printk(KERN_ERR "cow_open - BLKGETSIZE failed, "
++                             "error = %d\n", err);
++                      goto out;
++              }
++
++              kernel_thread(cow_thread, dev, 
++                            CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
++              down(&dev->sem);
++      }
++      dev->count++;
++out:
++      spin_unlock(&cow_lock);
++      return(err);
++}
++
++static int cow_release(struct inode * inode, struct file * file)
++{
++      struct cow *dev;
++      int n, err;
++
++      n = DEVICE_NR(inode->i_rdev);
++      if(n >= MAX_DEV)
++              return(-ENODEV);
++      dev = &cow_dev[n];
++
++      spin_lock(&cow_lock);
++
++      if(--dev->count > 0)
++              goto out;
++
++      err = blkdev_put(dev->cow_bdev, BDEV_RAW);
++      if(err)
++              printk("cow_release - blkdev_put of cow device failed, "
++                     "error = %d\n", err);
++      bdput(dev->cow_bdev);
++      dev->cow_bdev = 0;
++
++      err = blkdev_put(dev->backing_bdev, BDEV_RAW);
++      if(err)
++              printk("cow_release - blkdev_put of backing device failed, "
++                     "error = %d\n", err);
++      bdput(dev->backing_bdev);
++      dev->backing_bdev = 0;
++
++out:
++      spin_unlock(&cow_lock);
++      return(0);
++}
++
++static int cow_ioctl(struct inode * inode, struct file * file,
++                   unsigned int cmd, unsigned long arg)
++{
++      struct cow *dev;
++      int (*dev_ioctl)(struct inode *, struct file *, unsigned int, 
++                       unsigned long);
++      int n;
++
++      n = DEVICE_NR(inode->i_rdev);
++      if(n >= MAX_DEV)
++              return(-ENODEV);
++      dev = &cow_dev[n];
++
++      dev_ioctl = dev->backing_bdev->bd_op->ioctl;
++      return((*dev_ioctl)(inode, file, cmd, arg));
++}
++
++static int cow_revalidate(kdev_t rdev)
++{
++      printk(KERN_ERR "Need to implement cow_revalidate\n");
++      return(0);
++}
++
++static int parse_unit(char **ptr)
++{
++      char *str = *ptr, *end;
++      int n = -1;
++
++      if(isdigit(*str)) {
++              n = simple_strtoul(str, &end, 0);
++              if(end == str)
++                      return(-1);
++              *ptr = end;
++      }
++      else if (('a' <= *str) && (*str <= 'h')) {
++              n = *str - 'a';
++              str++;
++              *ptr = str;
++      }
++      return(n);
++}
++
++static int cow_setup(char *str)
++{
++      struct cow *dev;
++      char *cow_name, *backing_name;
++      int unit;
++
++      unit = parse_unit(&str);
++      if(unit < 0){
++              printk(KERN_ERR "cow_setup - Couldn't parse unit number\n");
++              return(1);
++      }
++
++      if(*str != '='){
++              printk(KERN_ERR "cow_setup - Missing '=' after unit "
++                     "number\n");
++              return(1);
++      }
++      str++;
++
++      cow_name = str;
++      backing_name = strchr(str, ',');
++      if(backing_name == NULL){
++              printk(KERN_ERR "cow_setup - missing backing device name\n");
++              return(0);
++      }
++      *backing_name = '\0';
++      backing_name++;
++
++      spin_lock(&cow_lock);
++
++      dev = &cow_dev[unit];
++      dev->cow_path = cow_name;
++      dev->backing_path = backing_name;
++      
++      spin_unlock(&cow_lock);
++      return(0);
++}
++
++__setup("cow", cow_setup);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/arch/um/drivers/cow_sys.h       2003-10-05 00:34:32.000000000 -0700
+@@ -0,0 +1,48 @@
++#ifndef __COW_SYS_H__
++#define __COW_SYS_H__
++
++#include "kern_util.h"
++#include "user_util.h"
++#include "os.h"
++#include "user.h"
++
++static inline void *cow_malloc(int size)
++{
++      return(um_kmalloc(size));
++}
++
++static inline void cow_free(void *ptr)
++{
++      kfree(ptr);
++}
++
++#define cow_printf printk
++
++static inline char *cow_strdup(char *str)
++{
++      return(uml_strdup(str));
++}
++
++static inline int cow_seek_file(int fd, __u64 offset)
++{
++      return(os_seek_file(fd, offset));
++}
++
++static inline int cow_file_size(char *file, __u64 *size_out)
++{
++      return(os_file_size(file, size_out));
++}
++
++static inline int cow_write_file(int fd, char *buf, int size)
++{
++      return(os_write_file(fd, buf, size));
++}
++
++#endif
++
++/*
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/arch/um/drivers/cow_user.c      2003-10-05 00:34:32.000000000 -0700
+@@ -0,0 +1,296 @@
++#include <stddef.h>
++#include <string.h>
++#include <errno.h>
++#include <unistd.h>
++#include <byteswap.h>
++#include <sys/stat.h>
++#include <sys/time.h>
++#include <sys/param.h>
++#include <netinet/in.h>
++
++#include "cow.h"
++#include "cow_sys.h"
++
++#define PATH_LEN_V1 256
++
++struct cow_header_v1 {
++      int magic;
++      int version;
++      char backing_file[PATH_LEN_V1];
++      time_t mtime;
++      __u64 size;
++      int sectorsize;
++};
++
++#define PATH_LEN_V2 MAXPATHLEN
++
++struct cow_header_v2 {
++      unsigned long magic;
++      unsigned long version;
++      char backing_file[PATH_LEN_V2];
++      time_t mtime;
++      __u64 size;
++      int sectorsize;
++};
++
++union cow_header {
++      struct cow_header_v1 v1;
++      struct cow_header_v2 v2;
++};
++
++#define COW_MAGIC 0x4f4f4f4d  /* MOOO */
++#define COW_VERSION 2
++
++void cow_sizes(__u64 size, int sectorsize, int bitmap_offset, 
++             unsigned long *bitmap_len_out, int *data_offset_out)
++{
++      *bitmap_len_out = (size + sectorsize - 1) / (8 * sectorsize);
++
++      *data_offset_out = bitmap_offset + *bitmap_len_out;
++      *data_offset_out = (*data_offset_out + sectorsize - 1) / sectorsize;
++      *data_offset_out *= sectorsize;
++}
++
++static int absolutize(char *to, int size, char *from)
++{
++      char save_cwd[256], *slash;
++      int remaining;
++
++      if(getcwd(save_cwd, sizeof(save_cwd)) == NULL) {
++              cow_printf("absolutize : unable to get cwd - errno = %d\n", 
++                         errno);
++              return(-1);
++      }
++      slash = strrchr(from, '/');
++      if(slash != NULL){
++              *slash = '\0';
++              if(chdir(from)){
++                      *slash = '/';
++                      cow_printf("absolutize : Can't cd to '%s' - " 
++                                 "errno = %d\n", from, errno);
++                      return(-1);
++              }
++              *slash = '/';
++              if(getcwd(to, size) == NULL){
++                      cow_printf("absolutize : unable to get cwd of '%s' - "
++                             "errno = %d\n", from, errno);
++                      return(-1);
++              }
++              remaining = size - strlen(to);
++              if(strlen(slash) + 1 > remaining){
++                      cow_printf("absolutize : unable to fit '%s' into %d "
++                             "chars\n", from, size);
++                      return(-1);
++              }
++              strcat(to, slash);
++      }
++      else {
++              if(strlen(save_cwd) + 1 + strlen(from) + 1 > size){
++                      cow_printf("absolutize : unable to fit '%s' into %d "
++                             "chars\n", from, size);
++                      return(-1);
++              }
++              strcpy(to, save_cwd);
++              strcat(to, "/");
++              strcat(to, from);
++      }
++      chdir(save_cwd);
++      return(0);
++}
++
++int write_cow_header(char *cow_file, int fd, char *backing_file, 
++                   int sectorsize, long long *size)
++{
++      struct cow_header_v2 *header;
++      struct stat64 buf;
++      int err;
++
++      err = cow_seek_file(fd, 0);
++      if(err != 0){
++              cow_printf("write_cow_header - lseek failed, errno = %d\n", 
++                         errno);
++              return(-errno);
++      }
++
++      err = -ENOMEM;
++      header = cow_malloc(sizeof(*header));
++      if(header == NULL){
++              cow_printf("Failed to allocate COW V2 header\n");
++              goto out;
++      }
++      header->magic = htonl(COW_MAGIC);
++      header->version = htonl(COW_VERSION);
++
++      err = -EINVAL;
++      if(strlen(backing_file) > sizeof(header->backing_file) - 1){
++              cow_printf("Backing file name \"%s\" is too long - names are "
++                         "limited to %d characters\n", backing_file, 
++                         sizeof(header->backing_file) - 1);
++              goto out_free;
++      }
++
++      if(absolutize(header->backing_file, sizeof(header->backing_file), 
++                    backing_file))
++              goto out_free;
++
++      err = stat64(header->backing_file, &buf);
++      if(err < 0){
++              cow_printf("Stat of backing file '%s' failed, errno = %d\n",
++                         header->backing_file, errno);
++              err = -errno;
++              goto out_free;
++      }
++
++      err = cow_file_size(header->backing_file, size);
++      if(err){
++              cow_printf("Couldn't get size of backing file '%s', "
++                         "errno = %d\n", header->backing_file, -*size);
++              goto out_free;
++      }
++
++      header->mtime = htonl(buf.st_mtime);
++      header->size = htonll(*size);
++      header->sectorsize = htonl(sectorsize);
++
++      err = write(fd, header, sizeof(*header));
++      if(err != sizeof(*header)){
++              cow_printf("Write of header to new COW file '%s' failed, "
++                         "errno = %d\n", cow_file, errno);
++              goto out_free;
++      }
++      err = 0;
++ out_free:
++      cow_free(header);
++ out:
++      return(err);
++}
++
++int file_reader(__u64 offset, char *buf, int len, void *arg)
++{
++      int fd = *((int *) arg);
++
++      return(pread(fd, buf, len, offset));
++}
++
++int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, 
++                  __u32 *magic_out, char **backing_file_out, 
++                  time_t *mtime_out, __u64 *size_out, 
++                  int *sectorsize_out, int *bitmap_offset_out)
++{
++      union cow_header *header;
++      char *file;
++      int err, n;
++      unsigned long version, magic;
++
++      header = cow_malloc(sizeof(*header));
++      if(header == NULL){
++              cow_printf("read_cow_header - Failed to allocate header\n");
++              return(-ENOMEM);
++      }
++      err = -EINVAL;
++      n = (*reader)(0, (char *) header, sizeof(*header), arg);
++      if(n < offsetof(typeof(header->v1), backing_file)){
++              cow_printf("read_cow_header - short header\n");
++              goto out;
++      }
++
++      magic = header->v1.magic;
++      if(magic == COW_MAGIC) {
++              version = header->v1.version;
++      }
++      else if(magic == ntohl(COW_MAGIC)){
++              version = ntohl(header->v1.version);
++      }
++      /* No error printed because the non-COW case comes through here */
++      else goto out;
++
++      *magic_out = COW_MAGIC;
++
++      if(version == 1){
++              if(n < sizeof(header->v1)){
++                      cow_printf("read_cow_header - failed to read V1 "
++                                 "header\n");
++                      goto out;
++              }
++              *mtime_out = header->v1.mtime;
++              *size_out = header->v1.size;
++              *sectorsize_out = header->v1.sectorsize;
++              *bitmap_offset_out = sizeof(header->v1);
++              file = header->v1.backing_file;
++      }
++      else if(version == 2){
++              if(n < sizeof(header->v2)){
++                      cow_printf("read_cow_header - failed to read V2 "
++                                 "header\n");
++                      goto out;
++              }
++              *mtime_out = ntohl(header->v2.mtime);
++              *size_out = ntohll(header->v2.size);
++              *sectorsize_out = ntohl(header->v2.sectorsize);
++              *bitmap_offset_out = sizeof(header->v2);
++              file = header->v2.backing_file;
++      }
++      else {
++              cow_printf("read_cow_header - invalid COW version\n");
++              goto out;
++      }
++      err = -ENOMEM;
++      *backing_file_out = cow_strdup(file);
++      if(*backing_file_out == NULL){
++              cow_printf("read_cow_header - failed to allocate backing "
++                         "file\n");
++              goto out;
++      }
++      err = 0;
++ out:
++      cow_free(header);
++      return(err);
++}
++
++int init_cow_file(int fd, char *cow_file, char *backing_file, int sectorsize,
++                int *bitmap_offset_out, unsigned long *bitmap_len_out, 
++                int *data_offset_out)
++{
++      __u64 size, offset;
++      char zero = 0;
++      int err;
++
++      err = write_cow_header(cow_file, fd, backing_file, sectorsize, &size);
++      if(err) 
++              goto out;
++      
++      cow_sizes(size, sectorsize, sizeof(struct cow_header_v2), 
++                bitmap_len_out, data_offset_out);
++      *bitmap_offset_out = sizeof(struct cow_header_v2);
++
++      offset = *data_offset_out + size - sizeof(zero);
++      err = cow_seek_file(fd, offset);
++      if(err != 0){
++              cow_printf("cow bitmap lseek failed : errno = %d\n", errno);
++              goto out;
++      }
++
++      /* does not really matter how much we write it is just to set EOF 
++       * this also sets the entire COW bitmap
++       * to zero without having to allocate it 
++       */
++      err = cow_write_file(fd, &zero, sizeof(zero));
++      if(err != sizeof(zero)){
++              err = -EINVAL;
++              cow_printf("Write of bitmap to new COW file '%s' failed, "
++                         "errno = %d\n", cow_file, errno);
++              goto out;
++      }
++
++      return(0);
++
++ out:
++      return(err);
++}
++
++/*
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- linux-2.6.0-test6/arch/um/drivers/hostaudio_kern.c 2003-06-14 12:18:35.000000000 -0700
++++ 25/arch/um/drivers/hostaudio_kern.c        2003-10-05 00:34:32.000000000 -0700
+@@ -11,6 +11,7 @@
+ #include "linux/fs.h"
+ #include "linux/sound.h"
+ #include "linux/soundcard.h"
++#include "asm/uaccess.h"
+ #include "kern_util.h"
+ #include "init.h"
+ #include "hostaudio.h"
+@@ -22,7 +23,7 @@ char *mixer = HOSTAUDIO_DEV_MIXER;
+ #ifndef MODULE
+ static int set_dsp(char *name, int *add)
+ {
+-      dsp = uml_strdup(name);
++      dsp = name;
+       return(0);
+ }
+@@ -34,7 +35,7 @@ __uml_setup("dsp=", set_dsp,
+ static int set_mixer(char *name, int *add)
+ {
+-      mixer = uml_strdup(name);
++      mixer = name;
+       return(0);
+ }
+@@ -51,23 +52,55 @@ static ssize_t hostaudio_read(struct fil
+                             loff_t *ppos)
+ {
+         struct hostaudio_state *state = file->private_data;
++      void *kbuf;
++      int err;
+ #ifdef DEBUG
+         printk("hostaudio: read called, count = %d\n", count);
+ #endif
+-        return(hostaudio_read_user(state, buffer, count, ppos));
++      kbuf = kmalloc(count, GFP_KERNEL);
++      if(kbuf == NULL)
++              return(-ENOMEM);
++
++        err = hostaudio_read_user(state, kbuf, count, ppos);
++      if(err < 0)
++              goto out;
++
++      if(copy_to_user(buffer, kbuf, err))
++              err = -EFAULT;
++
++ out:
++      kfree(kbuf);
++      return(err);
+ }
+ static ssize_t hostaudio_write(struct file *file, const char *buffer, 
+                              size_t count, loff_t *ppos)
+ {
+         struct hostaudio_state *state = file->private_data;
++      void *kbuf;
++      int err;
+ #ifdef DEBUG
+         printk("hostaudio: write called, count = %d\n", count);
+ #endif
+-        return(hostaudio_write_user(state, buffer, count, ppos));
++
++      kbuf = kmalloc(count, GFP_KERNEL);
++      if(kbuf == NULL)
++              return(-ENOMEM);
++
++      err = -EFAULT;
++      if(copy_from_user(kbuf, buffer, count))
++              goto out;
++
++        err = hostaudio_write_user(state, kbuf, count, ppos);
++      if(err < 0)
++              goto out;
++
++ out:
++      kfree(kbuf);
++      return(err);
+ }
+ static unsigned int hostaudio_poll(struct file *file, 
+@@ -86,12 +119,43 @@ static int hostaudio_ioctl(struct inode 
+                          unsigned int cmd, unsigned long arg)
+ {
+         struct hostaudio_state *state = file->private_data;
++      unsigned long data = 0;
++      int err;
+ #ifdef DEBUG
+         printk("hostaudio: ioctl called, cmd = %u\n", cmd);
+ #endif
++      switch(cmd){
++      case SNDCTL_DSP_SPEED:
++      case SNDCTL_DSP_STEREO:
++      case SNDCTL_DSP_GETBLKSIZE:
++      case SNDCTL_DSP_CHANNELS:
++      case SNDCTL_DSP_SUBDIVIDE:
++      case SNDCTL_DSP_SETFRAGMENT:
++              if(get_user(data, (int *) arg))
++                      return(-EFAULT);
++              break;
++      default:
++              break;
++      }
++
++        err = hostaudio_ioctl_user(state, cmd, (unsigned long) &data);
++
++      switch(cmd){
++      case SNDCTL_DSP_SPEED:
++      case SNDCTL_DSP_STEREO:
++      case SNDCTL_DSP_GETBLKSIZE:
++      case SNDCTL_DSP_CHANNELS:
++      case SNDCTL_DSP_SUBDIVIDE:
++      case SNDCTL_DSP_SETFRAGMENT:
++              if(put_user(data, (int *) arg))
++                      return(-EFAULT);
++              break;
++      default:
++              break;
++      }
+-        return(hostaudio_ioctl_user(state, cmd, arg));
++      return(err);
+ }
+ static int hostaudio_open(struct inode *inode, struct file *file)
+@@ -225,7 +289,8 @@ MODULE_LICENSE("GPL");
+ static int __init hostaudio_init_module(void)
+ {
+-        printk(KERN_INFO "UML Audio Relay\n");
++        printk(KERN_INFO "UML Audio Relay (host dsp = %s, host mixer = %s)\n",
++             dsp, mixer);
+       module_data.dev_audio = register_sound_dsp(&hostaudio_fops, -1);
+         if(module_data.dev_audio < 0){
+--- linux-2.6.0-test6/arch/um/drivers/line.c   2003-06-14 12:18:33.000000000 -0700
++++ 25/arch/um/drivers/line.c  2003-10-05 00:34:32.000000000 -0700
+@@ -6,8 +6,8 @@
+ #include "linux/sched.h"
+ #include "linux/slab.h"
+ #include "linux/list.h"
++#include "linux/interrupt.h"
+ #include "linux/devfs_fs_kernel.h"
+-#include "asm/irq.h"
+ #include "asm/uaccess.h"
+ #include "chan_kern.h"
+ #include "irq_user.h"
+@@ -16,16 +16,18 @@
+ #include "user_util.h"
+ #include "kern_util.h"
+ #include "os.h"
++#include "irq_kern.h"
+ #define LINE_BUFSIZE 4096
+-void line_interrupt(int irq, void *data, struct pt_regs *unused)
++irqreturn_t line_interrupt(int irq, void *data, struct pt_regs *unused)
+ {
+       struct line *dev = data;
+       if(dev->count > 0) 
+               chan_interrupt(&dev->chan_list, &dev->task, dev->tty, irq, 
+                              dev);
++      return IRQ_HANDLED;
+ }
+ void line_timer_cb(void *arg)
+@@ -136,20 +138,22 @@ int line_write(struct line *lines, struc
+       return(len);
+ }
+-void line_write_interrupt(int irq, void *data, struct pt_regs *unused)
++irqreturn_t line_write_interrupt(int irq, void *data, struct pt_regs *unused)
+ {
+       struct line *dev = data;
+       struct tty_struct *tty = dev->tty;
+       int err;
+       err = flush_buffer(dev);
+-      if(err == 0) return;
++      if(err == 0) 
++              return(IRQ_NONE);
+       else if(err < 0){
+               dev->head = dev->buffer;
+               dev->tail = dev->buffer;
+       }
+-      if(tty == NULL) return;
++      if(tty == NULL) 
++              return(IRQ_NONE);
+       if(test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) &&
+          (tty->ldisc.write_wakeup != NULL))
+@@ -161,9 +165,9 @@ void line_write_interrupt(int irq, void 
+        * writes.
+        */
+-      if (waitqueue_active(&tty->write_wait))
++      if(waitqueue_active(&tty->write_wait))
+               wake_up_interruptible(&tty->write_wait);
+-
++      return(IRQ_HANDLED);
+ }
+ int line_write_room(struct tty_struct *tty)
+@@ -369,7 +373,7 @@ int line_get_config(char *name, struct l
+       dev = simple_strtoul(name, &end, 0);
+       if((*end != '\0') || (end == name)){
+-              *error_out = "line_setup failed to parse device number";
++              *error_out = "line_get_config failed to parse device number";
+               return(0);
+       }
+@@ -379,15 +383,15 @@ int line_get_config(char *name, struct l
+       }
+       line = &lines[dev];
++
+       down(&line->sem);
+-      
+       if(!line->valid)
+               CONFIG_CHUNK(str, size, n, "none", 1);
+       else if(line->count == 0)
+               CONFIG_CHUNK(str, size, n, line->init_str, 1);
+       else n = chan_config_string(&line->chan_list, str, size, error_out);
+-
+       up(&line->sem);
++
+       return(n);
+ }
+@@ -412,7 +416,8 @@ struct tty_driver *line_register_devfs(s
+               return NULL;
+       driver->driver_name = line_driver->name;
+-      driver->name = line_driver->devfs_name;
++      driver->name = line_driver->device_name;
++      driver->devfs_name = line_driver->devfs_name;
+       driver->major = line_driver->major;
+       driver->minor_start = line_driver->minor_start;
+       driver->type = line_driver->type;
+@@ -432,7 +437,7 @@ struct tty_driver *line_register_devfs(s
+       for(i = 0; i < nlines; i++){
+               if(!lines[i].valid) 
+-                      tty_unregister_devfs(driver, i);
++                      tty_unregister_device(driver, i);
+       }
+       mconsole_register_dev(&line_driver->mc);
+@@ -465,24 +470,25 @@ struct winch {
+       struct line *line;
+ };
+-void winch_interrupt(int irq, void *data, struct pt_regs *unused)
++irqreturn_t winch_interrupt(int irq, void *data, struct pt_regs *unused)
+ {
+       struct winch *winch = data;
+       struct tty_struct *tty;
+       int err;
+       char c;
+-      err = generic_read(winch->fd, &c, NULL);
+-      if(err < 0){
+-              if(err != -EAGAIN){
+-                      printk("winch_interrupt : read failed, errno = %d\n", 
+-                             -err);
+-                      printk("fd %d is losing SIGWINCH support\n", 
+-                             winch->tty_fd);
+-                      free_irq(irq, data);
+-                      return;
++      if(winch->fd != -1){
++              err = generic_read(winch->fd, &c, NULL);
++              if(err < 0){
++                      if(err != -EAGAIN){
++                              printk("winch_interrupt : read failed, "
++                                     "errno = %d\n", -err);
++                              printk("fd %d is losing SIGWINCH support\n", 
++                                     winch->tty_fd);
++                              return(IRQ_HANDLED);
++                      }
++                      goto out;
+               }
+-              goto out;
+       }
+       tty = winch->line->tty;
+       if(tty != NULL){
+@@ -492,7 +498,9 @@ void winch_interrupt(int irq, void *data
+               kill_pg(tty->pgrp, SIGWINCH, 1);
+       }
+  out:
+-      reactivate_fd(winch->fd, WINCH_IRQ);
++      if(winch->fd != -1)
++              reactivate_fd(winch->fd, WINCH_IRQ);
++      return(IRQ_HANDLED);
+ }
+ DECLARE_MUTEX(winch_handler_sem);
+@@ -529,7 +537,10 @@ static void winch_cleanup(void)
+       list_for_each(ele, &winch_handlers){
+               winch = list_entry(ele, struct winch, list);
+-              close(winch->fd);
++              if(winch->fd != -1){
++                      deactivate_fd(winch->fd, WINCH_IRQ);
++                      close(winch->fd);
++              }
+               if(winch->pid != -1) 
+                       os_kill_process(winch->pid, 1);
+       }
+--- linux-2.6.0-test6/arch/um/drivers/Makefile 2003-06-14 12:18:23.000000000 -0700
++++ 25/arch/um/drivers/Makefile        2003-10-05 00:34:32.000000000 -0700
+@@ -1,5 +1,5 @@
+ # 
+-# Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com)
++# Copyright (C) 2000, 2002, 2003 Jeff Dike (jdike@karaya.com)
+ # Licensed under the GPL
+ #
+@@ -39,6 +39,8 @@ obj-$(CONFIG_PTY_CHAN) += pty.o
+ obj-$(CONFIG_TTY_CHAN) += tty.o 
+ obj-$(CONFIG_XTERM_CHAN) += xterm.o xterm_kern.o
+ obj-$(CONFIG_UML_WATCHDOG) += harddog.o
++obj-$(CONFIG_BLK_DEV_COW) += cow_kern.o
++obj-$(CONFIG_BLK_DEV_COW_COMMON) += cow_user.o
+ obj-y += stdio_console.o $(CHAN_OBJS)
+@@ -46,7 +48,7 @@ USER_SINGLE_OBJS = $(foreach f,$(patsubs
+ USER_OBJS := $(filter %_user.o,$(obj-y) $(obj-m) $(USER_SINGLE_OBJS)) fd.o \
+       null.o pty.o tty.o xterm.o
+-USER_OBJS := $(foreach file,$(USER_OBJS),arch/um/drivers/$(file))
++USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
+ $(USER_OBJS) : %.o: %.c
+       $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
+--- linux-2.6.0-test6/arch/um/drivers/mconsole_kern.c  2003-06-14 12:17:56.000000000 -0700
++++ 25/arch/um/drivers/mconsole_kern.c 2003-10-05 00:34:32.000000000 -0700
+@@ -27,6 +27,7 @@
+ #include "init.h"
+ #include "os.h"
+ #include "umid.h"
++#include "irq_kern.h"
+ static int do_unlink_socket(struct notifier_block *notifier, 
+                           unsigned long what, void *data)
+@@ -67,7 +68,7 @@ void mc_work_proc(void *unused)
+ DECLARE_WORK(mconsole_work, mc_work_proc, NULL);
+-void mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+ {
+       int fd;
+       struct mconsole_entry *new;
+@@ -88,6 +89,7 @@ void mconsole_interrupt(int irq, void *d
+       }
+       if(!list_empty(&mc_requests)) schedule_work(&mconsole_work);
+       reactivate_fd(fd, MCONSOLE_IRQ);
++      return(IRQ_HANDLED);
+ }
+ void mconsole_version(struct mc_request *req)
+@@ -100,20 +102,34 @@ void mconsole_version(struct mc_request 
+       mconsole_reply(req, version, 0, 0);
+ }
++void mconsole_log(struct mc_request *req)
++{
++      int len;
++      char *ptr = req->request.data;
++      
++      ptr += strlen("log");
++      while(isspace(*ptr)) ptr++;
++
++      len = ptr - req->request.data;
++      printk("%.*s", len, ptr);
++      mconsole_reply(req, "", 0, 0);
++}
++
+ #define UML_MCONSOLE_HELPTEXT \
+-"Commands:
+-    version - Get kernel version
+-    help - Print this message
+-    halt - Halt UML
+-    reboot - Reboot UML
+-    config <dev>=<config> - Add a new device to UML; 
+-      same syntax as command line
+-    config <dev> - Query the configuration of a device
+-    remove <dev> - Remove a device from UML
+-    sysrq <letter> - Performs the SysRq action controlled by the letter
+-    cad - invoke the Ctl-Alt-Del handler
+-    stop - pause the UML; it will do nothing until it receives a 'go'
+-    go - continue the UML after a 'stop'
++"Commands: \n\
++    version - Get kernel version \n\
++    help - Print this message \n\
++    halt - Halt UML \n\
++    reboot - Reboot UML \n\
++    config <dev>=<config> - Add a new device to UML;  \n\
++      same syntax as command line \n\
++    config <dev> - Query the configuration of a device \n\
++    remove <dev> - Remove a device from UML \n\
++    sysrq <letter> - Performs the SysRq action controlled by the letter \n\
++    cad - invoke the Ctl-Alt-Del handler \n\
++    stop - pause the UML; it will do nothing until it receives a 'go' \n\
++    go - continue the UML after a 'stop' \n\
++    log <string> - make UML enter <string> into the kernel log\n\
+ "
+ void mconsole_help(struct mc_request *req)
+@@ -302,7 +318,7 @@ int mconsole_init(void)
+       if(umid_file_name("mconsole", file, sizeof(file))) return(-1);
+       snprintf(mconsole_socket_name, sizeof(file), "%s", file);
+-      sock = create_unix_socket(file, sizeof(file));
++      sock = create_unix_socket(file, sizeof(file), 1);
+       if (sock < 0){
+               printk("Failed to initialize management console\n");
+               return(1);
+--- linux-2.6.0-test6/arch/um/drivers/mconsole_user.c  2003-06-14 12:17:59.000000000 -0700
++++ 25/arch/um/drivers/mconsole_user.c 2003-10-05 00:34:32.000000000 -0700
+@@ -28,6 +28,7 @@ static struct mconsole_command commands[
+       { "cad", mconsole_cad, 1 },
+       { "stop", mconsole_stop, 0 },
+       { "go", mconsole_go, 1 },
++      { "log", mconsole_log, 1 },
+ };
+ /* Initialized in mconsole_init, which is an initcall */
+@@ -139,6 +140,7 @@ int mconsole_reply(struct mc_request *re
+               memcpy(reply.data, str, len);
+               reply.data[len] = '\0';
+               total -= len;
++              str += len;
+               reply.len = len + 1;
+               len = sizeof(reply) + reply.len - sizeof(reply.data);
+--- linux-2.6.0-test6/arch/um/drivers/mmapper_kern.c   2003-06-14 12:17:58.000000000 -0700
++++ 25/arch/um/drivers/mmapper_kern.c  2003-10-05 00:34:32.000000000 -0700
+@@ -120,7 +120,10 @@ static int __init mmapper_init(void)
+       printk(KERN_INFO "Mapper v0.1\n");
+       v_buf = (char *) find_iomem("mmapper", &mmapper_size);
+-      if(mmapper_size == 0) return(0);
++      if(mmapper_size == 0){
++              printk(KERN_ERR "mmapper_init - find_iomem failed\n");
++              return(0);
++      }
+       p_buf = __pa(v_buf);
+--- linux-2.6.0-test6/arch/um/drivers/net_kern.c       2003-08-22 19:23:40.000000000 -0700
++++ 25/arch/um/drivers/net_kern.c      2003-10-05 00:34:32.000000000 -0700
+@@ -26,6 +26,7 @@
+ #include "mconsole_kern.h"
+ #include "init.h"
+ #include "irq_user.h"
++#include "irq_kern.h"
+ static spinlock_t opened_lock = SPIN_LOCK_UNLOCKED;
+ LIST_HEAD(opened);
+@@ -61,14 +62,14 @@ static int uml_net_rx(struct net_device 
+       return pkt_len;
+ }
+-void uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+ {
+       struct net_device *dev = dev_id;
+       struct uml_net_private *lp = dev->priv;
+       int err;
+       if(!netif_running(dev))
+-              return;
++              return(IRQ_NONE);
+       spin_lock(&lp->lock);
+       while((err = uml_net_rx(dev)) > 0) ;
+@@ -83,6 +84,7 @@ void uml_net_interrupt(int irq, void *de
+  out:
+       spin_unlock(&lp->lock);
++      return(IRQ_HANDLED);
+ }
+ static int uml_net_open(struct net_device *dev)
+@@ -252,37 +254,6 @@ void uml_net_user_timer_expire(unsigned 
+ #endif
+ }
+-/*
+- * default do nothing hard header packet routines for struct net_device init.
+- * real ethernet transports will overwrite with real routines.
+- */
+-static int uml_net_hard_header(struct sk_buff *skb, struct net_device *dev,
+-                 unsigned short type, void *daddr, void *saddr, unsigned len)
+-{
+-      return(0); /* no change */
+-}
+-
+-static int uml_net_rebuild_header(struct sk_buff *skb)
+-{
+-      return(0); /* ignore */ 
+-}
+-
+-static int uml_net_header_cache(struct neighbour *neigh, struct hh_cache *hh)
+-{
+-      return(-1); /* fail */
+-}
+-
+-static void uml_net_header_cache_update(struct hh_cache *hh,
+-                 struct net_device *dev, unsigned char * haddr)
+-{
+-      /* ignore */
+-}
+-
+-static int uml_net_header_parse(struct sk_buff *skb, unsigned char *haddr)
+-{
+-      return(0); /* nothing */
+-}
+-
+ static spinlock_t devices_lock = SPIN_LOCK_UNLOCKED;
+ static struct list_head devices = LIST_HEAD_INIT(devices);
+@@ -292,7 +263,7 @@ static int eth_configure(int n, void *in
+       struct uml_net *device;
+       struct net_device *dev;
+       struct uml_net_private *lp;
+-      int err, size;
++      int save, err, size;
+       size = transport->private_size + sizeof(struct uml_net_private) + 
+               sizeof(((struct uml_net_private *) 0)->user);
+@@ -334,12 +305,6 @@ static int eth_configure(int n, void *in
+       snprintf(dev->name, sizeof(dev->name), "eth%d", n);
+       device->dev = dev;
+-        dev->hard_header = uml_net_hard_header;
+-        dev->rebuild_header = uml_net_rebuild_header;
+-        dev->hard_header_cache = uml_net_header_cache;
+-        dev->header_cache_update= uml_net_header_cache_update;
+-        dev->hard_header_parse = uml_net_header_parse;
+-
+       (*transport->kern->init)(dev, init);
+       dev->mtu = transport->user->max_packet;
+@@ -362,21 +327,29 @@ static int eth_configure(int n, void *in
+               return 1;
+       lp = dev->priv;
+-      INIT_LIST_HEAD(&lp->list);
+-      spin_lock_init(&lp->lock);
+-      lp->dev = dev;
+-      lp->fd = -1;
+-      lp->mac = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0 };
+-      lp->have_mac = device->have_mac;
+-      lp->protocol = transport->kern->protocol;
+-      lp->open = transport->user->open;
+-      lp->close = transport->user->close;
+-      lp->remove = transport->user->remove;
+-      lp->read = transport->kern->read;
+-      lp->write = transport->kern->write;
+-      lp->add_address = transport->user->add_address;
+-      lp->delete_address = transport->user->delete_address;
+-      lp->set_mtu = transport->user->set_mtu;
++      /* lp.user is the first four bytes of the transport data, which
++       * has already been initialized.  This structure assignment will
++       * overwrite that, so we make sure that .user gets overwritten with
++       * what it already has.
++       */
++      save = lp->user[0];
++      *lp = ((struct uml_net_private) 
++              { .list                 = LIST_HEAD_INIT(lp->list),
++                .lock                 = SPIN_LOCK_UNLOCKED,
++                .dev                  = dev,
++                .fd                   = -1,
++                .mac                  = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0},
++                .have_mac             = device->have_mac,
++                .protocol             = transport->kern->protocol,
++                .open                 = transport->user->open,
++                .close                = transport->user->close,
++                .remove               = transport->user->remove,
++                .read                 = transport->kern->read,
++                .write                = transport->kern->write,
++                .add_address          = transport->user->add_address,
++                .delete_address       = transport->user->delete_address,
++                .set_mtu              = transport->user->set_mtu,
++                .user                 = { save } });
+       init_timer(&lp->tl);
+       lp->tl.function = uml_net_user_timer_expire;
+@@ -609,7 +582,8 @@ static int net_remove(char *str)
+       unregister_netdev(dev);
+       list_del(&device->list);
+-      free_netdev(device);
++      kfree(device);
++      free_netdev(dev);
+       return(0);
+ }
+--- linux-2.6.0-test6/arch/um/drivers/port_kern.c      2003-06-14 12:17:57.000000000 -0700
++++ 25/arch/um/drivers/port_kern.c     2003-10-05 00:34:32.000000000 -0700
+@@ -6,6 +6,7 @@
+ #include "linux/list.h"
+ #include "linux/sched.h"
+ #include "linux/slab.h"
++#include "linux/interrupt.h"
+ #include "linux/irq.h"
+ #include "linux/spinlock.h"
+ #include "linux/errno.h"
+@@ -14,6 +15,7 @@
+ #include "kern_util.h"
+ #include "kern.h"
+ #include "irq_user.h"
++#include "irq_kern.h"
+ #include "port.h"
+ #include "init.h"
+ #include "os.h"
+@@ -44,7 +46,7 @@ struct connection {
+       struct port_list *port;
+ };
+-static void pipe_interrupt(int irq, void *data, struct pt_regs *regs)
++static irqreturn_t pipe_interrupt(int irq, void *data, struct pt_regs *regs)
+ {
+       struct connection *conn = data;
+       int fd;
+@@ -52,7 +54,7 @@ static void pipe_interrupt(int irq, void
+       fd = os_rcv_fd(conn->socket[0], &conn->helper_pid);
+       if(fd < 0){
+               if(fd == -EAGAIN)
+-                      return;
++                      return(IRQ_NONE);
+               printk(KERN_ERR "pipe_interrupt : os_rcv_fd returned %d\n", 
+                      -fd);
+@@ -65,6 +67,7 @@ static void pipe_interrupt(int irq, void
+       list_add(&conn->list, &conn->port->connections);
+       up(&conn->port->sem);
++      return(IRQ_HANDLED);
+ }
+ static int port_accept(struct port_list *port)
+@@ -138,12 +141,13 @@ void port_work_proc(void *unused)
+ DECLARE_WORK(port_work, port_work_proc, NULL);
+-static void port_interrupt(int irq, void *data, struct pt_regs *regs)
++static irqreturn_t port_interrupt(int irq, void *data, struct pt_regs *regs)
+ {
+       struct port_list *port = data;
+       port->has_connection = 1;
+       schedule_work(&port_work);
++      return(IRQ_HANDLED);
+ } 
+ void *port_data(int port_num)
+--- linux-2.6.0-test6/arch/um/drivers/ssl.c    2003-06-14 12:18:21.000000000 -0700
++++ 25/arch/um/drivers/ssl.c   2003-10-05 00:34:32.000000000 -0700
+@@ -53,8 +53,9 @@ static int ssl_remove(char *str);
+ static struct line_driver driver = {
+       .name                   = "UML serial line",
+-      .devfs_name             = "tts/%d",
+-      .major                  = TTYAUX_MAJOR,
++      .device_name            = "ttS",
++      .devfs_name             = "tts/",
++      .major                  = TTY_MAJOR,
+       .minor_start            = 64,
+       .type                   = TTY_DRIVER_TYPE_SERIAL,
+       .subtype                = 0,
+--- linux-2.6.0-test6/arch/um/drivers/stdio_console.c  2003-06-14 12:18:04.000000000 -0700
++++ 25/arch/um/drivers/stdio_console.c 2003-10-05 00:34:32.000000000 -0700
+@@ -83,7 +83,8 @@ static int con_remove(char *str);
+ static struct line_driver driver = {
+       .name                   = "UML console",
+-      .devfs_name             = "vc/%d",
++      .device_name            = "tty",
++      .devfs_name             = "vc/",
+       .major                  = TTY_MAJOR,
+       .minor_start            = 0,
+       .type                   = TTY_DRIVER_TYPE_CONSOLE,
+@@ -159,6 +160,15 @@ static int chars_in_buffer(struct tty_st
+ static int con_init_done = 0;
++static struct tty_operations console_ops = {
++      .open                   = con_open,
++      .close                  = con_close,
++      .write                  = con_write,
++      .chars_in_buffer        = chars_in_buffer,
++      .set_termios            = set_termios,
++      .write_room             = line_write_room,
++};
++
+ int stdio_init(void)
+ {
+       char *new_title;
+@@ -166,7 +176,8 @@ int stdio_init(void)
+       printk(KERN_INFO "Initializing stdio console driver\n");
+       console_driver = line_register_devfs(&console_lines, &driver,
+-                              &console_ops, vts, sizeof(vts)/sizeof(vts[0]));
++                                           &console_ops, vts,
++                                           sizeof(vts)/sizeof(vts[0]));
+       lines_init(vts, sizeof(vts)/sizeof(vts[0]));
+@@ -188,15 +199,6 @@ static void console_write(struct console
+       if(con_init_done) up(&vts[console->index].sem);
+ }
+-static struct tty_operations console_ops = {
+-      .open                   = con_open,
+-      .close                  = con_close,
+-      .write                  = con_write,
+-      .chars_in_buffer        = chars_in_buffer,
+-      .set_termios            = set_termios,
+-      .write_room             = line_write_room,
+-};
+-
+ static struct tty_driver *console_device(struct console *c, int *index)
+ {
+       *index = c->index;
+@@ -212,12 +214,14 @@ static struct console stdiocons = INIT_C
+                                              console_device, console_setup,
+                                              CON_PRINTBUFFER);
+-static void __init stdio_console_init(void)
++static int __init stdio_console_init(void)
+ {
+       INIT_LIST_HEAD(&vts[0].chan_list);
+       list_add(&init_console_chan.list, &vts[0].chan_list);
+       register_console(&stdiocons);
++      return(0);
+ }
++
+ console_initcall(stdio_console_init);
+ static int console_chan_setup(char *str)
+--- linux-2.6.0-test6/arch/um/drivers/ubd_kern.c       2003-09-08 13:58:56.000000000 -0700
++++ 25/arch/um/drivers/ubd_kern.c      2003-10-05 00:34:32.000000000 -0700
+@@ -8,6 +8,13 @@
+  * old style ubd by setting UBD_SHIFT to 0
+  * 2002-09-27...2002-10-18 massive tinkering for 2.5
+  * partitions have changed in 2.5
++ * 2003-01-29 more tinkering for 2.5.59-1
++ * This should now address the sysfs problems and has
++ * the symlink for devfs to allow for booting with
++ * the common /dev/ubd/discX/... names rather than
++ * only /dev/ubdN/discN this version also has lots of
++ * clean ups preparing for ubd-many.
++ * James McMechan
+  */
+ #define MAJOR_NR UBD_MAJOR
+@@ -40,6 +47,7 @@
+ #include "mconsole_kern.h"
+ #include "init.h"
+ #include "irq_user.h"
++#include "irq_kern.h"
+ #include "ubd_user.h"
+ #include "2_5compat.h"
+ #include "os.h"
+@@ -49,9 +57,9 @@ static spinlock_t ubd_lock = SPIN_LOCK_U
+ static void (*do_ubd)(void);
+-static int ubd_open(struct inode * inode, struct file * filp);
+-static int ubd_release(struct inode * inode, struct file * file);
+-static int ubd_ioctl(struct inode * inode, struct file * file,
++static int ubd_open(struct block_device *bdev, struct file * filp);
++static int ubd_release(struct gendisk *disk);
++static int ubd_ioctl(struct block_device *bdev, struct file * file,
+                    unsigned int cmd, unsigned long arg);
+ #define MAX_DEV (8)
+@@ -67,7 +75,7 @@ static struct block_device_operations ub
+ static request_queue_t *ubd_queue;
+ /* Protected by ubd_lock */
+-static int fake_major = 0;
++static int fake_major = MAJOR_NR;
+ static struct gendisk *ubd_gendisk[MAX_DEV];
+ static struct gendisk *fake_gendisk[MAX_DEV];
+@@ -96,12 +104,12 @@ struct cow {
+ struct ubd {
+       char *file;
+-      int is_dir;
+       int count;
+       int fd;
+       __u64 size;
+       struct openflags boot_openflags;
+       struct openflags openflags;
++      int no_cow;
+       struct cow cow;
+ };
+@@ -115,12 +123,12 @@ struct ubd {
+ #define DEFAULT_UBD { \
+       .file =                 NULL, \
+-      .is_dir =               0, \
+       .count =                0, \
+       .fd =                   -1, \
+       .size =                 -1, \
+       .boot_openflags =       OPEN_FLAGS, \
+       .openflags =            OPEN_FLAGS, \
++        .no_cow =               0, \
+         .cow =                        DEFAULT_COW, \
+ }
+@@ -128,8 +136,10 @@ struct ubd ubd_dev[MAX_DEV] = { [ 0 ... 
+ static int ubd0_init(void)
+ {
+-      if(ubd_dev[0].file == NULL)
+-              ubd_dev[0].file = "root_fs";
++      struct ubd *dev = &ubd_dev[0];
++
++      if(dev->file == NULL)
++              dev->file = "root_fs";
+       return(0);
+ }
+@@ -196,19 +206,39 @@ __uml_help(fake_ide_setup,
+ "    Create ide0 entries that map onto ubd devices.\n\n"
+ );
++static int parse_unit(char **ptr)
++{
++      char *str = *ptr, *end;
++      int n = -1;
++
++      if(isdigit(*str)) {
++              n = simple_strtoul(str, &end, 0);
++              if(end == str)
++                      return(-1);
++              *ptr = end;
++      }
++      else if (('a' <= *str) && (*str <= 'h')) {
++              n = *str - 'a';
++              str++;
++              *ptr = str;
++      }
++      return(n);
++}
++
+ static int ubd_setup_common(char *str, int *index_out)
+ {
++      struct ubd *dev;
+       struct openflags flags = global_openflags;
+       char *backing_file;
+       int n, err;
+       if(index_out) *index_out = -1;
+-      n = *str++;
++      n = *str;
+       if(n == '='){
+-              static int fake_major_allowed = 1;
+               char *end;
+               int major;
++              str++;
+               if(!strcmp(str, "sync")){
+                       global_openflags.s = 1;
+                       return(0);
+@@ -220,20 +250,14 @@ static int ubd_setup_common(char *str, i
+                       return(1);
+               }
+-              if(!fake_major_allowed){
+-                      printk(KERN_ERR "Can't assign a fake major twice\n");
+-                      return(1);
+-              }
+-
+               err = 1;
+               spin_lock(&ubd_lock);
+-              if(!fake_major_allowed){
++              if(fake_major != MAJOR_NR){
+                       printk(KERN_ERR "Can't assign a fake major twice\n");
+                       goto out1;
+               }
+  
+               fake_major = major;
+-              fake_major_allowed = 0;
+               printk(KERN_INFO "Setting extra ubd major number to %d\n",
+                      major);
+@@ -243,25 +267,23 @@ static int ubd_setup_common(char *str, i
+               return(err);
+       }
+-      if(n < '0'){
+-              printk(KERN_ERR "ubd_setup : index out of range\n"); }
+-
+-      if((n >= '0') && (n <= '9')) n -= '0';
+-      else if((n >= 'a') && (n <= 'z')) n -= 'a';
+-      else {
+-              printk(KERN_ERR "ubd_setup : device syntax invalid\n");
++      n = parse_unit(&str);
++      if(n < 0){
++              printk(KERN_ERR "ubd_setup : couldn't parse unit number "
++                     "'%s'\n", str);
+               return(1);
+       }
+       if(n >= MAX_DEV){
+-              printk(KERN_ERR "ubd_setup : index out of range "
+-                     "(%d devices)\n", MAX_DEV);      
++              printk(KERN_ERR "ubd_setup : index %d out of range "
++                     "(%d devices)\n", n, MAX_DEV);
+               return(1);
+       }
+       err = 1;
+       spin_lock(&ubd_lock);
+-      if(ubd_dev[n].file != NULL){
++      dev = &ubd_dev[n];
++      if(dev->file != NULL){
+               printk(KERN_ERR "ubd_setup : device already configured\n");
+               goto out2;
+       }
+@@ -276,6 +298,11 @@ static int ubd_setup_common(char *str, i
+               flags.s = 1;
+               str++;
+       }
++      if (*str == 'd'){
++              dev->no_cow = 1;
++              str++;
++      }
++
+       if(*str++ != '='){
+               printk(KERN_ERR "ubd_setup : Expected '='\n");
+               goto out2;
+@@ -284,14 +311,17 @@ static int ubd_setup_common(char *str, i
+       err = 0;
+       backing_file = strchr(str, ',');
+       if(backing_file){
+-              *backing_file = '\0';
+-              backing_file++;
++              if(dev->no_cow)
++                      printk(KERN_ERR "Can't specify both 'd' and a "
++                             "cow file\n");
++              else {
++                      *backing_file = '\0';
++                      backing_file++;
++              }
+       }
+-      ubd_dev[n].file = str;
+-      if(ubd_is_dir(ubd_dev[n].file))
+-              ubd_dev[n].is_dir = 1;
+-      ubd_dev[n].cow.file = backing_file;
+-      ubd_dev[n].boot_openflags = flags;
++      dev->file = str;
++      dev->cow.file = backing_file;
++      dev->boot_openflags = flags;
+  out2:
+       spin_unlock(&ubd_lock);
+       return(err);
+@@ -321,8 +351,7 @@ __uml_help(ubd_setup,
+ static int fakehd_set = 0;
+ static int fakehd(char *str)
+ {
+-      printk(KERN_INFO 
+-             "fakehd : Changing ubd name to \"hd\".\n");
++      printk(KERN_INFO "fakehd : Changing ubd name to \"hd\".\n");
+       fakehd_set = 1;
+       return 1;
+ }
+@@ -391,9 +420,10 @@ static void ubd_handler(void)
+       do_ubd_request(ubd_queue);
+ }
+-static void ubd_intr(int irq, void *dev, struct pt_regs *unused)
++static irqreturn_t ubd_intr(int irq, void *dev, struct pt_regs *unused)
+ {
+       ubd_handler();
++      return(IRQ_HANDLED);
+ }
+ /* Only changed by ubd_init, which is an initcall. */
+@@ -429,16 +459,18 @@ static void ubd_close(struct ubd *dev)
+ static int ubd_open_dev(struct ubd *dev)
+ {
+       struct openflags flags;
+-      int err, n, create_cow, *create_ptr;
++      char **back_ptr;
++      int err, create_cow, *create_ptr;
++      dev->openflags = dev->boot_openflags;
+       create_cow = 0;
+       create_ptr = (dev->cow.file != NULL) ? &create_cow : NULL;
+-      dev->fd = open_ubd_file(dev->file, &dev->openflags, &dev->cow.file,
++      back_ptr = dev->no_cow ? NULL : &dev->cow.file;
++      dev->fd = open_ubd_file(dev->file, &dev->openflags, back_ptr,
+                               &dev->cow.bitmap_offset, &dev->cow.bitmap_len, 
+                               &dev->cow.data_offset, create_ptr);
+       if((dev->fd == -ENOENT) && create_cow){
+-              n = dev - ubd_dev;
+               dev->fd = create_cow_file(dev->file, dev->cow.file, 
+                                         dev->openflags, 1 << 9,
+                                         &dev->cow.bitmap_offset, 
+@@ -455,7 +487,10 @@ static int ubd_open_dev(struct ubd *dev)
+       if(dev->cow.file != NULL){
+               err = -ENOMEM;
+               dev->cow.bitmap = (void *) vmalloc(dev->cow.bitmap_len);
+-              if(dev->cow.bitmap == NULL) goto error;
++              if(dev->cow.bitmap == NULL){
++                      printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
++                      goto error;
++              }
+               flush_tlb_kernel_vm();
+               err = read_cow_bitmap(dev->fd, dev->cow.bitmap, 
+@@ -481,17 +516,31 @@ static int ubd_new_disk(int major, u64 s
+                       
+ {
+       struct gendisk *disk;
++      char from[sizeof("ubd/nnnnn\0")], to[sizeof("discnnnnn/disc\0")];
++      int err;
+       disk = alloc_disk(1 << UBD_SHIFT);
+-      if (!disk)
+-              return -ENOMEM;
++      if(disk == NULL)
++              return(-ENOMEM);
+       disk->major = major;
+       disk->first_minor = unit << UBD_SHIFT;
+       disk->fops = &ubd_blops;
+       set_capacity(disk, size / 512);
+-      sprintf(disk->disk_name, "ubd");
+-      sprintf(disk->devfs_name, "ubd/disc%d", unit);
++      if(major == MAJOR_NR){
++              sprintf(disk->disk_name, "ubd%d", unit);
++              sprintf(disk->devfs_name, "ubd/disc%d", unit);
++              sprintf(from, "ubd/%d", unit);
++              sprintf(to, "disc%d/disc", unit);
++              err = devfs_mk_symlink(from, to);
++              if(err)
++                      printk("ubd_new_disk failed to make link from %s to "
++                             "%s, error = %d\n", from, to, err);
++      }
++      else {
++              sprintf(disk->disk_name, "ubd_fake%d", unit);
++              sprintf(disk->devfs_name, "ubd_fake/disc%d", unit);
++      }
+       disk->private_data = &ubd_dev[unit];
+       disk->queue = ubd_queue;
+@@ -506,10 +555,7 @@ static int ubd_add(int n)
+       struct ubd *dev = &ubd_dev[n];
+       int err;
+-      if(dev->is_dir)
+-              return(-EISDIR);
+-
+-      if (!dev->file)
++      if(dev->file == NULL)
+               return(-ENODEV);
+       if (ubd_open_dev(dev))
+@@ -523,7 +569,7 @@ static int ubd_add(int n)
+       if(err) 
+               return(err);
+  
+-      if(fake_major)
++      if(fake_major != MAJOR_NR)
+               ubd_new_disk(fake_major, dev->size, n, 
+                            &fake_gendisk[n]);
+@@ -561,42 +607,42 @@ static int ubd_config(char *str)
+       return(err);
+ }
+-static int ubd_get_config(char *dev, char *str, int size, char **error_out)
++static int ubd_get_config(char *name, char *str, int size, char **error_out)
+ {
+-      struct ubd *ubd;
++      struct ubd *dev;
+       char *end;
+-      int major, n = 0;
++      int n, len = 0;
+-      major = simple_strtoul(dev, &end, 0);
+-      if((*end != '\0') || (end == dev)){
+-              *error_out = "ubd_get_config : didn't parse major number";
++      n = simple_strtoul(name, &end, 0);
++      if((*end != '\0') || (end == name)){
++              *error_out = "ubd_get_config : didn't parse device number";
+               return(-1);
+       }
+-      if((major >= MAX_DEV) || (major < 0)){
+-              *error_out = "ubd_get_config : major number out of range";
++      if((n >= MAX_DEV) || (n < 0)){
++              *error_out = "ubd_get_config : device number out of range";
+               return(-1);
+       }
+-      ubd = &ubd_dev[major];
++      dev = &ubd_dev[n];
+       spin_lock(&ubd_lock);
+-      if(ubd->file == NULL){
+-              CONFIG_CHUNK(str, size, n, "", 1);
++      if(dev->file == NULL){
++              CONFIG_CHUNK(str, size, len, "", 1);
+               goto out;
+       }
+-      CONFIG_CHUNK(str, size, n, ubd->file, 0);
++      CONFIG_CHUNK(str, size, len, dev->file, 0);
+-      if(ubd->cow.file != NULL){
+-              CONFIG_CHUNK(str, size, n, ",", 0);
+-              CONFIG_CHUNK(str, size, n, ubd->cow.file, 1);
++      if(dev->cow.file != NULL){
++              CONFIG_CHUNK(str, size, len, ",", 0);
++              CONFIG_CHUNK(str, size, len, dev->cow.file, 1);
+       }
+-      else CONFIG_CHUNK(str, size, n, "", 1);
++      else CONFIG_CHUNK(str, size, len, "", 1);
+  out:
+       spin_unlock(&ubd_lock);
+-      return(n);
++      return(len);
+ }
+ static int ubd_remove(char *str)
+@@ -604,11 +650,9 @@ static int ubd_remove(char *str)
+       struct ubd *dev;
+       int n, err = -ENODEV;
+-      if(!isdigit(*str))
+-              return(err);    /* it should be a number 0-7/a-h */
++      n = parse_unit(&str);
+-      n = *str - '0';
+-      if(n >= MAX_DEV) 
++      if((n < 0) || (n >= MAX_DEV))
+               return(err);
+       dev = &ubd_dev[n];
+@@ -669,7 +713,7 @@ int ubd_init(void)
+               
+       elevator_init(ubd_queue, &elevator_noop);
+-      if (fake_major != 0) {
++      if (fake_major != MAJOR_NR) {
+               char name[sizeof("ubd_nnn\0")];
+               snprintf(name, sizeof(name), "ubd_%d", fake_major);
+@@ -710,19 +754,13 @@ int ubd_driver_init(void){
+ device_initcall(ubd_driver_init);
+-static int ubd_open(struct inode *inode, struct file *filp)
++static int ubd_open(struct block_device *bdev, struct file *filp)
+ {
+-      struct gendisk *disk = inode->i_bdev->bd_disk;
++      struct gendisk *disk = bdev->bd_disk;
+       struct ubd *dev = disk->private_data;
+-      int err = -EISDIR;
+-
+-      if(dev->is_dir == 1)
+-              goto out;
++      int err = 0;
+-      err = 0;
+       if(dev->count == 0){
+-              dev->openflags = dev->boot_openflags;
+-
+               err = ubd_open_dev(dev);
+               if(err){
+                       printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n",
+@@ -739,9 +777,8 @@ static int ubd_open(struct inode *inode,
+       return(err);
+ }
+-static int ubd_release(struct inode * inode, struct file * file)
++static int ubd_release(struct gendisk *disk)
+ {
+-      struct gendisk *disk = inode->i_bdev->bd_disk;
+       struct ubd *dev = disk->private_data;
+       if(--dev->count == 0)
+@@ -796,15 +833,6 @@ static int prepare_request(struct reques
+       if(req->rq_status == RQ_INACTIVE) return(1);
+-      if(dev->is_dir){
+-              strcpy(req->buffer, "HOSTFS:");
+-              strcat(req->buffer, dev->file);
+-              spin_lock(&ubd_io_lock);
+-              end_request(req, 1);
+-              spin_unlock(&ubd_io_lock);
+-              return(1);
+-      }
+-
+       if((rq_data_dir(req) == WRITE) && !dev->openflags.w){
+               printk("Write attempted on readonly ubd device %s\n", 
+                      disk->disk_name);
+@@ -865,11 +893,11 @@ static void do_ubd_request(request_queue
+       }
+ }
+-static int ubd_ioctl(struct inode * inode, struct file * file,
++static int ubd_ioctl(struct block_device *bdev, struct file * file,
+                    unsigned int cmd, unsigned long arg)
+ {
+       struct hd_geometry *loc = (struct hd_geometry *) arg;
+-      struct ubd *dev = inode->i_bdev->bd_disk->private_data;
++      struct ubd *dev = bdev->bd_disk->private_data;
+       int err;
+       struct hd_driveid ubd_id = {
+               .cyls           = 0,
+@@ -890,7 +918,7 @@ static int ubd_ioctl(struct inode * inod
+       case HDIO_SET_UNMASKINTR:
+               if(!capable(CAP_SYS_ADMIN)) return(-EACCES);
+-              if((arg > 1) || (inode->i_bdev->bd_contains != inode->i_bdev))
++              if((arg > 1) || (bdev->bd_contains != bdev))
+                       return(-EINVAL);
+               return(0);
+@@ -910,7 +938,7 @@ static int ubd_ioctl(struct inode * inod
+       case HDIO_SET_MULTCOUNT:
+               if(!capable(CAP_SYS_ADMIN)) return(-EACCES);
+-              if(inode->i_bdev->bd_contains != inode->i_bdev)
++              if(bdev->bd_contains != bdev)
+                       return(-EINVAL);
+               return(0);
+--- linux-2.6.0-test6/arch/um/drivers/ubd_user.c       2003-06-14 12:18:04.000000000 -0700
++++ 25/arch/um/drivers/ubd_user.c      2003-10-05 00:34:32.000000000 -0700
+@@ -24,142 +24,24 @@
+ #include "user.h"
+ #include "ubd_user.h"
+ #include "os.h"
++#include "cow.h"
+ #include <endian.h>
+ #include <byteswap.h>
+-#if __BYTE_ORDER == __BIG_ENDIAN
+-# define ntohll(x) (x)
+-# define htonll(x) (x)
+-#elif __BYTE_ORDER == __LITTLE_ENDIAN
+-# define ntohll(x)  bswap_64(x)
+-# define htonll(x)  bswap_64(x)
+-#else
+-#error "__BYTE_ORDER not defined"
+-#endif
+-
+-#define PATH_LEN_V1 256
+-
+-struct cow_header_v1 {
+-      int magic;
+-      int version;
+-      char backing_file[PATH_LEN_V1];
+-      time_t mtime;
+-      __u64 size;
+-      int sectorsize;
+-};
+-
+-#define PATH_LEN_V2 MAXPATHLEN
+-
+-struct cow_header_v2 {
+-      unsigned long magic;
+-      unsigned long version;
+-      char backing_file[PATH_LEN_V2];
+-      time_t mtime;
+-      __u64 size;
+-      int sectorsize;
+-};
+-
+-union cow_header {
+-      struct cow_header_v1 v1;
+-      struct cow_header_v2 v2;
+-};
+-
+-#define COW_MAGIC 0x4f4f4f4d  /* MOOO */
+-#define COW_VERSION 2
+-
+-static void sizes(__u64 size, int sectorsize, int bitmap_offset, 
+-                unsigned long *bitmap_len_out, int *data_offset_out)
+-{
+-      *bitmap_len_out = (size + sectorsize - 1) / (8 * sectorsize);
+-
+-      *data_offset_out = bitmap_offset + *bitmap_len_out;
+-      *data_offset_out = (*data_offset_out + sectorsize - 1) / sectorsize;
+-      *data_offset_out *= sectorsize;
+-}
+-
+-static int read_cow_header(int fd, int *magic_out, char **backing_file_out, 
+-                         time_t *mtime_out, __u64 *size_out, 
+-                         int *sectorsize_out, int *bitmap_offset_out)
+-{
+-      union cow_header *header;
+-      char *file;
+-      int err, n;
+-      unsigned long version, magic;
+-
+-      header = um_kmalloc(sizeof(*header));
+-      if(header == NULL){
+-              printk("read_cow_header - Failed to allocate header\n");
+-              return(-ENOMEM);
+-      }
+-      err = -EINVAL;
+-      n = read(fd, header, sizeof(*header));
+-      if(n < offsetof(typeof(header->v1), backing_file)){
+-              printk("read_cow_header - short header\n");
+-              goto out;
+-      }
+-
+-      magic = header->v1.magic;
+-      if(magic == COW_MAGIC) {
+-              version = header->v1.version;
+-      }
+-      else if(magic == ntohl(COW_MAGIC)){
+-              version = ntohl(header->v1.version);
+-      }
+-      else goto out;
+-
+-      *magic_out = COW_MAGIC;
+-
+-      if(version == 1){
+-              if(n < sizeof(header->v1)){
+-                      printk("read_cow_header - failed to read V1 header\n");
+-                      goto out;
+-              }
+-              *mtime_out = header->v1.mtime;
+-              *size_out = header->v1.size;
+-              *sectorsize_out = header->v1.sectorsize;
+-              *bitmap_offset_out = sizeof(header->v1);
+-              file = header->v1.backing_file;
+-      }
+-      else if(version == 2){
+-              if(n < sizeof(header->v2)){
+-                      printk("read_cow_header - failed to read V2 header\n");
+-                      goto out;
+-              }
+-              *mtime_out = ntohl(header->v2.mtime);
+-              *size_out = ntohll(header->v2.size);
+-              *sectorsize_out = ntohl(header->v2.sectorsize);
+-              *bitmap_offset_out = sizeof(header->v2);
+-              file = header->v2.backing_file;
+-      }
+-      else {
+-              printk("read_cow_header - invalid COW version\n");
+-              goto out;
+-      }
+-      err = -ENOMEM;
+-      *backing_file_out = uml_strdup(file);
+-      if(*backing_file_out == NULL){
+-              printk("read_cow_header - failed to allocate backing file\n");
+-              goto out;
+-      }
+-      err = 0;
+- out:
+-      kfree(header);
+-      return(err);
+-}
+ static int same_backing_files(char *from_cmdline, char *from_cow, char *cow)
+ {
+-      struct stat buf1, buf2;
++      struct stat64 buf1, buf2;
+       if(from_cmdline == NULL) return(1);
+       if(!strcmp(from_cmdline, from_cow)) return(1);
+-      if(stat(from_cmdline, &buf1) < 0){
++      if(stat64(from_cmdline, &buf1) < 0){
+               printk("Couldn't stat '%s', errno = %d\n", from_cmdline, 
+                      errno);
+               return(1);
+       }
+-      if(stat(from_cow, &buf2) < 0){
++      if(stat64(from_cow, &buf2) < 0){
+               printk("Couldn't stat '%s', errno = %d\n", from_cow, errno);
+               return(1);
+       }
+@@ -215,118 +97,6 @@ int read_cow_bitmap(int fd, void *buf, i
+       return(0);
+ }
+-static int absolutize(char *to, int size, char *from)
+-{
+-      char save_cwd[256], *slash;
+-      int remaining;
+-
+-      if(getcwd(save_cwd, sizeof(save_cwd)) == NULL) {
+-              printk("absolutize : unable to get cwd - errno = %d\n", errno);
+-              return(-1);
+-      }
+-      slash = strrchr(from, '/');
+-      if(slash != NULL){
+-              *slash = '\0';
+-              if(chdir(from)){
+-                      *slash = '/';
+-                      printk("absolutize : Can't cd to '%s' - errno = %d\n",
+-                             from, errno);
+-                      return(-1);
+-              }
+-              *slash = '/';
+-              if(getcwd(to, size) == NULL){
+-                      printk("absolutize : unable to get cwd of '%s' - "
+-                             "errno = %d\n", from, errno);
+-                      return(-1);
+-              }
+-              remaining = size - strlen(to);
+-              if(strlen(slash) + 1 > remaining){
+-                      printk("absolutize : unable to fit '%s' into %d "
+-                             "chars\n", from, size);
+-                      return(-1);
+-              }
+-              strcat(to, slash);
+-      }
+-      else {
+-              if(strlen(save_cwd) + 1 + strlen(from) + 1 > size){
+-                      printk("absolutize : unable to fit '%s' into %d "
+-                             "chars\n", from, size);
+-                      return(-1);
+-              }
+-              strcpy(to, save_cwd);
+-              strcat(to, "/");
+-              strcat(to, from);
+-      }
+-      chdir(save_cwd);
+-      return(0);
+-}
+-
+-static int write_cow_header(char *cow_file, int fd, char *backing_file, 
+-                          int sectorsize, long long *size)
+-{
+-        struct cow_header_v2 *header;
+-      struct stat64 buf;
+-      int err;
+-
+-      err = os_seek_file(fd, 0);
+-      if(err != 0){
+-              printk("write_cow_header - lseek failed, errno = %d\n", errno);
+-              return(-errno);
+-      }
+-
+-      err = -ENOMEM;
+-      header = um_kmalloc(sizeof(*header));
+-      if(header == NULL){
+-              printk("Failed to allocate COW V2 header\n");
+-              goto out;
+-      }
+-      header->magic = htonl(COW_MAGIC);
+-      header->version = htonl(COW_VERSION);
+-
+-      err = -EINVAL;
+-      if(strlen(backing_file) > sizeof(header->backing_file) - 1){
+-              printk("Backing file name \"%s\" is too long - names are "
+-                     "limited to %d characters\n", backing_file, 
+-                     sizeof(header->backing_file) - 1);
+-              goto out_free;
+-      }
+-
+-      if(absolutize(header->backing_file, sizeof(header->backing_file), 
+-                    backing_file))
+-              goto out_free;
+-
+-      err = stat64(header->backing_file, &buf);
+-      if(err < 0){
+-              printk("Stat of backing file '%s' failed, errno = %d\n",
+-                     header->backing_file, errno);
+-              err = -errno;
+-              goto out_free;
+-      }
+-
+-      err = os_file_size(header->backing_file, size);
+-      if(err){
+-              printk("Couldn't get size of backing file '%s', errno = %d\n",
+-                     header->backing_file, -*size);
+-              goto out_free;
+-      }
+-
+-      header->mtime = htonl(buf.st_mtime);
+-      header->size = htonll(*size);
+-      header->sectorsize = htonl(sectorsize);
+-
+-      err = write(fd, header, sizeof(*header));
+-      if(err != sizeof(*header)){
+-              printk("Write of header to new COW file '%s' failed, "
+-                     "errno = %d\n", cow_file, errno);
+-              goto out_free;
+-      }
+-      err = 0;
+- out_free:
+-      kfree(header);
+- out:
+-      return(err);
+-}
+-
+ int open_ubd_file(char *file, struct openflags *openflags, 
+                 char **backing_file_out, int *bitmap_offset_out, 
+                 unsigned long *bitmap_len_out, int *data_offset_out, 
+@@ -346,10 +116,17 @@ int open_ubd_file(char *file, struct ope
+                 if((fd = os_open_file(file, *openflags, mode)) < 0) 
+                       return(fd);
+         }
++
++      err = os_lock_file(fd, openflags->w);
++      if(err){
++              printk("Failed to lock '%s', errno = %d\n", file, -err);
++              goto error;
++      }
++      
+       if(backing_file_out == NULL) return(fd);
+-      err = read_cow_header(fd, &magic, &backing_file, &mtime, &size, 
+-                            &sectorsize, bitmap_offset_out);
++      err = read_cow_header(file_reader, &fd, &magic, &backing_file, &mtime, 
++                            &size, &sectorsize, bitmap_offset_out);
+       if(err && (*backing_file_out != NULL)){
+               printk("Failed to read COW header from COW file \"%s\", "
+                      "errno = %d\n", file, err);
+@@ -376,12 +153,12 @@ int open_ubd_file(char *file, struct ope
+               if(err) goto error;
+       }
+-      sizes(size, sectorsize, *bitmap_offset_out, bitmap_len_out, 
+-            data_offset_out);
++      cow_sizes(size, sectorsize, *bitmap_offset_out, bitmap_len_out, 
++                data_offset_out);
+         return(fd);
+  error:
+-      close(fd);
++      os_close_file(fd);
+       return(err);
+ }
+@@ -389,10 +166,7 @@ int create_cow_file(char *cow_file, char
+                   int sectorsize, int *bitmap_offset_out, 
+                   unsigned long *bitmap_len_out, int *data_offset_out)
+ {
+-      __u64 blocks;
+-      long zero;
+-      int err, fd, i;
+-      long long size;
++      int err, fd;
+       flags.c = 1;
+       fd = open_ubd_file(cow_file, &flags, NULL, NULL, NULL, NULL, NULL);
+@@ -403,29 +177,12 @@ int create_cow_file(char *cow_file, char
+               goto out;
+       }
+-      err = write_cow_header(cow_file, fd, backing_file, sectorsize, &size);
+-      if(err) goto out_close;
+-
+-      blocks = (size + sectorsize - 1) / sectorsize;
+-      blocks = (blocks + sizeof(long) * 8 - 1) / (sizeof(long) * 8);
+-      zero = 0;
+-      for(i = 0; i < blocks; i++){
+-              err = write(fd, &zero, sizeof(zero));
+-              if(err != sizeof(zero)){
+-                      printk("Write of bitmap to new COW file '%s' failed, "
+-                             "errno = %d\n", cow_file, errno);
+-                      goto out_close;
+-              }
+-      }
+-
+-      sizes(size, sectorsize, sizeof(struct cow_header_v2), 
+-            bitmap_len_out, data_offset_out);
+-      *bitmap_offset_out = sizeof(struct cow_header_v2);
+-
+-      return(fd);
+-
+- out_close:
+-      close(fd);
++      err = init_cow_file(fd, cow_file, backing_file, sectorsize, 
++                          bitmap_offset_out, bitmap_len_out, 
++                          data_offset_out);
++      if(!err)
++              return(fd);
++      os_close_file(fd);
+  out:
+       return(err);
+ }
+@@ -448,14 +205,6 @@ int write_ubd_fs(int fd, char *buffer, i
+       else return(n);
+ }
+-int ubd_is_dir(char *file)
+-{
+-      struct stat64 buf;
+-
+-      if(stat64(file, &buf) < 0) return(0);
+-      return(S_ISDIR(buf.st_mode));
+-}
+-
+ void do_io(struct io_thread_req *req)
+ {
+       char *buf;
+--- linux-2.6.0-test6/arch/um/drivers/xterm.c  2003-06-14 12:17:57.000000000 -0700
++++ 25/arch/um/drivers/xterm.c 2003-10-05 00:34:32.000000000 -0700
+@@ -108,7 +108,7 @@ int xterm_open(int input, int output, in
+       }
+       close(fd);
+-      fd = create_unix_socket(file, sizeof(file));
++      fd = create_unix_socket(file, sizeof(file), 1);
+       if(fd < 0){
+               printk("xterm_open : create_unix_socket failed, errno = %d\n", 
+                      -fd);
+--- linux-2.6.0-test6/arch/um/drivers/xterm_kern.c     2003-06-14 12:18:28.000000000 -0700
++++ 25/arch/um/drivers/xterm_kern.c    2003-10-05 00:34:32.000000000 -0700
+@@ -5,9 +5,12 @@
+ #include "linux/errno.h"
+ #include "linux/slab.h"
++#include "linux/signal.h"
++#include "linux/interrupt.h"
+ #include "asm/semaphore.h"
+ #include "asm/irq.h"
+ #include "irq_user.h"
++#include "irq_kern.h"
+ #include "kern_util.h"
+ #include "os.h"
+ #include "xterm.h"
+@@ -19,17 +22,18 @@ struct xterm_wait {
+       int new_fd;
+ };
+-static void xterm_interrupt(int irq, void *data, struct pt_regs *regs)
++static irqreturn_t xterm_interrupt(int irq, void *data, struct pt_regs *regs)
+ {
+       struct xterm_wait *xterm = data;
+       int fd;
+       fd = os_rcv_fd(xterm->fd, &xterm->pid);
+       if(fd == -EAGAIN)
+-              return;
++              return(IRQ_NONE);
+       xterm->new_fd = fd;
+       up(&xterm->sem);
++      return(IRQ_HANDLED);
+ }
+ int xterm_fd(int socket, int *pid_out)
+--- linux-2.6.0-test6/arch/um/dyn.lds.S        2003-06-14 12:18:21.000000000 -0700
++++ 25/arch/um/dyn.lds.S       2003-10-05 00:34:32.000000000 -0700
+@@ -15,7 +15,11 @@ SECTIONS
+   . = ALIGN(4096);            /* Init code and data */
+   _stext = .;
+   __init_begin = .;
+-  .text.init : { *(.text.init) }
++  .init.text : { 
++      _sinittext = .;
++      *(.init.text)
++      _einittext = .;
++  }
+   . = ALIGN(4096);
+@@ -67,7 +71,7 @@ SECTIONS
+   #include "asm/common.lds.S"
+-  .data.init : { *(.data.init) }
++  init.data : { *(.init.data) }
+   /* Ensure the __preinit_array_start label is properly aligned.  We
+      could instead move the label definition inside the section, but
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/arch/um/include/irq_kern.h      2003-10-05 00:34:32.000000000 -0700
+@@ -0,0 +1,28 @@
++/* 
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __IRQ_KERN_H__
++#define __IRQ_KERN_H__
++
++#include "linux/interrupt.h"
++
++extern int um_request_irq(unsigned int irq, int fd, int type,
++                        irqreturn_t (*handler)(int, void *, 
++                                               struct pt_regs *),
++                        unsigned long irqflags,  const char * devname,
++                        void *dev_id);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- linux-2.6.0-test6/arch/um/include/kern_util.h      2003-06-14 12:18:07.000000000 -0700
++++ 25/arch/um/include/kern_util.h     2003-10-05 00:34:32.000000000 -0700
+@@ -63,10 +63,9 @@ extern void init_flush_vm(void);
+ extern void *syscall_sp(void *t);
+ extern void syscall_trace(void);
+ extern int hz(void);
+-extern void idle_timer(void);
++extern void uml_idle_timer(void);
+ extern unsigned int do_IRQ(int irq, union uml_pt_regs *regs);
+ extern int external_pid(void *t);
+-extern int pid_to_processor_id(int pid);
+ extern void boot_timer_handler(int sig);
+ extern void interrupt_end(void);
+ extern void initial_thread_cb(void (*proc)(void *), void *arg);
+@@ -90,9 +89,7 @@ extern int remove_gdb(void);
+ extern char *uml_strdup(char *string);
+ extern void unprotect_kernel_mem(void);
+ extern void protect_kernel_mem(void);
+-extern void set_kmem_end(unsigned long);
+ extern void uml_cleanup(void);
+-extern int pid_to_processor_id(int pid);
+ extern void set_current(void *t);
+ extern void lock_signalled_task(void *t);
+ extern void IPI_handler(int cpu);
+@@ -101,7 +98,9 @@ extern void *get_init_task(void);
+ extern int clear_user_proc(void *buf, int size);
+ extern int copy_to_user_proc(void *to, void *from, int size);
+ extern int copy_from_user_proc(void *to, void *from, int size);
++extern int strlen_user_proc(char *str);
+ extern void bus_handler(int sig, union uml_pt_regs *regs);
++extern void winch(int sig, union uml_pt_regs *regs);
+ extern long execute_syscall(void *r);
+ extern int smp_sigio_handler(void);
+ extern void *get_current(void);
+--- linux-2.6.0-test6/arch/um/include/line.h   2003-06-14 12:18:29.000000000 -0700
++++ 25/arch/um/include/line.h  2003-10-05 00:34:32.000000000 -0700
+@@ -9,12 +9,14 @@
+ #include "linux/list.h"
+ #include "linux/workqueue.h"
+ #include "linux/tty.h"
++#include "linux/interrupt.h"
+ #include "asm/semaphore.h"
+ #include "chan_user.h"
+ #include "mconsole_kern.h"
+ struct line_driver {
+       char *name;
++      char *device_name;
+       char *devfs_name;
+       short major;
+       short minor_start;
+@@ -67,8 +69,9 @@ struct lines {
+ #define LINES_INIT(n) {  num :                n }
+-extern void line_interrupt(int irq, void *data, struct pt_regs *unused);
+-extern void line_write_interrupt(int irq, void *data, struct pt_regs *unused);
++extern irqreturn_t line_interrupt(int irq, void *data, struct pt_regs *unused);
++extern irqreturn_t line_write_interrupt(int irq, void *data, 
++                                      struct pt_regs *unused);
+ extern void line_close(struct line *lines, struct tty_struct *tty);
+ extern int line_open(struct line *lines, struct tty_struct *tty, 
+                    struct chan_opts *opts);
+--- linux-2.6.0-test6/arch/um/include/mconsole.h       2003-06-14 12:18:08.000000000 -0700
++++ 25/arch/um/include/mconsole.h      2003-10-05 00:34:32.000000000 -0700
+@@ -77,6 +77,7 @@ extern void mconsole_sysrq(struct mc_req
+ extern void mconsole_cad(struct mc_request *req);
+ extern void mconsole_stop(struct mc_request *req);
+ extern void mconsole_go(struct mc_request *req);
++extern void mconsole_log(struct mc_request *req);
+ extern int mconsole_get_request(int fd, struct mc_request *req);
+ extern int mconsole_notify(char *sock_name, int type, const void *data, 
+--- linux-2.6.0-test6/arch/um/include/mem.h    2003-06-14 12:18:51.000000000 -0700
++++ 25/arch/um/include/mem.h   2003-10-05 00:34:32.000000000 -0700
+@@ -13,7 +13,6 @@ struct vm_reserved {
+ };
+ extern void set_usable_vm(unsigned long start, unsigned long end);
+-extern void set_kmem_end(unsigned long new);
+ #endif
+--- linux-2.6.0-test6/arch/um/include/mem_user.h       2003-06-14 12:18:25.000000000 -0700
++++ 25/arch/um/include/mem_user.h      2003-10-05 00:34:32.000000000 -0700
+@@ -51,9 +51,6 @@ extern unsigned long task_size;
+ extern int init_mem_user(void);
+ extern int create_mem_file(unsigned long len);
+-extern void setup_range(int fd, char *driver, unsigned long start,
+-                      unsigned long pfn, unsigned long total, int need_vm, 
+-                      struct mem_region *region, void *reserved);
+ extern void setup_memory(void *entry);
+ extern unsigned long find_iomem(char *driver, unsigned long *len_out);
+ extern int init_maps(struct mem_region *region);
+--- linux-2.6.0-test6/arch/um/include/os.h     2003-06-14 12:18:02.000000000 -0700
++++ 25/arch/um/include/os.h    2003-10-05 00:34:32.000000000 -0700
+@@ -103,10 +103,11 @@ extern int os_accept_connection(int fd);
+ extern int os_shutdown_socket(int fd, int r, int w);
+ extern void os_close_file(int fd);
+ extern int os_rcv_fd(int fd, int *helper_pid_out);
+-extern int create_unix_socket(char *file, int len);
++extern int create_unix_socket(char *file, int len, int close_on_exec);
+ extern int os_connect_socket(char *name);
+ extern int os_file_type(char *file);
+ extern int os_file_mode(char *file, struct openflags *mode_out);
++extern int os_lock_file(int fd, int excl);
+ extern unsigned long os_process_pc(int pid);
+ extern int os_process_parent(int pid);
+@@ -120,6 +121,7 @@ extern int os_map_memory(void *virt, int
+ extern int os_protect_memory(void *addr, unsigned long len, 
+                            int r, int w, int x);
+ extern int os_unmap_memory(void *addr, int len);
++extern void os_flush_stdout(void);
+ #endif
+--- linux-2.6.0-test6/arch/um/include/sysdep-i386/sigcontext.h 2003-06-14 12:18:28.000000000 -0700
++++ 25/arch/um/include/sysdep-i386/sigcontext.h        2003-10-05 00:34:32.000000000 -0700
+@@ -28,8 +28,8 @@
+  */
+ #define SC_START_SYSCALL(sc) do SC_EAX(sc) = -ENOSYS; while(0)
+-/* These are General Protection and Page Fault */
+-#define SEGV_IS_FIXABLE(trap) ((trap == 13) || (trap == 14))
++/* This is Page Fault */
++#define SEGV_IS_FIXABLE(trap) (trap == 14)
+ #define SC_SEGV_IS_FIXABLE(sc) (SEGV_IS_FIXABLE(SC_TRAPNO(sc)))
+--- linux-2.6.0-test6/arch/um/include/ubd_user.h       2003-06-14 12:18:22.000000000 -0700
++++ 25/arch/um/include/ubd_user.h      2003-10-05 00:34:32.000000000 -0700
+@@ -39,7 +39,6 @@ extern int read_ubd_fs(int fd, void *buf
+ extern int write_ubd_fs(int fd, char *buffer, int len);
+ extern int start_io_thread(unsigned long sp, int *fds_out);
+ extern void do_io(struct io_thread_req *req);
+-extern int ubd_is_dir(char *file);
+ static inline int ubd_test_bit(__u64 bit, unsigned char *data)
+ {
+--- linux-2.6.0-test6/arch/um/include/user.h   2003-06-14 12:17:57.000000000 -0700
++++ 25/arch/um/include/user.h  2003-10-05 00:34:32.000000000 -0700
+@@ -14,7 +14,7 @@ extern void *um_kmalloc_atomic(int size)
+ extern void kfree(void *ptr);
+ extern int in_aton(char *str);
+ extern int open_gdb_chan(void);
+-
++extern int strlcpy(char *, const char *, int);
+ #endif
+ /*
+--- linux-2.6.0-test6/arch/um/include/user_util.h      2003-06-14 12:17:58.000000000 -0700
++++ 25/arch/um/include/user_util.h     2003-10-05 00:34:32.000000000 -0700
+@@ -59,7 +59,6 @@ extern int wait_for_stop(int pid, int si
+ extern void *add_signal_handler(int sig, void (*handler)(int));
+ extern int start_fork_tramp(void *arg, unsigned long temp_stack, 
+                           int clone_flags, int (*tramp)(void *));
+-extern int clone_and_wait(int (*fn)(void *), void *arg, void *sp, int flags);
+ extern int linux_main(int argc, char **argv);
+ extern void set_cmdline(char *cmd);
+ extern void input_cb(void (*proc)(void *), void *arg, int arg_len);
+@@ -90,7 +89,8 @@ extern int arch_handle_signal(int sig, u
+ extern int arch_fixup(unsigned long address, void *sc_ptr);
+ extern void forward_pending_sigio(int target);
+ extern int can_do_skas(void);
+- 
++extern void arch_init_thread(void);
++
+ #endif
+ /*
+--- linux-2.6.0-test6/arch/um/Kconfig  2003-08-08 22:55:11.000000000 -0700
++++ 25/arch/um/Kconfig 2003-10-05 00:34:32.000000000 -0700
+@@ -61,6 +61,20 @@ config MODE_SKAS
+ config NET
+       bool "Networking support"
++      help
++      Unless you really know what you are doing, you should say Y here.
++      The reason is that some programs need kernel networking support even
++      when running on a stand-alone machine that isn't connected to any
++      other computer. If you are upgrading from an older kernel, you
++      should consider updating your networking tools too because changes
++      in the kernel and the tools often go hand in hand. The tools are
++      contained in the package net-tools, the location and version number
++      of which are given in Documentation/Changes.
++
++      For a general introduction to Linux networking, it is highly
++      recommended to read the NET-HOWTO, available from
++      <http://www.tldp.org/docs.html#howto>.
++
+ source "fs/Kconfig.binfmt"
+@@ -105,6 +119,16 @@ config MCONSOLE
+ config MAGIC_SYSRQ
+       bool "Magic SysRq key"
+       depends on MCONSOLE
++      help
++      If you say Y here, you will have some control over the system even
++      if the system crashes for example during kernel debugging (e.g., you
++      will be able to flush the buffer cache to disk, reboot the system
++      immediately or dump some status information). This is accomplished
++      by pressing various keys while holding SysRq (Alt+PrintScreen). It
++      also works on a serial console (on PC hardware at least), if you
++      send a BREAK and then within 5 seconds a command keypress. The
++      keys are documented in Documentation/sysrq.txt. Don't say Y
++      unless you really know what this hack does.
+ config HOST_2G_2G
+       bool "2G/2G host address space split"
+@@ -239,6 +263,10 @@ config FRAME_POINTER
+ config PT_PROXY
+       bool "Enable ptrace proxy"
+       depends on XTERM_CHAN && DEBUG_INFO
++      help
++      This option enables a debugging interface which allows gdb to debug
++      the kernel without needing to actually attach to kernel threads.
++      If you want to do kernel debugging, say Y here; otherwise say N.
+ config GPROF
+       bool "Enable gprof support"
+--- linux-2.6.0-test6/arch/um/Kconfig_block    2003-06-14 12:18:25.000000000 -0700
++++ 25/arch/um/Kconfig_block   2003-10-05 00:34:32.000000000 -0700
+@@ -29,6 +29,20 @@ config BLK_DEV_UBD_SYNC
+         wise choice too.  In all other cases (for example, if you're just
+         playing around with User-Mode Linux) you can choose N.
++# Turn this back on when the driver actually works
++#
++#config BLK_DEV_COW
++#     tristate "COW block device"
++#     help
++#     This is a layered driver which sits above two other block devices.
++#     One is read-only, and the other is a read-write layer which stores
++#     all changes.  This provides the illusion that the read-only layer
++#     can be mounted read-write and changed.
++
++config BLK_DEV_COW_COMMON
++      bool
++      default BLK_DEV_COW || BLK_DEV_UBD
++
+ config BLK_DEV_LOOP
+       tristate "Loopback device support"
+--- linux-2.6.0-test6/arch/um/Kconfig_net      2003-06-14 12:18:23.000000000 -0700
++++ 25/arch/um/Kconfig_net     2003-10-05 00:34:32.000000000 -0700
+@@ -1,5 +1,5 @@
+-menu "Network Devices"
++menu "UML Network Devices"
+       depends on NET
+ # UML virtual driver
+@@ -176,73 +176,5 @@ config UML_NET_SLIRP
+       
+         Startup example: "eth0=slirp,FE:FD:01:02:03:04,/usr/local/bin/slirp"
+-
+-# Below are hardware-independent drivers mirrored from
+-# drivers/net/Config.in. It would be nice if Linux
+-# had HW independent drivers separated from the other
+-# but it does not. Until then each non-ISA/PCI arch
+-# needs to provide it's own menu of network drivers
+-config DUMMY
+-      tristate "Dummy net driver support"
+-
+-config BONDING
+-      tristate "Bonding driver support"
+-
+-config EQUALIZER
+-      tristate "EQL (serial line load balancing) support"
+-
+-config TUN
+-      tristate "Universal TUN/TAP device driver support"
+-
+-config ETHERTAP
+-      tristate "Ethertap network tap (OBSOLETE)"
+-      depends on EXPERIMENTAL && NETLINK
+-
+-config PPP
+-      tristate "PPP (point-to-point protocol) support"
+-
+-config PPP_MULTILINK
+-      bool "PPP multilink support (EXPERIMENTAL)"
+-      depends on PPP && EXPERIMENTAL
+-
+-config PPP_FILTER
+-      bool "PPP filtering"
+-      depends on PPP && FILTER
+-
+-config PPP_ASYNC
+-      tristate "PPP support for async serial ports"
+-      depends on PPP
+-
+-config PPP_SYNC_TTY
+-      tristate "PPP support for sync tty ports"
+-      depends on PPP
+-
+-config PPP_DEFLATE
+-      tristate "PPP Deflate compression"
+-      depends on PPP
+-
+-config PPP_BSDCOMP
+-      tristate "PPP BSD-Compress compression"
+-      depends on PPP
+-
+-config PPPOE
+-      tristate "PPP over Ethernet (EXPERIMENTAL)"
+-      depends on PPP && EXPERIMENTAL
+-
+-config SLIP
+-      tristate "SLIP (serial line) support"
+-
+-config SLIP_COMPRESSED
+-      bool "CSLIP compressed headers"
+-      depends on SLIP=y
+-
+-config SLIP_SMART
+-      bool "Keepalive and linefill"
+-      depends on SLIP=y
+-
+-config SLIP_MODE_SLIP6
+-      bool "Six bit SLIP encapsulation"
+-      depends on SLIP=y
+-
+ endmenu
+--- linux-2.6.0-test6/arch/um/kernel/config.c.in       2003-06-14 12:18:28.000000000 -0700
++++ 25/arch/um/kernel/config.c.in      2003-10-05 00:34:32.000000000 -0700
+@@ -7,9 +7,7 @@
+ #include <stdlib.h>
+ #include "init.h"
+-static __initdata char *config = "
+-CONFIG
+-";
++static __initdata char *config = "CONFIG";
+ static int __init print_config(char *line, int *add)
+ {
+--- linux-2.6.0-test6/arch/um/kernel/init_task.c       2003-06-14 12:18:51.000000000 -0700
++++ 25/arch/um/kernel/init_task.c      2003-10-05 00:34:32.000000000 -0700
+@@ -17,6 +17,7 @@ static struct fs_struct init_fs = INIT_F
+ struct mm_struct init_mm = INIT_MM(init_mm);
+ static struct files_struct init_files = INIT_FILES;
+ static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
++static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
+ /*
+  * Initial task structure.
+@@ -38,26 +39,12 @@ union thread_union init_thread_union 
+ __attribute__((__section__(".data.init_task"))) = 
+ { INIT_THREAD_INFO(init_task) };
+-struct task_struct *alloc_task_struct(void)
+-{
+-      return((struct task_struct *) 
+-             __get_free_pages(GFP_KERNEL, CONFIG_KERNEL_STACK_ORDER));
+-}
+-
+ void unprotect_stack(unsigned long stack)
+ {
+       protect_memory(stack, (1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE, 
+                      1, 1, 0, 1);
+ }
+-void free_task_struct(struct task_struct *task)
+-{
+-      /* free_pages decrements the page counter and only actually frees
+-       * the pages if they are now not accessed by anything.
+-       */
+-      free_pages((unsigned long) task, CONFIG_KERNEL_STACK_ORDER);
+-}
+-
+ /*
+  * Overrides for Emacs so that we follow Linus's tabbing style.
+  * Emacs will notice this stuff at the end of the file and automatically
+--- linux-2.6.0-test6/arch/um/kernel/irq.c     2003-08-22 19:23:40.000000000 -0700
++++ 25/arch/um/kernel/irq.c    2003-10-05 00:34:32.000000000 -0700
+@@ -28,6 +28,7 @@
+ #include "user_util.h"
+ #include "kern_util.h"
+ #include "irq_user.h"
++#include "irq_kern.h"
+ static void register_irq_proc (unsigned int irq);
+@@ -82,65 +83,52 @@ struct hw_interrupt_type no_irq_type = {
+       end_none
+ };
+-/* Not changed */
+-volatile unsigned long irq_err_count;
+-
+ /*
+  * Generic, controller-independent functions:
+  */
+-int get_irq_list(char *buf)
++int show_interrupts(struct seq_file *p, void *v)
+ {
+       int i, j;
+-      unsigned long flags;
+       struct irqaction * action;
+-      char *p = buf;
++      unsigned long flags;
+-      p += sprintf(p, "           ");
+-      for (j=0; j<num_online_cpus(); j++)
+-              p += sprintf(p, "CPU%d       ",j);
+-      *p++ = '\n';
++      seq_printf(p, "           ");
++      for (j=0; j<NR_CPUS; j++)
++              if (cpu_online(j))
++                      seq_printf(p, "CPU%d       ",j);
++      seq_putc(p, '\n');
+       for (i = 0 ; i < NR_IRQS ; i++) {
+               spin_lock_irqsave(&irq_desc[i].lock, flags);
+               action = irq_desc[i].action;
+               if (!action) 
+-                      goto end;
+-              p += sprintf(p, "%3d: ",i);
++                      goto skip;
++              seq_printf(p, "%3d: ",i);
+ #ifndef CONFIG_SMP
+-              p += sprintf(p, "%10u ", kstat_irqs(i));
++              seq_printf(p, "%10u ", kstat_irqs(i));
+ #else
+-              for (j = 0; j < num_online_cpus(); j++)
+-                      p += sprintf(p, "%10u ",
+-                              kstat_cpu(cpu_logical_map(j)).irqs[i]);
++              for (j = 0; j < NR_CPUS; j++)
++                      if (cpu_online(j))
++                              seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
+ #endif
+-              p += sprintf(p, " %14s", irq_desc[i].handler->typename);
+-              p += sprintf(p, "  %s", action->name);
++              seq_printf(p, " %14s", irq_desc[i].handler->typename);
++              seq_printf(p, "  %s", action->name);
+               for (action=action->next; action; action = action->next)
+-                      p += sprintf(p, ", %s", action->name);
+-              *p++ = '\n';
+-      end:
++                      seq_printf(p, ", %s", action->name);
++
++              seq_putc(p, '\n');
++skip:
+               spin_unlock_irqrestore(&irq_desc[i].lock, flags);
+       }
+-      p += sprintf(p, "\n");
+-#ifdef notdef
+-#ifdef CONFIG_SMP
+-      p += sprintf(p, "LOC: ");
+-      for (j = 0; j < num_online_cpus(); j++)
+-              p += sprintf(p, "%10u ",
+-                      apic_timer_irqs[cpu_logical_map(j)]);
+-      p += sprintf(p, "\n");
+-#endif
+-#endif
+-      p += sprintf(p, "ERR: %10lu\n", irq_err_count);
+-      return p - buf;
+-}
+-
++      seq_printf(p, "NMI: ");
++      for (j = 0; j < NR_CPUS; j++)
++              if (cpu_online(j))
++                      seq_printf(p, "%10u ", nmi_count(j));
++      seq_putc(p, '\n');
+-int show_interrupts(struct seq_file *p, void *v)
+-{
+-      return(0);
++      return 0;
+ }
+ /*
+@@ -281,13 +269,12 @@ unsigned int do_IRQ(int irq, union uml_p
+        * 0 return value means that this irq is already being
+        * handled by some other CPU. (or is disabled)
+        */
+-      int cpu = smp_processor_id();
+       irq_desc_t *desc = irq_desc + irq;
+       struct irqaction * action;
+       unsigned int status;
+       irq_enter();
+-      kstat_cpu(cpu).irqs[irq]++;
++      kstat_this_cpu.irqs[irq]++;
+       spin_lock(&desc->lock);
+       desc->handler->ack(irq);
+       /*
+@@ -384,7 +371,7 @@ out:
+  */
+  
+ int request_irq(unsigned int irq,
+-              void (*handler)(int, void *, struct pt_regs *),
++              irqreturn_t (*handler)(int, void *, struct pt_regs *),
+               unsigned long irqflags, 
+               const char * devname,
+               void *dev_id)
+@@ -430,15 +417,19 @@ int request_irq(unsigned int irq,
+ }
+ int um_request_irq(unsigned int irq, int fd, int type,
+-                 void (*handler)(int, void *, struct pt_regs *),
++                 irqreturn_t (*handler)(int, void *, struct pt_regs *),
+                  unsigned long irqflags, const char * devname,
+                  void *dev_id)
+ {
+-      int retval;
++      int err;
+-      retval = request_irq(irq, handler, irqflags, devname, dev_id);
+-      if(retval) return(retval);
+-      return(activate_fd(irq, fd, type, dev_id));
++      err = request_irq(irq, handler, irqflags, devname, dev_id);
++      if(err) 
++              return(err);
++
++      if(fd != -1)
++              err = activate_fd(irq, fd, type, dev_id);
++      return(err);
+ }
+ /* this was setup_x86_irq but it seems pretty generic */
+@@ -654,7 +645,7 @@ static int prof_cpu_mask_read_proc (char
+               return -EINVAL;
+       tmp = *mask;
+       for (k = 0; k < sizeof(cpumask_t)/sizeof(u16); ++k) {
+-              int j = sprintf(page, "%04hx", cpus_coerce(tmp));
++              int j = sprintf(page, "%04hx", (short) cpus_coerce(tmp));
+               len += j;
+               page += j;
+               cpus_shift_right(tmp, tmp, 16);
+--- linux-2.6.0-test6/arch/um/kernel/Makefile  2003-08-22 19:23:40.000000000 -0700
++++ 25/arch/um/kernel/Makefile 2003-10-05 00:34:32.000000000 -0700
+@@ -21,6 +21,8 @@ obj-$(CONFIG_TTY_LOG)        += tty_log.o
+ obj-$(CONFIG_MODE_TT) += tt/
+ obj-$(CONFIG_MODE_SKAS) += skas/
++clean-files   := config.c
++
+ user-objs-$(CONFIG_TTY_LOG) += tty_log.o
+ USER_OBJS := $(filter %_user.o,$(obj-y))  $(user-objs-y) config.o helper.o \
+@@ -45,17 +47,13 @@ $(USER_OBJS) : %.o: %.c
+ $(obj)/frame.o: $(src)/frame.c
+       $(CC) $(CFLAGS_$(notdir $@)) -c -o $@ $<
+-QUOTE = 'my $$config=`cat $(TOPDIR)/.config`; $$config =~ s/"/\\"/g ; while(<STDIN>) { $$_ =~ s/CONFIG/$$config/; print $$_ }'
++QUOTE = 'my $$config=`cat $(TOPDIR)/.config`; $$config =~ s/"/\\"/g ; $$config =~ s/\n/\\n"\n"/g ; while(<STDIN>) { $$_ =~ s/CONFIG/$$config/; print $$_ }'
+ $(obj)/config.c : $(src)/config.c.in $(TOPDIR)/.config
+       $(PERL) -e $(QUOTE) < $(src)/config.c.in > $@
+ $(obj)/config.o : $(obj)/config.c
+-clean:
+-      rm -f config.c
+-      for dir in $(subdir-y) ; do $(MAKE) -C $$dir clean; done
+-
+ modules:
+ fastdep:
+--- linux-2.6.0-test6/arch/um/kernel/mem.c     2003-06-14 12:18:08.000000000 -0700
++++ 25/arch/um/kernel/mem.c    2003-10-05 00:34:32.000000000 -0700
+@@ -119,11 +119,6 @@ unsigned long get_kmem_end(void)
+       return(kmem_top);
+ }
+-void set_kmem_end(unsigned long new)
+-{
+-      kmem_top = new;
+-}
+-
+ #ifdef CONFIG_HIGHMEM
+ /* Changed during early boot */
+ pte_t *kmap_pte;
+@@ -218,7 +213,7 @@ static int setup_one_range(int fd, char 
+               if(regions[i] == NULL) break;           
+       }
+       if(i == NREGIONS){
+-              printk("setup_range : no free regions\n");
++              printk("setup_one_range : no free regions\n");
+               i = -1;
+               goto out;
+       }
+@@ -227,7 +222,9 @@ static int setup_one_range(int fd, char 
+               fd = create_mem_file(len);
+       if(region == NULL){
+-              region = alloc_bootmem_low_pages(sizeof(*region));
++              if(kmalloc_ok)
++                      region = kmalloc(sizeof(*region), GFP_KERNEL);
++              else region = alloc_bootmem_low_pages(sizeof(*region));
+               if(region == NULL)
+                       panic("Failed to allocating mem_region");
+       }
+@@ -528,9 +525,9 @@ int nregions(void)
+       return(NREGIONS);
+ }
+-void setup_range(int fd, char *driver, unsigned long start, unsigned long pfn,
+-               unsigned long len, int need_vm, struct mem_region *region, 
+-               void *reserved)
++static void setup_range(int fd, char *driver, unsigned long start, 
++                      unsigned long pfn, unsigned long len, int need_vm, 
++                      struct mem_region *region, void *reserved)
+ {
+       int i, cur;
+--- linux-2.6.0-test6/arch/um/kernel/mem_user.c        2003-06-14 12:18:22.000000000 -0700
++++ 25/arch/um/kernel/mem_user.c       2003-10-05 00:34:32.000000000 -0700
+@@ -111,6 +111,11 @@ int setup_region(struct mem_region *regi
+               offset = 0;
+       }
++      if(offset >= region->len){
++              printf("%ld bytes of physical memory is insufficient\n",
++                     region->len);
++              exit(1);
++      }
+       loc = mmap(start, region->len - offset, PROT_READ | PROT_WRITE, 
+                  MAP_SHARED | MAP_FIXED, region->fd, offset);
+       if(loc != start){
+@@ -122,26 +127,26 @@ int setup_region(struct mem_region *regi
+ static int __init parse_iomem(char *str, int *add)
+ {
+-      struct stat buf;
++      struct stat64 buf;
+       char *file, *driver;
+       int fd;
+       driver = str;
+       file = strchr(str,',');
+       if(file == NULL){
+-              printk("parse_iomem : failed to parse iomem\n");
++              printf("parse_iomem : failed to parse iomem\n");
+               return(1);
+       }
+       *file = '\0';
+       file++;
+       fd = os_open_file(file, of_rdwr(OPENFLAGS()), 0);
+       if(fd < 0){
+-              printk("parse_iomem - Couldn't open io file, errno = %d\n", 
++              printf("parse_iomem - Couldn't open io file, errno = %d\n", 
+                      errno);
+               return(1);
+       }
+-      if(fstat(fd, &buf) < 0) {
+-              printk("parse_iomem - cannot fstat file, errno = %d\n", errno);
++      if(fstat64(fd, &buf) < 0) {
++              printf("parse_iomem - cannot fstat file, errno = %d\n", errno);
+               return(1);
+       }
+       add_iomem(driver, fd, buf.st_size);
+--- linux-2.6.0-test6/arch/um/kernel/process.c 2003-06-14 12:18:32.000000000 -0700
++++ 25/arch/um/kernel/process.c        2003-10-05 00:34:32.000000000 -0700
+@@ -72,7 +72,6 @@ void init_new_thread_signals(int altstac
+                   SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
+       set_handler(SIGUSR2, (__sighandler_t) sig_handler, 
+                   SA_NOMASK | flags, -1);
+-      (void) CHOOSE_MODE(signal(SIGCHLD, SIG_IGN), (void *) 0);
+       signal(SIGHUP, SIG_IGN);
+       init_irq_signals(altstack);
+@@ -127,7 +126,8 @@ int start_fork_tramp(void *thread_arg, u
+       if(err < 0) panic("Waiting for outer trampoline failed - errno = %d", 
+                         errno);
+       if(!WIFSIGNALED(status) || (WTERMSIG(status) != SIGKILL))
+-              panic("outer trampoline didn't exit with SIGKILL");
++              panic("outer trampoline didn't exit with SIGKILL, "
++                    "status = %d", status);
+       return(arg.pid);
+ }
+--- linux-2.6.0-test6/arch/um/kernel/process_kern.c    2003-07-10 18:50:30.000000000 -0700
++++ 25/arch/um/kernel/process_kern.c   2003-10-05 00:34:32.000000000 -0700
+@@ -52,17 +52,12 @@ struct cpu_task cpu_tasks[NR_CPUS] = { [
+ struct task_struct *get_task(int pid, int require)
+ {
+-        struct task_struct *task, *ret;
++        struct task_struct *ret;
+-        ret = NULL;
+         read_lock(&tasklist_lock);
+-        for_each_process(task){
+-                if(task->pid == pid){
+-                        ret = task;
+-                        break;
+-                }
+-        }
++      ret = find_task_by_pid(pid);
+         read_unlock(&tasklist_lock);
++
+         if(require && (ret == NULL)) panic("get_task couldn't find a task\n");
+         return(ret);
+ }
+@@ -103,13 +98,14 @@ unsigned long alloc_stack(int order, int
+ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+ {
+-      struct task_struct *p;
++      int pid;
+       current->thread.request.u.thread.proc = fn;
+       current->thread.request.u.thread.arg = arg;
+-      p = do_fork(CLONE_VM | flags, 0, NULL, 0, NULL, NULL);
+-      if(IS_ERR(p)) panic("do_fork failed in kernel_thread");
+-      return(p->pid);
++      pid = do_fork(CLONE_VM | flags, 0, NULL, 0, NULL, NULL);
++      if(pid < 0)
++              panic("do_fork failed in kernel_thread, errno = %d", pid);
++      return(pid);
+ }
+ void switch_mm(struct mm_struct *prev, struct mm_struct *next, 
+@@ -129,7 +125,7 @@ void set_current(void *t)
+               { external_pid(task), task });
+ }
+-void *switch_to(void *prev, void *next, void *last)
++void *_switch_to(void *prev, void *next, void *last)
+ {
+       return(CHOOSE_MODE(switch_to_tt(prev, next), 
+                          switch_to_skas(prev, next)));
+@@ -149,7 +145,7 @@ void release_thread(struct task_struct *
+ void exit_thread(void)
+ {
+       CHOOSE_MODE(exit_thread_tt(), exit_thread_skas());
+-      unprotect_stack((unsigned long) current->thread_info);
++      unprotect_stack((unsigned long) current_thread);
+ }
+  
+ void *get_current(void)
+@@ -157,6 +153,10 @@ void *get_current(void)
+       return(current);
+ }
++void prepare_to_copy(struct task_struct *tsk)
++{
++}
++
+ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
+               unsigned long stack_top, struct task_struct * p, 
+               struct pt_regs *regs)
+@@ -190,7 +190,7 @@ int current_pid(void)
+ void default_idle(void)
+ {
+-      idle_timer();
++      uml_idle_timer();
+       atomic_inc(&init_mm.mm_count);
+       current->mm = &init_mm;
+@@ -363,10 +363,15 @@ int clear_user_proc(void *buf, int size)
+       return(clear_user(buf, size));
+ }
++int strlen_user_proc(char *str)
++{
++      return(strlen_user(str));
++}
++
+ int smp_sigio_handler(void)
+ {
+ #ifdef CONFIG_SMP
+-      int cpu = current->thread_info->cpu;
++      int cpu = current_thread->cpu;
+       IPI_handler(cpu);
+       if(cpu != 0)
+               return(1);
+@@ -381,7 +386,7 @@ int um_in_interrupt(void)
+ int cpu(void)
+ {
+-      return(current->thread_info->cpu);
++      return(current_thread->cpu);
+ }
+ /*
+--- linux-2.6.0-test6/arch/um/kernel/ptrace.c  2003-06-14 12:17:58.000000000 -0700
++++ 25/arch/um/kernel/ptrace.c 2003-10-05 00:34:32.000000000 -0700
+@@ -311,11 +311,8 @@ void syscall_trace(void)
+       /* the 0x80 provides a way for the tracing parent to distinguish
+          between a syscall stop and SIGTRAP delivery */
+-      current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+-                                      ? 0x80 : 0);
+-      current->state = TASK_STOPPED;
+-      notify_parent(current, SIGCHLD);
+-      schedule();
++      ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
++                               ? 0x80 : 0));
+       /*
+        * this isn't the same as continuing with a signal, but it will do
+--- linux-2.6.0-test6/arch/um/kernel/sigio_kern.c      2003-06-14 12:18:04.000000000 -0700
++++ 25/arch/um/kernel/sigio_kern.c     2003-10-05 00:34:32.000000000 -0700
+@@ -6,18 +6,21 @@
+ #include "linux/kernel.h"
+ #include "linux/list.h"
+ #include "linux/slab.h"
+-#include "asm/irq.h"
++#include "linux/signal.h"
++#include "linux/interrupt.h"
+ #include "init.h"
+ #include "sigio.h"
+ #include "irq_user.h"
++#include "irq_kern.h"
+ /* Protected by sigio_lock() called from write_sigio_workaround */
+ static int sigio_irq_fd = -1;
+-void sigio_interrupt(int irq, void *data, struct pt_regs *unused)
++irqreturn_t sigio_interrupt(int irq, void *data, struct pt_regs *unused)
+ {
+       read_sigio_fd(sigio_irq_fd);
+       reactivate_fd(sigio_irq_fd, SIGIO_WRITE_IRQ);
++      return(IRQ_HANDLED);
+ }
+ int write_sigio_irq(int fd)
+--- linux-2.6.0-test6/arch/um/kernel/signal_kern.c     2003-06-14 12:18:23.000000000 -0700
++++ 25/arch/um/kernel/signal_kern.c    2003-10-05 00:34:32.000000000 -0700
+@@ -36,7 +36,7 @@ static void force_segv(int sig)
+       if(sig == SIGSEGV){
+               struct k_sigaction *ka;
+-              ka = &current->sig->action[SIGSEGV - 1];
++              ka = &current->sighand->action[SIGSEGV - 1];
+               ka->sa.sa_handler = SIG_DFL;
+       }
+       force_sig(SIGSEGV, current);
+@@ -142,7 +142,7 @@ static int kern_do_signal(struct pt_regs
+               return(0);
+       /* Whee!  Actually deliver the signal.  */
+-      ka = &current->sig->action[sig -1 ];
++      ka = &current->sighand->action[sig -1 ];
+       err = handle_signal(regs, sig, ka, &info, oldset, error);
+       if(!err) return(1);
+@@ -201,7 +201,7 @@ int sys_sigsuspend(int history0, int his
+       }
+ }
+-int sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize)
++int sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize)
+ {
+       sigset_t saveset, newset;
+@@ -227,6 +227,42 @@ int sys_rt_sigsuspend(sigset_t *unewset,
+       }
+ }
++int sys_sigaction(int sig, const struct old_sigaction __user *act,
++                       struct old_sigaction __user *oact)
++{
++      struct k_sigaction new_ka, old_ka;
++      int ret;
++
++      if (act) {
++              old_sigset_t mask;
++              if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
++                  __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
++                  __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
++                      return -EFAULT;
++              __get_user(new_ka.sa.sa_flags, &act->sa_flags);
++              __get_user(mask, &act->sa_mask);
++              siginitset(&new_ka.sa.sa_mask, mask);
++      }
++
++      ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
++
++      if (!ret && oact) {
++              if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
++                  __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
++                  __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
++                      return -EFAULT;
++              __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
++              __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
++      }
++
++      return ret;
++}
++
++int sys_sigaltstack(const stack_t *uss, stack_t *uoss)
++{
++      return(do_sigaltstack(uss, uoss, PT_REGS_SP(&current->thread.regs)));
++}
++
+ static int copy_sc_from_user(struct pt_regs *to, void *from, 
+                            struct arch_frame_data *arch)
+ {
+@@ -239,8 +275,8 @@ static int copy_sc_from_user(struct pt_r
+ int sys_sigreturn(struct pt_regs regs)
+ {
+-      void *sc = sp_to_sc(PT_REGS_SP(&current->thread.regs));
+-      void *mask = sp_to_mask(PT_REGS_SP(&current->thread.regs));
++      void __user *sc = sp_to_sc(PT_REGS_SP(&current->thread.regs));
++      void __user *mask = sp_to_mask(PT_REGS_SP(&current->thread.regs));
+       int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long);
+       spin_lock_irq(&current->sighand->siglock);
+@@ -257,7 +293,8 @@ int sys_sigreturn(struct pt_regs regs)
+ int sys_rt_sigreturn(struct pt_regs regs)
+ {
+-      struct ucontext *uc = sp_to_uc(PT_REGS_SP(&current->thread.regs));
++      unsigned long sp = PT_REGS_SP(&current->thread.regs);
++      struct ucontext __user *uc = sp_to_uc(sp);
+       void *fp;
+       int sig_size = _NSIG_WORDS * sizeof(unsigned long);
+--- linux-2.6.0-test6/arch/um/kernel/skas/include/mode.h       2003-06-14 12:18:22.000000000 -0700
++++ 25/arch/um/kernel/skas/include/mode.h      2003-10-05 00:34:32.000000000 -0700
+@@ -20,6 +20,7 @@ extern void sig_handler_common_skas(int 
+ extern void halt_skas(void);
+ extern void reboot_skas(void);
+ extern void kill_off_processes_skas(void);
++extern int is_skas_winch(int pid, int fd, void *data);
+ #endif
+--- linux-2.6.0-test6/arch/um/kernel/skas/include/uaccess.h    2003-06-14 12:18:08.000000000 -0700
++++ 25/arch/um/kernel/skas/include/uaccess.h   2003-10-05 00:34:32.000000000 -0700
+@@ -19,7 +19,7 @@
+ #define access_ok_skas(type, addr, size) \
+       ((segment_eq(get_fs(), KERNEL_DS)) || \
+        (((unsigned long) (addr) < TASK_SIZE) && \
+-        ((unsigned long) (addr) + (size) < TASK_SIZE)))
++        ((unsigned long) (addr) + (size) <= TASK_SIZE)))
+ static inline int verify_area_skas(int type, const void * addr, 
+                                  unsigned long size)
+--- linux-2.6.0-test6/arch/um/kernel/skas/Makefile     2003-06-14 12:18:06.000000000 -0700
++++ 25/arch/um/kernel/skas/Makefile    2003-10-05 00:34:32.000000000 -0700
+@@ -7,18 +7,22 @@ obj-y = exec_kern.o exec_user.o mem.o me
+       process_kern.o syscall_kern.o syscall_user.o time.o tlb.o trap_user.o \
+       sys-$(SUBARCH)/
++host-progs    := util/mk_ptregs
++clean-files   := include/skas_ptregs.h
++
+ USER_OBJS = $(filter %_user.o,$(obj-y)) process.o time.o
+ USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
+-include/skas_ptregs.h : util/mk_ptregs
+-      util/mk_ptregs > $@
+-
+-util/mk_ptregs :
+-      $(MAKE) -C util
++$(TOPDIR)/arch/um/include/skas_ptregs.h : $(src)/util/mk_ptregs
++      @echo -n '  Generating $@'
++      @$< > $@.tmp
++      @if [ -r $@ ] && cmp -s $@ $@.tmp; then \
++              echo ' (unchanged)'; \
++              rm -f $@.tmp; \
++      else \
++              echo ' (updated)'; \
++              mv -f $@.tmp $@; \
++      fi
+ $(USER_OBJS) : %.o: %.c
+       $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
+-
+-clean :
+-      $(MAKE) -C util clean
+-      $(RM) -f include/skas_ptregs.h
+--- linux-2.6.0-test6/arch/um/kernel/skas/process.c    2003-06-14 12:18:34.000000000 -0700
++++ 25/arch/um/kernel/skas/process.c   2003-10-05 00:34:32.000000000 -0700
+@@ -4,6 +4,7 @@
+  */
+ #include <stdlib.h>
++#include <unistd.h>
+ #include <errno.h>
+ #include <signal.h>
+ #include <setjmp.h>
+@@ -24,6 +25,16 @@
+ #include "os.h"
+ #include "proc_mm.h"
+ #include "skas_ptrace.h"
++#include "chan_user.h"
++
++int is_skas_winch(int pid, int fd, void *data)
++{
++      if(pid != getpid())
++              return(0);
++
++      register_winch_irq(-1, fd, -1, data);
++      return(1);
++}
+ unsigned long exec_regs[FRAME_SIZE];
+ unsigned long exec_fp_regs[HOST_FP_SIZE];
+@@ -48,11 +59,11 @@ static void handle_trap(int pid, union u
+       int err, syscall_nr, status;
+       syscall_nr = PT_SYSCALL_NR(regs->skas.regs);
++      UPT_SYSCALL_NR(regs) = syscall_nr;
+       if(syscall_nr < 1){
+               relay_signal(SIGTRAP, regs);
+               return;
+       }
+-      UPT_SYSCALL_NR(regs) = syscall_nr;
+       err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid);
+       if(err < 0)
+@@ -72,8 +83,6 @@ static void handle_trap(int pid, union u
+       handle_syscall(regs);
+ }
+-int userspace_pid;
+-
+ static int userspace_tramp(void *arg)
+ {
+       init_new_thread_signals(0);
+@@ -83,6 +92,8 @@ static int userspace_tramp(void *arg)
+       return(0);
+ }
++int userspace_pid;
++
+ void start_userspace(void)
+ {
+       void *stack;
+@@ -149,6 +160,7 @@ void userspace(union uml_pt_regs *regs)
+                       case SIGILL:
+                       case SIGBUS:
+                       case SIGFPE:
++                      case SIGWINCH:
+                               user_signal(WSTOPSIG(status), regs);
+                               break;
+                       default:
+@@ -328,7 +340,8 @@ void reboot_skas(void)
+ int new_mm(int from)
+ {
+       struct proc_mm_op copy;
+-      int n, fd = os_open_file("/proc/mm", of_write(OPENFLAGS()), 0);
++      int n, fd = os_open_file("/proc/mm", 
++                               of_cloexec(of_write(OPENFLAGS())), 0);
+       if(fd < 0)
+               return(-errno);
+@@ -342,6 +355,7 @@ int new_mm(int from)
+                       printk("new_mm : /proc/mm copy_segments failed, "
+                              "errno = %d\n", errno);
+       }
++
+       return(fd);
+ }
+--- linux-2.6.0-test6/arch/um/kernel/skas/process_kern.c       2003-08-22 19:23:40.000000000 -0700
++++ 25/arch/um/kernel/skas/process_kern.c      2003-10-05 00:34:32.000000000 -0700
+@@ -61,9 +61,8 @@ void new_thread_handler(int sig)
+       thread_wait(&current->thread.mode.skas.switch_buf, 
+                   current->thread.mode.skas.fork_buf);
+-#ifdef CONFIG_SMP
+-      schedule_tail(NULL);
+-#endif
++      if(current->thread.prev_sched != NULL)
++              schedule_tail(current->thread.prev_sched);
+       current->thread.prev_sched = NULL;
+       n = run_kernel_thread(fn, arg, &current->thread.exec_buf);
+@@ -93,9 +92,8 @@ void fork_handler(int sig)
+                   current->thread.mode.skas.fork_buf);
+       
+       force_flush_all();
+-#ifdef CONFIG_SMP
+-      schedule_tail(current->thread.prev_sched);
+-#endif
++      if(current->thread.prev_sched != NULL)
++              schedule_tail(current->thread.prev_sched);
+       current->thread.prev_sched = NULL;
+       unblock_signals();
+@@ -136,7 +134,7 @@ int copy_thread_skas(int nr, unsigned lo
+ void init_idle_skas(void)
+ {
+-      cpu_tasks[current->thread_info->cpu].pid = os_getpid();
++      cpu_tasks[current_thread->cpu].pid = os_getpid();
+       default_idle();
+ }
+@@ -164,7 +162,7 @@ int start_uml_skas(void)
+       capture_signal_stack();
+       init_new_thread_signals(1);
+-      idle_timer();
++      uml_idle_timer();
+       init_task.thread.request.u.thread.proc = start_kernel_proc;
+       init_task.thread.request.u.thread.arg = NULL;
+--- linux-2.6.0-test6/arch/um/kernel/skas/util/mk_ptregs.c     2003-06-14 12:18:08.000000000 -0700
++++ 25/arch/um/kernel/skas/util/mk_ptregs.c    2003-10-05 00:34:32.000000000 -0700
+@@ -1,3 +1,4 @@
++#include <stdio.h>
+ #include <asm/ptrace.h>
+ #include <asm/user.h>
+--- linux-2.6.0-test6/arch/um/kernel/smp.c     2003-08-22 19:23:40.000000000 -0700
++++ 25/arch/um/kernel/smp.c    2003-10-05 00:34:32.000000000 -0700
+@@ -22,7 +22,7 @@
+ #include "os.h"
+ /* CPU online map, set by smp_boot_cpus */
+-unsigned long cpu_online_map = cpumask_of_cpu(0);
++unsigned long cpu_online_map = CPU_MASK_NONE;
+ /* Per CPU bogomips and other parameters
+  * The only piece used here is the ipi pipe, which is set before SMP is
+@@ -97,15 +97,15 @@ void smp_send_stop(void)
+       printk(KERN_INFO "Stopping all CPUs...");
+       for(i = 0; i < num_online_cpus(); i++){
+-              if(i == current->thread_info->cpu)
++              if(i == current_thread->cpu)
+                       continue;
+               write(cpu_data[i].ipi_pipe[1], "S", 1);
+       }
+       printk("done\n");
+ }
+-static cpumask_t smp_commenced_mask;
+-static cpumask_t smp_callin_map = CPU_MASK_NONE;
++static cpumask_t smp_commenced_mask = CPU_MASK_NONE;
++static cpumask_t cpu_callin_map = CPU_MASK_NONE;
+ static int idle_proc(void *cpup)
+ {
+@@ -120,12 +120,12 @@ static int idle_proc(void *cpup)
+                    current->thread.mode.tt.extern_pid);
+  
+       wmb();
+-      if (cpu_test_and_set(cpu, &smp_callin_map)) {
++      if (cpu_test_and_set(cpu, cpu_callin_map)) {
+               printk("huh, CPU#%d already present??\n", cpu);
+               BUG();
+       }
+-      while (!cpu_isset(cpu, &smp_commenced_mask))
++      while (!cpu_isset(cpu, smp_commenced_mask))
+               cpu_relax();
+       cpu_set(cpu, cpu_online_map);
+@@ -140,8 +140,11 @@ static struct task_struct *idle_thread(i
+         current->thread.request.u.thread.proc = idle_proc;
+         current->thread.request.u.thread.arg = (void *) cpu;
+-      new_task = do_fork(CLONE_VM | CLONE_IDLETASK, 0, NULL, 0, NULL, NULL);
+-      if(IS_ERR(new_task)) panic("do_fork failed in idle_thread");
++      new_task = copy_process(CLONE_VM | CLONE_IDLETASK, 0, NULL, 0, NULL, 
++                              NULL);
++      if(IS_ERR(new_task)) 
++              panic("copy_process failed in idle_thread, error = %ld",
++                    PTR_ERR(new_task));
+       cpu_tasks[cpu] = ((struct cpu_task) 
+                         { .pid =      new_task->thread.mode.tt.extern_pid,
+@@ -150,6 +153,7 @@ static struct task_struct *idle_thread(i
+       CHOOSE_MODE(write(new_task->thread.mode.tt.switch_pipe[1], &c, 
+                         sizeof(c)),
+                   ({ panic("skas mode doesn't support SMP"); }));
++      wake_up_forked_process(new_task);
+       return(new_task);
+ }
+@@ -157,15 +161,16 @@ void smp_prepare_cpus(unsigned int maxcp
+ {
+       struct task_struct *idle;
+       unsigned long waittime;
+-      int err, cpu;
++      int err, cpu, me = smp_processor_id();
+-      cpu_set(0, cpu_online_map);
+-      cpu_set(0, smp_callin_map);
++      cpu_clear(me, cpu_online_map);
++      cpu_set(me, cpu_online_map);
++      cpu_set(me, cpu_callin_map);
+-      err = os_pipe(cpu_data[0].ipi_pipe, 1, 1);
++      err = os_pipe(cpu_data[me].ipi_pipe, 1, 1);
+       if(err) panic("CPU#0 failed to create IPI pipe, errno = %d", -err);
+-      activate_ipi(cpu_data[0].ipi_pipe[0], 
++      activate_ipi(cpu_data[me].ipi_pipe[0], 
+                    current->thread.mode.tt.extern_pid);
+       for(cpu = 1; cpu < ncpus; cpu++){
+@@ -177,10 +182,10 @@ void smp_prepare_cpus(unsigned int maxcp
+               unhash_process(idle);
+               waittime = 200000000;
+-              while (waittime-- && !cpu_isset(cpu, smp_callin_map))
++              while (waittime-- && !cpu_isset(cpu, cpu_callin_map))
+                       cpu_relax();
+-              if (cpu_isset(cpu, smp_callin_map))
++              if (cpu_isset(cpu, cpu_callin_map))
+                       printk("done\n");
+               else printk("failed\n");
+       }
+@@ -270,7 +275,7 @@ int smp_call_function(void (*_func)(void
+       info = _info;
+       for (i=0;i<NR_CPUS;i++)
+-              if((i != current->thread_info->cpu) && 
++              if((i != current_thread->cpu) && 
+                  cpu_isset(i, cpu_online_map))
+                       write(cpu_data[i].ipi_pipe[1], "C", 1);
+--- linux-2.6.0-test6/arch/um/kernel/syscall_kern.c    2003-06-14 12:18:28.000000000 -0700
++++ 25/arch/um/kernel/syscall_kern.c   2003-10-05 00:34:32.000000000 -0700
+@@ -35,39 +35,40 @@ long um_mount(char * dev_name, char * di
+ long sys_fork(void)
+ {
+-      struct task_struct *p;
++      long ret;
+       current->thread.forking = 1;
+-        p = do_fork(SIGCHLD, 0, NULL, 0, NULL, NULL);
++        ret = do_fork(SIGCHLD, 0, NULL, 0, NULL, NULL);
+       current->thread.forking = 0;
+-      return(IS_ERR(p) ? PTR_ERR(p) : p->pid);
++      return(ret);
+ }
+-long sys_clone(unsigned long clone_flags, unsigned long newsp)
++long sys_clone(unsigned long clone_flags, unsigned long newsp, 
++             int *parent_tid, int *child_tid)
+ {
+-      struct task_struct *p;
++      long ret;
+       current->thread.forking = 1;
+-      p = do_fork(clone_flags, newsp, NULL, 0, NULL, NULL);
++      ret = do_fork(clone_flags, newsp, NULL, 0, parent_tid, child_tid);
+       current->thread.forking = 0;
+-      return(IS_ERR(p) ? PTR_ERR(p) : p->pid);
++      return(ret);
+ }
+ long sys_vfork(void)
+ {
+-      struct task_struct *p;
++      long ret;
+       current->thread.forking = 1;
+-      p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, NULL, 0, NULL, NULL);
++      ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, NULL, 0, NULL, 
++                    NULL);
+       current->thread.forking = 0;
+-      return(IS_ERR(p) ? PTR_ERR(p) : p->pid);
++      return(ret);
+ }
+ /* common code for old and new mmaps */
+-static inline long do_mmap2(
+-      unsigned long addr, unsigned long len,
+-      unsigned long prot, unsigned long flags,
+-      unsigned long fd, unsigned long pgoff)
++long do_mmap2(struct mm_struct *mm, unsigned long addr, unsigned long len,
++            unsigned long prot, unsigned long flags, unsigned long fd,
++            unsigned long pgoff)
+ {
+       int error = -EBADF;
+       struct file * file = NULL;
+@@ -93,7 +94,7 @@ long sys_mmap2(unsigned long addr, unsig
+              unsigned long prot, unsigned long flags,
+              unsigned long fd, unsigned long pgoff)
+ {
+-      return do_mmap2(addr, len, prot, flags, fd, pgoff);
++      return do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff);
+ }
+ /*
+@@ -120,7 +121,8 @@ int old_mmap(unsigned long addr, unsigne
+       if (offset & ~PAGE_MASK)
+               goto out;
+-      err = do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
++      err = do_mmap2(current->mm, addr, len, prot, flags, fd, 
++                     offset >> PAGE_SHIFT);
+  out:
+       return err;
+ }
+@@ -141,37 +143,6 @@ int sys_pipe(unsigned long * fildes)
+         return error;
+ }
+-int sys_sigaction(int sig, const struct old_sigaction *act,
+-                       struct old_sigaction *oact)
+-{
+-      struct k_sigaction new_ka, old_ka;
+-      int ret;
+-
+-      if (act) {
+-              old_sigset_t mask;
+-              if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+-                  __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+-                  __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+-                      return -EFAULT;
+-              __get_user(new_ka.sa.sa_flags, &act->sa_flags);
+-              __get_user(mask, &act->sa_mask);
+-              siginitset(&new_ka.sa.sa_mask, mask);
+-      }
+-
+-      ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+-
+-      if (!ret && oact) {
+-              if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+-                  __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
+-                  __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+-                      return -EFAULT;
+-              __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+-              __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+-      }
+-
+-      return ret;
+-}
+-
+ /*
+  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
+  *
+@@ -253,7 +224,7 @@ int sys_ipc (uint call, int first, int s
+               return sys_shmctl (first, second,
+                                  (struct shmid_ds *) ptr);
+       default:
+-              return -EINVAL;
++              return -ENOSYS;
+       }
+ }
+@@ -302,11 +273,6 @@ int sys_olduname(struct oldold_utsname *
+       return error;
+ }
+-int sys_sigaltstack(const stack_t *uss, stack_t *uoss)
+-{
+-      return(do_sigaltstack(uss, uoss, PT_REGS_SP(&current->thread.regs)));
+-}
+-
+ long execute_syscall(void *r)
+ {
+       return(CHOOSE_MODE_PROC(execute_syscall_tt, execute_syscall_skas, r));
+--- linux-2.6.0-test6/arch/um/kernel/sys_call_table.c  2003-06-14 12:18:30.000000000 -0700
++++ 25/arch/um/kernel/sys_call_table.c 2003-10-05 00:34:32.000000000 -0700
+@@ -219,15 +219,30 @@ extern syscall_handler_t sys_getdents64;
+ extern syscall_handler_t sys_gettid;
+ extern syscall_handler_t sys_readahead;
+ extern syscall_handler_t sys_tkill;
++extern syscall_handler_t sys_setxattr;
++extern syscall_handler_t sys_lsetxattr;
++extern syscall_handler_t sys_fsetxattr;
++extern syscall_handler_t sys_getxattr;
++extern syscall_handler_t sys_lgetxattr;
++extern syscall_handler_t sys_fgetxattr;
++extern syscall_handler_t sys_listxattr;
++extern syscall_handler_t sys_llistxattr;
++extern syscall_handler_t sys_flistxattr;
++extern syscall_handler_t sys_removexattr;
++extern syscall_handler_t sys_lremovexattr;
++extern syscall_handler_t sys_fremovexattr;
+ extern syscall_handler_t sys_sendfile64;
+ extern syscall_handler_t sys_futex;
+ extern syscall_handler_t sys_sched_setaffinity;
+ extern syscall_handler_t sys_sched_getaffinity;
++extern syscall_handler_t sys_set_thread_area;
++extern syscall_handler_t sys_get_thread_area;
+ extern syscall_handler_t sys_io_setup;
+ extern syscall_handler_t sys_io_destroy;
+ extern syscall_handler_t sys_io_getevents;
+ extern syscall_handler_t sys_io_submit;
+ extern syscall_handler_t sys_io_cancel;
++extern syscall_handler_t sys_fadvise64;
+ extern syscall_handler_t sys_exit_group;
+ extern syscall_handler_t sys_lookup_dcookie;
+ extern syscall_handler_t sys_epoll_create;
+@@ -235,6 +250,20 @@ extern syscall_handler_t sys_epoll_ctl;
+ extern syscall_handler_t sys_epoll_wait;
+ extern syscall_handler_t sys_remap_file_pages;
+ extern syscall_handler_t sys_set_tid_address;
++extern syscall_handler_t sys_timer_create;
++extern syscall_handler_t sys_timer_settime;
++extern syscall_handler_t sys_timer_gettime;
++extern syscall_handler_t sys_timer_getoverrun;
++extern syscall_handler_t sys_timer_delete;
++extern syscall_handler_t sys_clock_settime;
++extern syscall_handler_t sys_clock_gettime;
++extern syscall_handler_t sys_clock_getres;
++extern syscall_handler_t sys_clock_nanosleep;
++extern syscall_handler_t sys_statfs64;
++extern syscall_handler_t sys_fstatfs64;
++extern syscall_handler_t sys_tgkill;
++extern syscall_handler_t sys_utimes;
++extern syscall_handler_t sys_fadvise64_64;
+ #ifdef CONFIG_NFSD
+ #define NFSSERVCTL sys_nfsservctl
+@@ -246,7 +275,7 @@ extern syscall_handler_t um_mount;
+ extern syscall_handler_t um_time;
+ extern syscall_handler_t um_stime;
+-#define LAST_GENERIC_SYSCALL __NR_set_tid_address
++#define LAST_GENERIC_SYSCALL __NR_fadvise64_64
+ #if LAST_GENERIC_SYSCALL > LAST_ARCH_SYSCALL
+ #define LAST_SYSCALL LAST_GENERIC_SYSCALL
+@@ -455,32 +484,37 @@ syscall_handler_t *sys_call_table[] = {
+       [ __NR_stat64 ] = sys_stat64,
+       [ __NR_lstat64 ] = sys_lstat64,
+       [ __NR_fstat64 ] = sys_fstat64,
+-      [ __NR_fcntl64 ] = sys_fcntl64,
+       [ __NR_getdents64 ] = sys_getdents64,
++      [ __NR_fcntl64 ] = sys_fcntl64,
++      [ 223 ] = sys_ni_syscall,
+       [ __NR_gettid ] = sys_gettid,
+       [ __NR_readahead ] = sys_readahead,
+-      [ __NR_setxattr ] = sys_ni_syscall,
+-      [ __NR_lsetxattr ] = sys_ni_syscall,
+-      [ __NR_fsetxattr ] = sys_ni_syscall,
+-      [ __NR_getxattr ] = sys_ni_syscall,
+-      [ __NR_lgetxattr ] = sys_ni_syscall,
+-      [ __NR_fgetxattr ] = sys_ni_syscall,
+-      [ __NR_listxattr ] = sys_ni_syscall,
+-      [ __NR_llistxattr ] = sys_ni_syscall,
+-      [ __NR_flistxattr ] = sys_ni_syscall,
+-      [ __NR_removexattr ] = sys_ni_syscall,
+-      [ __NR_lremovexattr ] = sys_ni_syscall,
+-      [ __NR_fremovexattr ] = sys_ni_syscall,
++      [ __NR_setxattr ] = sys_setxattr,
++      [ __NR_lsetxattr ] = sys_lsetxattr,
++      [ __NR_fsetxattr ] = sys_fsetxattr,
++      [ __NR_getxattr ] = sys_getxattr,
++      [ __NR_lgetxattr ] = sys_lgetxattr,
++      [ __NR_fgetxattr ] = sys_fgetxattr,
++      [ __NR_listxattr ] = sys_listxattr,
++      [ __NR_llistxattr ] = sys_llistxattr,
++      [ __NR_flistxattr ] = sys_flistxattr,
++      [ __NR_removexattr ] = sys_removexattr,
++      [ __NR_lremovexattr ] = sys_lremovexattr,
++      [ __NR_fremovexattr ] = sys_fremovexattr,
+       [ __NR_tkill ] = sys_tkill,
+       [ __NR_sendfile64 ] = sys_sendfile64,
+       [ __NR_futex ] = sys_futex,
+       [ __NR_sched_setaffinity ] = sys_sched_setaffinity,
+       [ __NR_sched_getaffinity ] = sys_sched_getaffinity,
++      [ __NR_set_thread_area ] = sys_ni_syscall,
++      [ __NR_get_thread_area ] = sys_ni_syscall,
+       [ __NR_io_setup ] = sys_io_setup,
+       [ __NR_io_destroy ] = sys_io_destroy,
+       [ __NR_io_getevents ] = sys_io_getevents,
+       [ __NR_io_submit ] = sys_io_submit,
+       [ __NR_io_cancel ] = sys_io_cancel,
++      [ __NR_fadvise64 ] = sys_fadvise64,
++      [ 251 ] = sys_ni_syscall,
+       [ __NR_exit_group ] = sys_exit_group,
+       [ __NR_lookup_dcookie ] = sys_lookup_dcookie,
+       [ __NR_epoll_create ] = sys_epoll_create,
+@@ -488,6 +522,20 @@ syscall_handler_t *sys_call_table[] = {
+       [ __NR_epoll_wait ] = sys_epoll_wait,
+         [ __NR_remap_file_pages ] = sys_remap_file_pages,
+         [ __NR_set_tid_address ] = sys_set_tid_address,
++      [ __NR_timer_create ] = sys_timer_create,
++      [ __NR_timer_settime ] = sys_timer_settime,
++      [ __NR_timer_gettime ] = sys_timer_gettime,
++      [ __NR_timer_getoverrun ] = sys_timer_getoverrun,
++      [ __NR_timer_delete ] = sys_timer_delete,
++      [ __NR_clock_settime ] = sys_clock_settime,
++      [ __NR_clock_gettime ] = sys_clock_gettime,
++      [ __NR_clock_getres ] = sys_clock_getres,
++      [ __NR_clock_nanosleep ] = sys_clock_nanosleep,
++      [ __NR_statfs64 ] = sys_statfs64,
++      [ __NR_fstatfs64 ] = sys_fstatfs64,
++      [ __NR_tgkill ] = sys_tgkill,
++      [ __NR_utimes ] = sys_utimes,
++      [ __NR_fadvise64_64 ] = sys_fadvise64_64,
+       ARCH_SYSCALLS
+       [ LAST_SYSCALL + 1 ... NR_syscalls ] = 
+--- linux-2.6.0-test6/arch/um/kernel/sysrq.c   2003-06-14 12:18:07.000000000 -0700
++++ 25/arch/um/kernel/sysrq.c  2003-10-05 00:34:32.000000000 -0700
+@@ -53,6 +53,14 @@ void show_trace_task(struct task_struct 
+       show_trace((unsigned long *)esp);
+ }
++void show_stack(struct task_struct *task, unsigned long *sp)
++{
++      if(task)
++              show_trace_task(task);
++      else
++              show_trace(sp);
++}
++
+ /*
+  * Overrides for Emacs so that we follow Linus's tabbing style.
+  * Emacs will notice this stuff at the end of the file and automatically
+--- linux-2.6.0-test6/arch/um/kernel/time.c    2003-06-16 22:32:20.000000000 -0700
++++ 25/arch/um/kernel/time.c   2003-10-05 00:34:32.000000000 -0700
+@@ -15,12 +15,16 @@
+ #include "process.h"
+ #include "signal_user.h"
+ #include "time_user.h"
++#include "kern_constants.h"
+ extern struct timeval xtime;
++struct timeval local_offset = { 0, 0 };
++
+ void timer(void)
+ {
+       gettimeofday(&xtime, NULL);
++      timeradd(&xtime, &local_offset, &xtime);
+ }
+ void set_interval(int timer_type)
+@@ -65,7 +69,7 @@ void switch_timers(int to_real)
+                      errno);
+ }
+-void idle_timer(void)
++void uml_idle_timer(void)
+ {
+       if(signal(SIGVTALRM, SIG_IGN) == SIG_ERR)
+               panic("Couldn't unset SIGVTALRM handler");
+@@ -82,8 +86,6 @@ void time_init(void)
+       set_interval(ITIMER_VIRTUAL);
+ }
+-struct timeval local_offset = { 0, 0 };
+-
+ void do_gettimeofday(struct timeval *tv)
+ {
+       unsigned long flags;
+@@ -100,7 +102,7 @@ int do_settimeofday(struct timespec *tv)
+       unsigned long flags;
+       struct timeval tv_in;
+-      if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
++      if ((unsigned long) tv->tv_nsec >= UM_NSEC_PER_SEC)
+               return -EINVAL;
+       tv_in.tv_sec = tv->tv_sec;
+@@ -110,6 +112,8 @@ int do_settimeofday(struct timespec *tv)
+       gettimeofday(&now, NULL);
+       timersub(&tv_in, &now, &local_offset);
+       time_unlock(flags);
++
++      return(0);
+ }
+ void idle_sleep(int secs)
+--- linux-2.6.0-test6/arch/um/kernel/time_kern.c       2003-06-14 12:18:24.000000000 -0700
++++ 25/arch/um/kernel/time_kern.c      2003-10-05 00:34:32.000000000 -0700
+@@ -38,7 +38,7 @@ int __attribute__ ((__section__ (".unpro
+ void timer_irq(union uml_pt_regs *regs)
+ {
+-      int cpu = current->thread_info->cpu, ticks = missed_ticks[cpu];
++      int cpu = current_thread->cpu, ticks = missed_ticks[cpu];
+         if(!timer_irq_inited) return;
+       missed_ticks[cpu] = 0;
+@@ -55,12 +55,13 @@ void boot_timer_handler(int sig)
+       do_timer(&regs);
+ }
+-void um_timer(int irq, void *dev, struct pt_regs *regs)
++irqreturn_t um_timer(int irq, void *dev, struct pt_regs *regs)
+ {
+       do_timer(regs);
+-      write_seqlock(&xtime_lock);
++      write_seqlock_irq(&xtime_lock);
+       timer();
+-      write_sequnlock(&xtime_lock);
++      write_sequnlock_irq(&xtime_lock);
++      return(IRQ_HANDLED);
+ }
+ long um_time(int * tloc)
+@@ -78,12 +79,12 @@ long um_time(int * tloc)
+ long um_stime(int * tptr)
+ {
+       int value;
+-      struct timeval new;
++      struct timespec new;
+       if (get_user(value, tptr))
+                 return -EFAULT;
+       new.tv_sec = value;
+-      new.tv_usec = 0;
++      new.tv_nsec = 0;
+       do_settimeofday(&new);
+       return 0;
+ }
+@@ -122,9 +123,11 @@ void __const_udelay(um_udelay_t usecs)
+ void timer_handler(int sig, union uml_pt_regs *regs)
+ {
+ #ifdef CONFIG_SMP
++      local_irq_disable();
+       update_process_times(user_context(UPT_SP(regs)));
++      local_irq_enable();
+ #endif
+-      if(current->thread_info->cpu == 0)
++      if(current_thread->cpu == 0)
+               timer_irq(regs);
+ }
+--- linux-2.6.0-test6/arch/um/kernel/trap_kern.c       2003-06-14 12:17:57.000000000 -0700
++++ 25/arch/um/kernel/trap_kern.c      2003-10-05 00:34:32.000000000 -0700
+@@ -16,6 +16,7 @@
+ #include "asm/tlbflush.h"
+ #include "asm/a.out.h"
+ #include "asm/current.h"
++#include "asm/irq.h"
+ #include "user_util.h"
+ #include "kern_util.h"
+ #include "kern.h"
+@@ -51,7 +52,7 @@ int handle_page_fault(unsigned long addr
+       if(is_write && !(vma->vm_flags & VM_WRITE)) 
+               goto out;
+       page = address & PAGE_MASK;
+-      if(page == (unsigned long) current->thread_info + PAGE_SIZE)
++      if(page == (unsigned long) current_thread + PAGE_SIZE)
+               panic("Kernel stack overflow");
+       pgd = pgd_offset(mm, page);
+       pmd = pmd_offset(pgd, page);
+@@ -180,6 +181,11 @@ void bus_handler(int sig, union uml_pt_r
+       else relay_signal(sig, regs);
+ }
++void winch(int sig, union uml_pt_regs *regs)
++{
++      do_IRQ(WINCH_IRQ, regs);
++}
++
+ void trap_init(void)
+ {
+ }
+--- linux-2.6.0-test6/arch/um/kernel/trap_user.c       2003-06-14 12:18:09.000000000 -0700
++++ 25/arch/um/kernel/trap_user.c      2003-10-05 00:34:32.000000000 -0700
+@@ -82,6 +82,8 @@ struct signal_info sig_info[] = {
+                    .is_irq            = 0 },
+       [ SIGILL ] { .handler           = relay_signal,
+                    .is_irq            = 0 },
++      [ SIGWINCH ] { .handler         = winch,
++                     .is_irq          = 1 },
+       [ SIGBUS ] { .handler           = bus_handler,
+                    .is_irq            = 0 },
+       [ SIGSEGV] { .handler           = segv_handler,
+--- linux-2.6.0-test6/arch/um/kernel/tt/exec_kern.c    2003-06-14 12:17:59.000000000 -0700
++++ 25/arch/um/kernel/tt/exec_kern.c   2003-10-05 00:34:32.000000000 -0700
+@@ -47,17 +47,17 @@ void flush_thread_tt(void)
+               do_exit(SIGKILL);
+       }
+-      if(current->thread_info->cpu == 0)
++      if(current_thread->cpu == 0)
+               forward_interrupts(new_pid);
+       current->thread.request.op = OP_EXEC;
+       current->thread.request.u.exec.pid = new_pid;
+-      unprotect_stack((unsigned long) current->thread_info);
++      unprotect_stack((unsigned long) current_thread);
+       os_usr1_process(os_getpid());
+       enable_timer();
+       free_page(stack);
+       protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1);
+-      task_protections((unsigned long) current->thread_info);
++      task_protections((unsigned long) current_thread);
+       force_flush_all();
+       unblock_signals();
+ }
+--- linux-2.6.0-test6/arch/um/kernel/tt/include/uaccess.h      2003-06-14 12:18:24.000000000 -0700
++++ 25/arch/um/kernel/tt/include/uaccess.h     2003-10-05 00:34:32.000000000 -0700
+@@ -46,18 +46,20 @@ extern int __do_copy_from_user(void *to,
+ static inline int copy_from_user_tt(void *to, const void *from, int n)
+ {
+-      return(access_ok_tt(VERIFY_READ, from, n) ?
+-             __do_copy_from_user(to, from, n, 
+-                                 &current->thread.fault_addr,
+-                                 &current->thread.fault_catcher) : n);
++      if(!access_ok_tt(VERIFY_READ, from, n)) 
++              return(n);
++
++      return(__do_copy_from_user(to, from, n, &current->thread.fault_addr,
++                                 &current->thread.fault_catcher));
+ }
+ static inline int copy_to_user_tt(void *to, const void *from, int n)
+ {
+-      return(access_ok_tt(VERIFY_WRITE, to, n) ?
+-             __do_copy_to_user(to, from, n, 
+-                                 &current->thread.fault_addr,
+-                                 &current->thread.fault_catcher) : n);
++      if(!access_ok_tt(VERIFY_WRITE, to, n))
++              return(n);
++              
++      return(__do_copy_to_user(to, from, n, &current->thread.fault_addr,
++                               &current->thread.fault_catcher));
+ }
+ extern int __do_strncpy_from_user(char *dst, const char *src, size_t n,
+@@ -67,7 +69,9 @@ static inline int strncpy_from_user_tt(c
+ {
+       int n;
+-      if(!access_ok_tt(VERIFY_READ, src, 1)) return(-EFAULT);
++      if(!access_ok_tt(VERIFY_READ, src, 1)) 
++              return(-EFAULT);
++
+       n = __do_strncpy_from_user(dst, src, count, 
+                                  &current->thread.fault_addr,
+                                  &current->thread.fault_catcher);
+@@ -87,10 +91,11 @@ static inline int __clear_user_tt(void *
+ static inline int clear_user_tt(void *mem, int len)
+ {
+-      return(access_ok_tt(VERIFY_WRITE, mem, len) ? 
+-             __do_clear_user(mem, len, 
+-                             &current->thread.fault_addr,
+-                             &current->thread.fault_catcher) : len);
++      if(!access_ok_tt(VERIFY_WRITE, mem, len))
++              return(len);
++
++      return(__do_clear_user(mem, len, &current->thread.fault_addr,
++                             &current->thread.fault_catcher));
+ }
+ extern int __do_strnlen_user(const char *str, unsigned long n,
+--- linux-2.6.0-test6/arch/um/kernel/tt/process_kern.c 2003-08-22 19:23:40.000000000 -0700
++++ 25/arch/um/kernel/tt/process_kern.c        2003-10-05 00:34:32.000000000 -0700
+@@ -104,7 +104,10 @@ void *switch_to_tt(void *prev, void *nex
+ void release_thread_tt(struct task_struct *task)
+ {
+-      os_kill_process(task->thread.mode.tt.extern_pid, 0);
++      int pid = task->thread.mode.tt.extern_pid;
++
++      if(os_getpid() != pid)
++              os_kill_process(pid, 0);
+ }
+ void exit_thread_tt(void)
+@@ -125,27 +128,27 @@ static void new_thread_handler(int sig)
+       UPT_SC(&current->thread.regs.regs) = (void *) (&sig + 1);
+       suspend_new_thread(current->thread.mode.tt.switch_pipe[0]);
+-      block_signals();
++      force_flush_all();
++      if(current->thread.prev_sched != NULL)
++              schedule_tail(current->thread.prev_sched);
++      current->thread.prev_sched = NULL;
++
+       init_new_thread_signals(1);
+-#ifdef CONFIG_SMP
+-      schedule_tail(current->thread.prev_sched);
+-#endif
+       enable_timer();
+       free_page(current->thread.temp_stack);
+       set_cmdline("(kernel thread)");
+-      force_flush_all();
+-      current->thread.prev_sched = NULL;
+       change_sig(SIGUSR1, 1);
+       change_sig(SIGVTALRM, 1);
+       change_sig(SIGPROF, 1);
+-      unblock_signals();
++      local_irq_enable();
+       if(!run_kernel_thread(fn, arg, &current->thread.exec_buf))
+               do_exit(0);
+ }
+ static int new_thread_proc(void *stack)
+ {
++      local_irq_disable();
+       init_new_thread_stack(stack, new_thread_handler);
+       os_usr1_process(os_getpid());
+       return(0);
+@@ -165,35 +168,32 @@ void finish_fork_handler(int sig)
+       UPT_SC(&current->thread.regs.regs) = (void *) (&sig + 1);
+       suspend_new_thread(current->thread.mode.tt.switch_pipe[0]);
+-#ifdef CONFIG_SMP     
+-      schedule_tail(NULL);
+-#endif
++      force_flush_all();
++      if(current->thread.prev_sched != NULL)
++              schedule_tail(current->thread.prev_sched);
++      current->thread.prev_sched = NULL;
++
+       enable_timer();
+       change_sig(SIGVTALRM, 1);
+       local_irq_enable();
+-      force_flush_all();
+       if(current->mm != current->parent->mm)
+               protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 
+                              1, 0, 1);
+-      task_protections((unsigned long) current->thread_info);
+-
+-      current->thread.prev_sched = NULL;
++      task_protections((unsigned long) current_thread);
+       free_page(current->thread.temp_stack);
++      local_irq_disable();
+       change_sig(SIGUSR1, 0);
+       set_user_mode(current);
+ }
+-static int sigusr1 = SIGUSR1;
+-
+ int fork_tramp(void *stack)
+ {
+-      int sig = sigusr1;
+-
+       local_irq_disable();
++      arch_init_thread();
+       init_new_thread_stack(stack, finish_fork_handler);
+-      kill(os_getpid(), sig);
++      os_usr1_process(os_getpid());
+       return(0);
+ }
+@@ -377,8 +377,8 @@ static void mprotect_kernel_mem(int w)
+       pages = (1 << CONFIG_KERNEL_STACK_ORDER);
+-      start = (unsigned long) current->thread_info + PAGE_SIZE;
+-      end = (unsigned long) current + PAGE_SIZE * pages;
++      start = (unsigned long) current_thread + PAGE_SIZE;
++      end = (unsigned long) current_thread + PAGE_SIZE * pages;
+       protect_memory(uml_reserved, start - uml_reserved, 1, w, 1, 1);
+       protect_memory(end, high_physmem - end, 1, w, 1, 1);
+--- linux-2.6.0-test6/arch/um/kernel/tt/ptproxy/proxy.c        2003-06-14 12:18:23.000000000 -0700
++++ 25/arch/um/kernel/tt/ptproxy/proxy.c       2003-10-05 00:34:32.000000000 -0700
+@@ -293,10 +293,10 @@ void fake_child_exit(void)
+ }
+ char gdb_init_string[] = 
+-"att 1
+-b panic
+-b stop
+-handle SIGWINCH nostop noprint pass
++"att 1 \n\
++b panic \n\
++b stop \n\
++handle SIGWINCH nostop noprint pass \n\
+ ";
+ int start_debugger(char *prog, int startup, int stop, int *fd_out)
+--- linux-2.6.0-test6/arch/um/kernel/tt/tracer.c       2003-06-14 12:17:56.000000000 -0700
++++ 25/arch/um/kernel/tt/tracer.c      2003-10-05 00:34:32.000000000 -0700
+@@ -39,7 +39,7 @@ int is_tracer_winch(int pid, int fd, voi
+               return(0);
+       register_winch_irq(tracer_winch[0], fd, -1, data);
+-      return(0);
++      return(1);
+ }
+ static void tracer_winch_handler(int sig)
+@@ -401,7 +401,7 @@ static int __init uml_debug_setup(char *
+               
+               if(!strcmp(line, "go")) debug_stop = 0;
+               else if(!strcmp(line, "parent")) debug_parent = 1;
+-              else printk("Unknown debug option : '%s'\n", line);
++              else printf("Unknown debug option : '%s'\n", line);
+               line = next;
+       }
+--- linux-2.6.0-test6/arch/um/kernel/tt/uaccess_user.c 2003-06-14 12:18:06.000000000 -0700
++++ 25/arch/um/kernel/tt/uaccess_user.c        2003-10-05 00:34:32.000000000 -0700
+@@ -8,15 +8,20 @@
+ #include <string.h>
+ #include "user_util.h"
+ #include "uml_uaccess.h"
++#include "task.h"
++#include "kern_util.h"
+ int __do_copy_from_user(void *to, const void *from, int n,
+                       void **fault_addr, void **fault_catcher)
+ {
++      struct tt_regs save = TASK_REGS(get_current())->tt;
+       unsigned long fault;
+       int faulted;
+       fault = __do_user_copy(to, from, n, fault_addr, fault_catcher,
+                              __do_copy, &faulted);
++      TASK_REGS(get_current())->tt = save;
++
+       if(!faulted) return(0);
+       else return(n - (fault - (unsigned long) from));
+ }
+@@ -29,11 +34,14 @@ static void __do_strncpy(void *dst, cons
+ int __do_strncpy_from_user(char *dst, const char *src, unsigned long count,
+                          void **fault_addr, void **fault_catcher)
+ {
++      struct tt_regs save = TASK_REGS(get_current())->tt;
+       unsigned long fault;
+       int faulted;
+       fault = __do_user_copy(dst, src, count, fault_addr, fault_catcher,
+                              __do_strncpy, &faulted);
++      TASK_REGS(get_current())->tt = save;
++
+       if(!faulted) return(strlen(dst));
+       else return(-1);
+ }
+@@ -46,11 +54,14 @@ static void __do_clear(void *to, const v
+ int __do_clear_user(void *mem, unsigned long len,
+                   void **fault_addr, void **fault_catcher)
+ {
++      struct tt_regs save = TASK_REGS(get_current())->tt;
+       unsigned long fault;
+       int faulted;
+       fault = __do_user_copy(mem, NULL, len, fault_addr, fault_catcher,
+                              __do_clear, &faulted);
++      TASK_REGS(get_current())->tt = save;
++
+       if(!faulted) return(0);
+       else return(len - (fault - (unsigned long) mem));
+ }
+@@ -58,6 +69,7 @@ int __do_clear_user(void *mem, unsigned 
+ int __do_strnlen_user(const char *str, unsigned long n,
+                     void **fault_addr, void **fault_catcher)
+ {
++      struct tt_regs save = TASK_REGS(get_current())->tt;
+       int ret;
+       unsigned long *faddrp = (unsigned long *)fault_addr;
+       jmp_buf jbuf;
+@@ -71,6 +83,8 @@ int __do_strnlen_user(const char *str, u
+       }
+       *fault_addr = NULL;
+       *fault_catcher = NULL;
++
++      TASK_REGS(get_current())->tt = save;
+       return ret;
+ }
+--- linux-2.6.0-test6/arch/um/kernel/um_arch.c 2003-08-22 19:23:40.000000000 -0700
++++ 25/arch/um/kernel/um_arch.c        2003-10-05 00:34:32.000000000 -0700
+@@ -38,13 +38,18 @@
+ #include "mode_kern.h"
+ #include "mode.h"
+-#define DEFAULT_COMMAND_LINE "root=6200"
++#define DEFAULT_COMMAND_LINE "root=ubd0"
+ struct cpuinfo_um boot_cpu_data = { 
+       .loops_per_jiffy        = 0,
+       .ipi_pipe               = { -1, -1 }
+ };
++/* Placeholder to make UML link until the vsyscall stuff is actually 
++ * implemented
++ */
++void *__kernel_vsyscall;
++
+ unsigned long thread_saved_pc(struct task_struct *task)
+ {
+       return(os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas,
+@@ -61,10 +66,14 @@ static int show_cpuinfo(struct seq_file 
+               return 0;
+ #endif
+-      seq_printf(m, "bogomips\t: %lu.%02lu\n",
++      seq_printf(m, "processor\t: %d\n", index);
++      seq_printf(m, "vendor_id\t: User Mode Linux\n");
++      seq_printf(m, "model name\t: UML\n");
++      seq_printf(m, "mode\t\t: %s\n", CHOOSE_MODE("tt", "skas"));
++      seq_printf(m, "host\t\t: %s\n", host_info);
++      seq_printf(m, "bogomips\t: %lu.%02lu\n\n",
+                  loops_per_jiffy/(500000/HZ),
+                  (loops_per_jiffy/(5000/HZ)) % 100);
+-      seq_printf(m, "host\t\t: %s\n", host_info);
+       return(0);
+ }
+@@ -134,12 +143,12 @@ void set_cmdline(char *cmd)
+       if(umid != NULL){
+               snprintf(argv1_begin, 
+                        (argv1_end - argv1_begin) * sizeof(*ptr), 
+-                       "(%s)", umid);
++                       "(%s) ", umid);
+               ptr = &argv1_begin[strlen(argv1_begin)];
+       }
+       else ptr = argv1_begin;
+-      snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), " [%s]", cmd);
++      snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), "[%s]", cmd);
+       memset(argv1_begin + strlen(argv1_begin), '\0', 
+              argv1_end - argv1_begin - strlen(argv1_begin));
+ #endif
+@@ -179,7 +188,7 @@ __uml_setup("root=", uml_root_setup,
+ static int __init uml_ncpus_setup(char *line, int *add)
+ {
+        if (!sscanf(line, "%d", &ncpus)) {
+-               printk("Couldn't parse [%s]\n", line);
++               printf("Couldn't parse [%s]\n", line);
+                return -1;
+        }
+@@ -210,7 +219,7 @@ static int __init mode_tt_setup(char *li
+ static int __init mode_tt_setup(char *line, int *add)
+ {
+-      printk("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n");
++      printf("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n");
+       return(0);
+ }
+@@ -221,7 +230,7 @@ static int __init mode_tt_setup(char *li
+ static int __init mode_tt_setup(char *line, int *add)
+ {
+-      printk("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n");
++      printf("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n");
+       return(0);
+ }
+@@ -369,6 +378,7 @@ int linux_main(int argc, char **argv)
+               2 * PAGE_SIZE;
+       task_protections((unsigned long) &init_thread_info);
++      os_flush_stdout();
+       return(CHOOSE_MODE(start_uml_tt(), start_uml_skas()));
+ }
+--- linux-2.6.0-test6/arch/um/kernel/umid.c    2003-06-14 12:18:34.000000000 -0700
++++ 25/arch/um/kernel/umid.c   2003-10-05 00:34:32.000000000 -0700
+@@ -33,18 +33,19 @@ static char *uml_dir = UML_DIR;
+ static int umid_is_random = 1;
+ static int umid_inited = 0;
+-static int make_umid(void);
++static int make_umid(int (*printer)(const char *fmt, ...));
+-static int __init set_umid(char *name, int is_random)
++static int __init set_umid(char *name, int is_random, 
++                         int (*printer)(const char *fmt, ...))
+ {
+       if(umid_inited){
+-              printk("Unique machine name can't be set twice\n");
++              (*printer)("Unique machine name can't be set twice\n");
+               return(-1);
+       }
+       if(strlen(name) > UMID_LEN - 1)
+-              printk("Unique machine name is being truncated to %s "
+-                     "characters\n", UMID_LEN);
++              (*printer)("Unique machine name is being truncated to %s "
++                         "characters\n", UMID_LEN);
+       strlcpy(umid, name, sizeof(umid));
+       umid_is_random = is_random;
+@@ -54,7 +55,7 @@ static int __init set_umid(char *name, i
+ static int __init set_umid_arg(char *name, int *add)
+ {
+-      return(set_umid(name, 0));
++      return(set_umid(name, 0, printf));
+ }
+ __uml_setup("umid=", set_umid_arg,
+@@ -67,7 +68,7 @@ int __init umid_file_name(char *name, ch
+ {
+       int n;
+-      if(!umid_inited && make_umid()) return(-1);
++      if(!umid_inited && make_umid(printk)) return(-1);
+       n = strlen(uml_dir) + strlen(umid) + strlen(name) + 1;
+       if(n > len){
+@@ -92,14 +93,14 @@ static int __init create_pid_file(void)
+       fd = os_open_file(file, of_create(of_excl(of_rdwr(OPENFLAGS()))), 
+                         0644);
+       if(fd < 0){
+-              printk("Open of machine pid file \"%s\" failed - "
++              printf("Open of machine pid file \"%s\" failed - "
+                      "errno = %d\n", file, -fd);
+               return 0;
+       }
+       sprintf(pid, "%d\n", os_getpid());
+       if(write(fd, pid, strlen(pid)) != strlen(pid))
+-              printk("Write of pid file failed - errno = %d\n", errno);
++              printf("Write of pid file failed - errno = %d\n", errno);
+       close(fd);
+       return 0;
+ }
+@@ -197,7 +198,7 @@ static int __init set_uml_dir(char *name
+       if((strlen(name) > 0) && (name[strlen(name) - 1] != '/')){
+               uml_dir = malloc(strlen(name) + 1);
+               if(uml_dir == NULL){
+-                      printk("Failed to malloc uml_dir - error = %d\n",
++                      printf("Failed to malloc uml_dir - error = %d\n",
+                              errno);
+                       uml_dir = name;
+                       return(0);
+@@ -217,7 +218,7 @@ static int __init make_uml_dir(void)
+               char *home = getenv("HOME");
+               if(home == NULL){
+-                      printk("make_uml_dir : no value in environment for "
++                      printf("make_uml_dir : no value in environment for "
+                              "$HOME\n");
+                       exit(1);
+               }
+@@ -239,25 +240,25 @@ static int __init make_uml_dir(void)
+       strcpy(uml_dir, dir);
+       
+       if((mkdir(uml_dir, 0777) < 0) && (errno != EEXIST)){
+-              printk("Failed to mkdir %s - errno = %i\n", uml_dir, errno);
++              printf("Failed to mkdir %s - errno = %i\n", uml_dir, errno);
+               return(-1);
+       }
+       return 0;
+ }
+-static int __init make_umid(void)
++static int __init make_umid(int (*printer)(const char *fmt, ...))
+ {
+       int fd, err;
+       char tmp[strlen(uml_dir) + UMID_LEN + 1];
+       strlcpy(tmp, uml_dir, sizeof(tmp));
+-      if(*umid == 0){
++      if(!umid_inited){
+               strcat(tmp, "XXXXXX");
+               fd = mkstemp(tmp);
+               if(fd < 0){
+-                      printk("make_umid - mkstemp failed, errno = %d\n",
+-                             errno);
++                      (*printer)("make_umid - mkstemp failed, errno = %d\n",
++                                 errno);
+                       return(1);
+               }
+@@ -267,7 +268,7 @@ static int __init make_umid(void)
+                * for directories.
+                */
+               unlink(tmp);
+-              set_umid(&tmp[strlen(uml_dir)], 1);
++              set_umid(&tmp[strlen(uml_dir)], 1, printer);
+       }
+       
+       sprintf(tmp, "%s%s", uml_dir, umid);
+@@ -275,14 +276,14 @@ static int __init make_umid(void)
+       if((err = mkdir(tmp, 0777)) < 0){
+               if(errno == EEXIST){
+                       if(not_dead_yet(tmp)){
+-                              printk("umid '%s' is in use\n", umid);
++                              (*printer)("umid '%s' is in use\n", umid);
+                               return(-1);
+                       }
+                       err = mkdir(tmp, 0777);
+               }
+       }
+       if(err < 0){
+-              printk("Failed to create %s - errno = %d\n", umid, errno);
++              (*printer)("Failed to create %s - errno = %d\n", umid, errno);
+               return(-1);
+       }
+@@ -295,7 +296,13 @@ __uml_setup("uml_dir=", set_uml_dir,
+ );
+ __uml_postsetup(make_uml_dir);
+-__uml_postsetup(make_umid);
++
++static int __init make_umid_setup(void)
++{
++      return(make_umid(printf));
++}
++
++__uml_postsetup(make_umid_setup);
+ __uml_postsetup(create_pid_file);
+ /*
+--- linux-2.6.0-test6/arch/um/kernel/user_util.c       2003-06-14 12:17:59.000000000 -0700
++++ 25/arch/um/kernel/user_util.c      2003-10-05 00:34:32.000000000 -0700
+@@ -119,17 +119,6 @@ int wait_for_stop(int pid, int sig, int 
+       }
+ }
+-int clone_and_wait(int (*fn)(void *), void *arg, void *sp, int flags)
+-{
+-      int pid;
+-
+-      pid = clone(fn, sp, flags, arg);
+-      if(pid < 0) return(-1);
+-      wait_for_stop(pid, SIGSTOP, PTRACE_CONT, NULL);
+-      ptrace(PTRACE_CONT, pid, 0, 0);
+-      return(pid);
+-}
+-
+ int raw(int fd, int complain)
+ {
+       struct termios tt;
+--- linux-2.6.0-test6/arch/um/Makefile 2003-08-08 22:55:11.000000000 -0700
++++ 25/arch/um/Makefile        2003-10-05 00:34:32.000000000 -0700
+@@ -24,15 +24,17 @@ core-y                     += $(ARCH_DIR)/kernel/           \
+ # Have to precede the include because the included Makefiles reference them.
+ SYMLINK_HEADERS = include/asm-um/archparam.h include/asm-um/system.h \
+       include/asm-um/sigcontext.h include/asm-um/processor.h \
+-      include/asm-um/ptrace.h include/asm-um/arch-signal.h
++      include/asm-um/ptrace.h include/asm-um/arch-signal.h \
++      include/asm-um/module.h
+ ARCH_SYMLINKS = include/asm-um/arch $(ARCH_DIR)/include/sysdep $(ARCH_DIR)/os \
+       $(SYMLINK_HEADERS) $(ARCH_DIR)/include/uml-config.h
+ GEN_HEADERS += $(ARCH_DIR)/include/task.h $(ARCH_DIR)/include/kern_constants.h
+-include $(ARCH_DIR)/Makefile-$(SUBARCH)
+-include $(ARCH_DIR)/Makefile-os-$(OS)
++.PHONY: sys_prepare
++sys_prepare:
++      @:
+ MAKEFILE-$(CONFIG_MODE_TT) += Makefile-tt
+ MAKEFILE-$(CONFIG_MODE_SKAS) += Makefile-skas
+@@ -41,6 +43,9 @@ ifneq ($(MAKEFILE-y),)
+   include $(addprefix $(ARCH_DIR)/,$(MAKEFILE-y))
+ endif
++include $(ARCH_DIR)/Makefile-$(SUBARCH)
++include $(ARCH_DIR)/Makefile-os-$(OS)
++
+ EXTRAVERSION := $(EXTRAVERSION)-1um
+ ARCH_INCLUDE = -I$(ARCH_DIR)/include
+@@ -52,14 +57,14 @@ ARCH_INCLUDE = -I$(ARCH_DIR)/include
+ CFLAGS += $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \
+       -D_LARGEFILE64_SOURCE $(ARCH_INCLUDE) -Derrno=kernel_errno \
+-      $(MODE_INCLUDE)
++      -Dsigprocmask=kernel_sigprocmask $(MODE_INCLUDE)
+ LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc
+ SIZE = (($(CONFIG_NEST_LEVEL) + $(CONFIG_KERNEL_HALF_GIGS)) * 0x20000000)
+ ifeq ($(CONFIG_MODE_SKAS), y)
+-$(SYS_HEADERS) : $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h
++$(SYS_HEADERS) : $(TOPDIR)/$(ARCH_DIR)/include/skas_ptregs.h
+ endif
+ include/linux/version.h: arch/$(ARCH)/Makefile
+@@ -98,17 +103,17 @@ CPP_MODE_TT := $(shell [ "$(CONFIG_MODE_
+ CONFIG_KERNEL_STACK_ORDER ?= 2
+ STACK_SIZE := $(shell echo $$[ 4096 * (1 << $(CONFIG_KERNEL_STACK_ORDER)) ] )
+-AFLAGS_vmlinux.lds.o = -U$(SUBARCH) \
++AFLAGS_vmlinux.lds.o = $(shell echo -U$(SUBARCH) \
+       -DSTART=$$(($(TOP_ADDR) - $(SIZE))) -DELF_ARCH=$(ELF_ARCH) \
+       -DELF_FORMAT=\"$(ELF_FORMAT)\" $(CPP_MODE_TT) \
+-      -DKERNEL_STACK_SIZE=$(STACK_SIZE)
++      -DKERNEL_STACK_SIZE=$(STACK_SIZE))
+-AFLAGS_$(LD_SCRIPT-y:.s=).o = $(AFLAGS_vmlinux.lds.o) -P -C -Uum
++export AFLAGS_$(LD_SCRIPT-y:.s=).o = $(AFLAGS_vmlinux.lds.o) -P -C -Uum
+ LD_SCRIPT-y := $(ARCH_DIR)/$(LD_SCRIPT-y)
+-$(LD_SCRIPT-y) : $(LD_SCRIPT-y:.s=.S) scripts FORCE
+-      $(call if_changed_dep,as_s_S)
++#$(LD_SCRIPT-y) : $(LD_SCRIPT-y:.s=.S) scripts FORCE
++#     $(call if_changed_dep,as_s_S)
+ linux: vmlinux $(LD_SCRIPT-y)
+       $(CC) -Wl,-T,$(LD_SCRIPT-y) $(LINK-y) $(LINK_WRAPS) \
+@@ -116,6 +121,7 @@ linux: vmlinux $(LD_SCRIPT-y)
+ USER_CFLAGS := $(patsubst -I%,,$(CFLAGS))
+ USER_CFLAGS := $(patsubst -Derrno=kernel_errno,,$(USER_CFLAGS))
++USER_CFLAGS := $(patsubst -Dsigprocmask=kernel_sigprocmask,,$(USER_CFLAGS))
+ USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) $(ARCH_INCLUDE) \
+       $(MODE_INCLUDE)
+@@ -123,9 +129,10 @@ USER_CFLAGS := $(patsubst -D__KERNEL__,,
+ USER_CFLAGS += -D_GNU_SOURCE
+ CLEAN_FILES += linux x.i gmon.out $(ARCH_DIR)/uml.lds.s \
+-      $(ARCH_DIR)/dyn_link.ld.s $(GEN_HEADERS)
++      $(ARCH_DIR)/dyn_link.ld.s $(ARCH_DIR)/include/uml-config.h \
++      $(GEN_HEADERS)
+-$(ARCH_DIR)/main.o: $(ARCH_DIR)/main.c
++$(ARCH_DIR)/main.o: $(ARCH_DIR)/main.c sys_prepare
+       $(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
+ archmrproper:
+@@ -161,19 +168,23 @@ $(ARCH_DIR)/include/sysdep:
+ $(ARCH_DIR)/os:
+       cd $(ARCH_DIR) && ln -sf os-$(OS) os
+-$(ARCH_DIR)/include/uml-config.h :
++$(ARCH_DIR)/include/uml-config.h : $(TOPDIR)/include/linux/autoconf.h
+       sed 's/ CONFIG/ UML_CONFIG/' $(TOPDIR)/include/linux/autoconf.h > $@
++filechk_$(ARCH_DIR)/include/task.h := $(ARCH_DIR)/util/mk_task
++
+ $(ARCH_DIR)/include/task.h : $(ARCH_DIR)/util/mk_task
+-      $< > $@
++      $(call filechk,$@)
++
++filechk_$(ARCH_DIR)/include/kern_constants.h := $(ARCH_DIR)/util/mk_constants
+ $(ARCH_DIR)/include/kern_constants.h : $(ARCH_DIR)/util/mk_constants
+-      $< > $@
++      $(call filechk,$@)
+-$(ARCH_DIR)/util/mk_task : $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h \
+-      $(ARCH_DIR)/util FORCE ;
++$(ARCH_DIR)/util/mk_task $(ARCH_DIR)/util/mk_constants : $(ARCH_DIR)/util \
++      sys_prepare FORCE ;
+ $(ARCH_DIR)/util: FORCE
+-      @$(call descend,$@,)
++      $(MAKE) -f scripts/Makefile.build obj=$@
+-export SUBARCH USER_CFLAGS OS
++export SUBARCH USER_CFLAGS OS 
+--- linux-2.6.0-test6/arch/um/Makefile-i386    2003-06-14 12:18:29.000000000 -0700
++++ 25/arch/um/Makefile-i386   2003-10-05 00:34:32.000000000 -0700
+@@ -16,22 +16,28 @@ SYS_UTIL_DIR       := $(ARCH_DIR)/sys-i386/uti
+ SYS_HEADERS = $(SYS_DIR)/sc.h $(SYS_DIR)/thread.h
++sys_prepare: $(SYS_DIR)/sc.h
++
+ prepare: $(SYS_HEADERS)
++filechk_$(SYS_DIR)/sc.h := $(SYS_UTIL_DIR)/mk_sc
++
+ $(SYS_DIR)/sc.h: $(SYS_UTIL_DIR)/mk_sc
+-      $< > $@
++      $(call filechk,$@)
++
++filechk_$(SYS_DIR)/thread.h := $(SYS_UTIL_DIR)/mk_thread 
+ $(SYS_DIR)/thread.h: $(SYS_UTIL_DIR)/mk_thread 
+-      $< > $@
++      $(call filechk,$@)
+-$(SYS_UTIL_DIR)/mk_sc: FORCE ; 
+-      @$(call descend,$(SYS_UTIL_DIR),$@)
++$(SYS_UTIL_DIR)/mk_sc: scripts/fixdep include/config/MARKER FORCE ; 
++      +@$(call descend,$(SYS_UTIL_DIR),$@)
+-$(SYS_UTIL_DIR)/mk_thread: $(ARCH_SYMLINKS) $(GEN_HEADERS) FORCE ; 
+-      @$(call descend,$(SYS_UTIL_DIR),$@)
++$(SYS_UTIL_DIR)/mk_thread: $(ARCH_SYMLINKS) $(GEN_HEADERS) sys_prepare FORCE ; 
++      +@$(call descend,$(SYS_UTIL_DIR),$@)
+ $(SYS_UTIL_DIR): include/asm FORCE
+-      @$(call descend,$@,)
++      +@$(call descend,$@,)
+ sysclean :
+       rm -f $(SYS_HEADERS)
+--- linux-2.6.0-test6/arch/um/Makefile-skas    2003-06-14 12:18:09.000000000 -0700
++++ 25/arch/um/Makefile-skas   2003-10-05 00:34:32.000000000 -0700
+@@ -14,7 +14,7 @@ MODE_INCLUDE += -I$(TOPDIR)/$(ARCH_DIR)/
+ LINK_SKAS = -Wl,-rpath,/lib 
+ LD_SCRIPT_SKAS = dyn.lds.s
+-GEN_HEADERS += $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h
++GEN_HEADERS += $(TOPDIR)/$(ARCH_DIR)/include/skas_ptregs.h
+-$(ARCH_DIR)/kernel/skas/include/skas_ptregs.h :
+-      $(MAKE) -C $(ARCH_DIR)/kernel/skas include/skas_ptregs.h
++$(TOPDIR)/$(ARCH_DIR)/include/skas_ptregs.h :
++      $(call descend,$(ARCH_DIR)/kernel/skas,$@)
+--- linux-2.6.0-test6/arch/um/os-Linux/drivers/tuntap_user.c   2003-06-14 12:18:51.000000000 -0700
++++ 25/arch/um/os-Linux/drivers/tuntap_user.c  2003-10-05 00:34:32.000000000 -0700
+@@ -142,7 +142,7 @@ static int tuntap_open(void *data)
+                       return(-errno);
+               }
+               memset(&ifr, 0, sizeof(ifr));
+-              ifr.ifr_flags = IFF_TAP;
++              ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+               strlcpy(ifr.ifr_name, pri->dev_name, sizeof(ifr.ifr_name));
+               if(ioctl(pri->fd, TUNSETIFF, (void *) &ifr) < 0){
+                       printk("TUNSETIFF failed, errno = %d", errno);
+--- linux-2.6.0-test6/arch/um/os-Linux/file.c  2003-06-14 12:18:51.000000000 -0700
++++ 25/arch/um/os-Linux/file.c 2003-10-05 00:34:32.000000000 -0700
+@@ -315,7 +315,7 @@ int os_rcv_fd(int fd, int *helper_pid_ou
+       return(new);
+ }
+-int create_unix_socket(char *file, int len)
++int create_unix_socket(char *file, int len, int close_on_exec)
+ {
+       struct sockaddr_un addr;
+       int sock, err;
+@@ -327,6 +327,10 @@ int create_unix_socket(char *file, int l
+               return(-errno);
+       }
++      if(close_on_exec && fcntl(sock, F_SETFD, 1) < 0)
++              printk("create_unix_socket : Setting FD_CLOEXEC failed, "
++                     "errno = %d", errno);
++
+       addr.sun_family = AF_UNIX;
+       /* XXX Be more careful about overflow */
+@@ -342,6 +346,37 @@ int create_unix_socket(char *file, int l
+       return(sock);
+ }
++void os_flush_stdout(void)
++{
++      fflush(stdout);
++}
++
++int os_lock_file(int fd, int excl)
++{
++      int type = excl ? F_WRLCK : F_RDLCK;
++      struct flock lock = ((struct flock) { .l_type   = type,
++                                            .l_whence = SEEK_SET,
++                                            .l_start  = 0,
++                                            .l_len    = 0 } );
++      int err, save;
++
++      err = fcntl(fd, F_SETLK, &lock);
++      if(!err)
++              goto out;
++
++      save = -errno;
++      err = fcntl(fd, F_GETLK, &lock);
++      if(err){
++              err = -errno;
++              goto out;
++      }
++      
++      printk("F_SETLK failed, file already locked by pid %d\n", lock.l_pid);
++      err = save;
++ out:
++      return(err);
++}
++
+ /*
+  * Overrides for Emacs so that we follow Linus's tabbing style.
+  * Emacs will notice this stuff at the end of the file and automatically
+--- linux-2.6.0-test6/arch/um/sys-i386/bugs.c  2003-06-14 12:18:29.000000000 -0700
++++ 25/arch/um/sys-i386/bugs.c 2003-10-05 00:34:32.000000000 -0700
+@@ -8,6 +8,7 @@
+ #include <errno.h>
+ #include <string.h>
+ #include <sys/signal.h>
++#include <asm/ldt.h>
+ #include "kern_util.h"
+ #include "user.h"
+ #include "sysdep/ptrace.h"
+@@ -16,8 +17,8 @@
+ #define MAXTOKEN 64
+ /* Set during early boot */
+-int cpu_has_cmov = 1;
+-int cpu_has_xmm = 0;
++int host_has_cmov = 1;
++int host_has_xmm = 0;
+ static char token(int fd, char *buf, int len, char stop)
+ {
+@@ -104,6 +105,25 @@ static int check_cpu_feature(char *featu
+       return(1);
+ }
++static void disable_lcall(void)
++{
++      struct modify_ldt_ldt_s ldt;
++      int err;
++
++      bzero(&ldt, sizeof(ldt));
++      ldt.entry_number = 7;
++      ldt.base_addr = 0;
++      ldt.limit = 0;
++      err = modify_ldt(1, &ldt, sizeof(ldt));
++      if(err)
++              printk("Failed to disable lcall7 - errno = %d\n", errno);
++}
++
++void arch_init_thread(void)
++{
++      disable_lcall();
++}
++
+ void arch_check_bugs(void)
+ {
+       int have_it;
+@@ -113,8 +133,8 @@ void arch_check_bugs(void)
+                      "checks\n");
+               return;
+       }
+-      if(check_cpu_feature("cmov", &have_it)) cpu_has_cmov = have_it;
+-      if(check_cpu_feature("xmm", &have_it)) cpu_has_xmm = have_it;
++      if(check_cpu_feature("cmov", &have_it)) host_has_cmov = have_it;
++      if(check_cpu_feature("xmm", &have_it)) host_has_xmm = have_it;
+ }
+ int arch_handle_signal(int sig, union uml_pt_regs *regs)
+@@ -130,18 +150,18 @@ int arch_handle_signal(int sig, union um
+       if((*((char *) ip) != 0x0f) || ((*((char *) (ip + 1)) & 0xf0) != 0x40))
+               return(0);
+-      if(cpu_has_cmov == 0)
++      if(host_has_cmov == 0)
+               panic("SIGILL caused by cmov, which this processor doesn't "
+                     "implement, boot a filesystem compiled for older "
+                     "processors");
+-      else if(cpu_has_cmov == 1)
++      else if(host_has_cmov == 1)
+               panic("SIGILL caused by cmov, which this processor claims to "
+                     "implement");
+-      else if(cpu_has_cmov == -1)
++      else if(host_has_cmov == -1)
+               panic("SIGILL caused by cmov, couldn't tell if this processor "
+                     "implements it, boot a filesystem compiled for older "
+                     "processors");
+-      else panic("Bad value for cpu_has_cmov (%d)", cpu_has_cmov);
++      else panic("Bad value for host_has_cmov (%d)", host_has_cmov);
+       return(0);
+ }
+--- linux-2.6.0-test6/arch/um/sys-i386/Makefile        2003-06-14 12:17:59.000000000 -0700
++++ 25/arch/um/sys-i386/Makefile       2003-10-05 00:34:32.000000000 -0700
+@@ -1,7 +1,8 @@
+-obj-y = bugs.o checksum.o extable.o fault.o ksyms.o ldt.o module.o \
+-      ptrace.o ptrace_user.o semaphore.o sigcontext.o syscalls.o sysrq.o
++obj-y = bugs.o checksum.o extable.o fault.o ksyms.o ldt.o ptrace.o \
++      ptrace_user.o semaphore.o sigcontext.o syscalls.o sysrq.o
+ obj-$(CONFIG_HIGHMEM) += highmem.o
++obj-$(CONFIG_MODULES) += module.o
+ USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o
+ USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
+@@ -9,6 +10,8 @@ USER_OBJS := $(foreach file,$(USER_OBJS)
+ SYMLINKS = semaphore.c highmem.c module.c
+ SYMLINKS := $(foreach f,$(SYMLINKS),$(src)/$f)
++clean-files := $(SYMLINKS)
++
+ semaphore.c-dir = kernel
+ highmem.c-dir = mm
+ module.c-dir = kernel
+@@ -24,8 +27,7 @@ $(USER_OBJS) : %.o: %.c
+ $(SYMLINKS): 
+       $(call make_link,$@)
+-clean:
+-      $(MAKE) -C util clean
++subdir- := util
+ fastdep:
+--- linux-2.6.0-test6/arch/um/uml.lds.S        2003-06-14 12:18:09.000000000 -0700
++++ 25/arch/um/uml.lds.S       2003-10-05 00:34:32.000000000 -0700
+@@ -26,7 +26,11 @@ SECTIONS
+   . = ALIGN(4096);            /* Init code and data */
+   _stext = .;
+   __init_begin = .;
+-  .text.init : { *(.text.init) }
++  .init.text : { 
++      _sinittext = .;
++      *(.init.text)
++      _einittext = .;
++  }
+   . = ALIGN(4096);
+   .text      :
+   {
+@@ -38,7 +42,7 @@ SECTIONS
+   #include "asm/common.lds.S"
+-  .data.init : { *(.data.init) }
++  init.data : { *(init.data) }
+   .data    :
+   {
+     . = ALIGN(KERNEL_STACK_SIZE);             /* init_task */
+--- linux-2.6.0-test6/arch/um/util/mk_constants_kern.c 2003-06-14 12:17:57.000000000 -0700
++++ 25/arch/um/util/mk_constants_kern.c        2003-10-05 00:34:32.000000000 -0700
+@@ -1,5 +1,6 @@
+ #include "linux/kernel.h"
+ #include "linux/stringify.h"
++#include "linux/time.h"
+ #include "asm/page.h"
+ extern void print_head(void);
+@@ -11,6 +12,7 @@ int main(int argc, char **argv)
+ {
+   print_head();
+   print_constant_int("UM_KERN_PAGE_SIZE", PAGE_SIZE);
++
+   print_constant_str("UM_KERN_EMERG", KERN_EMERG);
+   print_constant_str("UM_KERN_ALERT", KERN_ALERT);
+   print_constant_str("UM_KERN_CRIT", KERN_CRIT);
+@@ -19,6 +21,8 @@ int main(int argc, char **argv)
+   print_constant_str("UM_KERN_NOTICE", KERN_NOTICE);
+   print_constant_str("UM_KERN_INFO", KERN_INFO);
+   print_constant_str("UM_KERN_DEBUG", KERN_DEBUG);
++
++  print_constant_int("UM_NSEC_PER_SEC", NSEC_PER_SEC);
+   print_tail();
+   return(0);
+ }
+--- linux-2.6.0-test6/arch/x86_64/boot/compressed/head.S       2003-06-26 22:07:24.000000000 -0700
++++ 25/arch/x86_64/boot/compressed/head.S      2003-10-05 00:33:43.000000000 -0700
+@@ -26,6 +26,7 @@
+ .code32
+ .text
++#define IN_BOOTLOADER
+ #include <linux/linkage.h>
+ #include <asm/segment.h>
+--- linux-2.6.0-test6/arch/x86_64/boot/compressed/misc.c       2003-09-27 18:57:44.000000000 -0700
++++ 25/arch/x86_64/boot/compressed/misc.c      2003-10-05 00:33:43.000000000 -0700
+@@ -9,6 +9,7 @@
+  * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
+  */
++#define IN_BOOTLOADER
+ #include "miscsetup.h"
+ #include <asm/io.h>
+--- linux-2.6.0-test6/arch/x86_64/ia32/ia32_binfmt.c   2003-08-22 19:23:40.000000000 -0700
++++ 25/arch/x86_64/ia32/ia32_binfmt.c  2003-10-05 00:33:23.000000000 -0700
+@@ -82,9 +82,12 @@ do {                                                                              \
+       int i;                                                                \
+       Elf32_Off ofs = 0;                                                    \
+       for (i = 0; i < VSYSCALL32_EHDR->e_phnum; ++i) {                      \
+-              struct elf_phdr phdr = vsyscall_phdrs[i];                     \
++              struct elf32_phdr phdr = vsyscall_phdrs[i];                   \
+               if (phdr.p_type == PT_LOAD) {                                 \
++                      BUG_ON(ofs != 0);                                     \
+                       ofs = phdr.p_offset = offset;                         \
++                      phdr.p_memsz = PAGE_ALIGN(phdr.p_memsz);              \
++                      phdr.p_filesz = phdr.p_memsz;                         \
+                       offset += phdr.p_filesz;                              \
+               }                                                             \
+               else                                                          \
+@@ -99,10 +102,10 @@ do {                                                                            \
+               (const struct elf32_phdr *) (VSYSCALL32_BASE                  \
+                                          + VSYSCALL32_EHDR->e_phoff);       \
+       int i;                                                                \
+-      for (i = 0; i < VSYSCALL32_EHDR->e_phnum; ++i) {                      \
++      for (i = 0; i < VSYSCALL_EHDR->e_phnum; ++i) {                        \
+               if (vsyscall_phdrs[i].p_type == PT_LOAD)                      \
+                       DUMP_WRITE((void *) (u64) vsyscall_phdrs[i].p_vaddr,          \
+-                                 vsyscall_phdrs[i].p_filesz);               \
++                                 PAGE_ALIGN(vsyscall_phdrs[i].p_memsz));    \
+       }                                                                     \
+ } while (0)
+--- linux-2.6.0-test6/arch/x86_64/ia32/ia32_ioctl.c    2003-09-27 18:57:44.000000000 -0700
++++ 25/arch/x86_64/ia32/ia32_ioctl.c   2003-10-05 00:34:44.000000000 -0700
+@@ -38,87 +38,6 @@ static int tiocgdev(unsigned fd, unsigne
+       return put_user(new_encode_dev(tty_devnum(real_tty)), ptr); 
+ } 
+-
+-struct raw32_config_request 
+-{
+-      compat_int_t    raw_minor;
+-      __u64   block_major;
+-      __u64   block_minor;
+-} __attribute__((packed));
+-
+-static int raw_ioctl(unsigned fd, unsigned cmd,  void *ptr) 
+-{ 
+-      int ret;
+-      switch (cmd) { 
+-      case RAW_SETBIND:
+-      case RAW_GETBIND: {
+-              struct raw_config_request req; 
+-              struct raw32_config_request *user_req = ptr;
+-              mm_segment_t oldfs = get_fs(); 
+-
+-              if (get_user(req.raw_minor, &user_req->raw_minor) ||
+-                  get_user(req.block_major, &user_req->block_major) ||
+-                  get_user(req.block_minor, &user_req->block_minor))
+-                      return -EFAULT;
+-              set_fs(KERNEL_DS); 
+-              ret = sys_ioctl(fd,cmd,(unsigned long)&req); 
+-              set_fs(oldfs); 
+-              break;
+-      }
+-      default:
+-              ret = sys_ioctl(fd,cmd,(unsigned long)ptr);
+-              break;
+-      } 
+-      return ret;             
+-} 
+-
+-
+-#define REISERFS_IOC_UNPACK32               _IOW(0xCD,1,int)
+-
+-static int reiserfs_ioctl32(unsigned fd, unsigned cmd, unsigned long ptr) 
+-{ 
+-      if (cmd == REISERFS_IOC_UNPACK32) 
+-              cmd = REISERFS_IOC_UNPACK; 
+-      return sys_ioctl(fd,cmd,ptr); 
+-} 
+-
+-struct dirent32 {
+-      compat_int_t    d_ino;
+-      compat_off_t    d_off;
+-      unsigned short  d_reclen;
+-      char            d_name[256]; /* We must not include limits.h! */
+-};
+-
+-#define       VFAT_IOCTL_READDIR_BOTH32       _IOR('r', 1, struct dirent32 [2])
+-#define       VFAT_IOCTL_READDIR_SHORT32      _IOR('r', 2, struct dirent32 [2])
+-
+-static int put_dirent32(struct dirent *src, struct dirent32 *dst)
+-{
+-      int ret; 
+-      ret = put_user(src->d_ino, &dst->d_ino); 
+-      ret |= __put_user(src->d_off, &dst->d_off); 
+-      ret |= __put_user(src->d_reclen, &dst->d_reclen); 
+-      if (__copy_to_user(&dst->d_name, src->d_name, src->d_reclen))
+-              ret |= -EFAULT;
+-      return ret;
+-} 
+-
+-static int vfat_ioctl32(unsigned fd, unsigned cmd,  void *ptr) 
+-{
+-      int ret;
+-      mm_segment_t oldfs = get_fs();
+-      struct dirent d[2]; 
+-
+-      set_fs(KERNEL_DS);
+-      ret = sys_ioctl(fd,cmd,(unsigned long)&d); 
+-      set_fs(oldfs); 
+-      if (!ret) { 
+-              ret |= put_dirent32(&d[0], (struct dirent32 *)ptr); 
+-              ret |= put_dirent32(&d[1], ((struct dirent32 *)ptr) + 1); 
+-      }
+-      return ret; 
+-} 
+-
+ #define RTC_IRQP_READ32       _IOR('p', 0x0b, unsigned int)    /* Read IRQ rate   */
+ #define RTC_IRQP_SET32        _IOW('p', 0x0c, unsigned int)    /* Set IRQ rate    */
+ #define RTC_EPOCH_READ32      _IOR('p', 0x0d, unsigned)        /* Read epoch      */
+@@ -158,436 +77,6 @@ static int rtc32_ioctl(unsigned fd, unsi
+       return sys_ioctl(fd,cmd,arg); 
+ } 
+-struct serial_struct32 {
+-      compat_int_t    type;
+-      compat_int_t    line;
+-      compat_uint_t   port;
+-      compat_int_t    irq;
+-      compat_int_t    flags;
+-      compat_int_t    xmit_fifo_size;
+-      compat_int_t    custom_divisor;
+-      compat_int_t    baud_base;
+-      unsigned short  close_delay;
+-      char    io_type;
+-      char    reserved_char[1];
+-      compat_int_t    hub6;
+-      unsigned short  closing_wait; /* time to wait before closing */
+-      unsigned short  closing_wait2; /* no longer used... */
+-      compat_uint_t   iomem_base;
+-      unsigned short  iomem_reg_shift;
+-      unsigned int    port_high;
+-      compat_int_t    reserved[1];
+-};
+-
+-static int serial_struct_ioctl(unsigned fd, unsigned cmd,  void *ptr) 
+-{
+-      typedef struct serial_struct SS;
+-      struct serial_struct32 *ss32 = ptr; 
+-      int err;
+-      struct serial_struct ss; 
+-      mm_segment_t oldseg = get_fs(); 
+-      if (cmd == TIOCSSERIAL) { 
+-              if (copy_from_user(&ss, ss32, sizeof(struct serial_struct32)))
+-                      return -EFAULT;
+-              memmove(&ss.iomem_reg_shift, ((char*)&ss.iomem_base)+4, 
+-                      sizeof(SS)-offsetof(SS,iomem_reg_shift)); 
+-              ss.iomem_base = (void *)((unsigned long)ss.iomem_base & 0xffffffff);
+-      }
+-      set_fs(KERNEL_DS);
+-              err = sys_ioctl(fd,cmd,(unsigned long)(&ss)); 
+-      set_fs(oldseg);
+-      if (cmd == TIOCGSERIAL && err >= 0) { 
+-              if (__copy_to_user(ss32,&ss,offsetof(SS,iomem_base)) ||
+-                  __put_user((unsigned long)ss.iomem_base  >> 32 ? 
+-                             0xffffffff : (unsigned)(unsigned long)ss.iomem_base,
+-                             &ss32->iomem_base) ||
+-                  __put_user(ss.iomem_reg_shift, &ss32->iomem_reg_shift) ||
+-                  __put_user(ss.port_high, &ss32->port_high))
+-                      return -EFAULT;
+-      } 
+-      return err;     
+-}
+-
+-
+-
+-struct usbdevfs_ctrltransfer32 {
+-      u8 bRequestType;
+-      u8 bRequest;
+-      u16 wValue;
+-      u16 wIndex;
+-      u16 wLength;
+-      u32 timeout;  /* in milliseconds */
+-      compat_caddr_t data;
+-};
+-
+-#define USBDEVFS_CONTROL32           _IOWR('U', 0, struct usbdevfs_ctrltransfer32)
+-
+-static int do_usbdevfs_control(unsigned int fd, unsigned int cmd, unsigned long arg)
+-{
+-      struct usbdevfs_ctrltransfer kctrl;
+-      struct usbdevfs_ctrltransfer32 *uctrl;
+-      mm_segment_t old_fs;
+-      __u32 udata;
+-      void *uptr, *kptr;
+-      int err;
+-
+-      uctrl = (struct usbdevfs_ctrltransfer32 *) arg;
+-
+-      if (copy_from_user(&kctrl, uctrl,
+-                         (sizeof(struct usbdevfs_ctrltransfer) -
+-                          sizeof(void *))))
+-              return -EFAULT;
+-
+-      if (get_user(udata, &uctrl->data))
+-              return -EFAULT;
+-      uptr = compat_ptr(udata);
+-
+-      /* In usbdevice_fs, it limits the control buffer to a page,
+-       * for simplicity so do we.
+-       */
+-      if (!uptr || kctrl.wLength > PAGE_SIZE)
+-              return -EINVAL;
+-
+-      kptr = (void *)__get_free_page(GFP_KERNEL);
+-
+-      if ((kctrl.bRequestType & 0x80) == 0) {
+-              err = -EFAULT;
+-              if (copy_from_user(kptr, uptr, kctrl.wLength))
+-                      goto out;
+-      }
+-
+-      kctrl.data = kptr;
+-
+-      old_fs = get_fs();
+-      set_fs(KERNEL_DS);
+-      err = sys_ioctl(fd, USBDEVFS_CONTROL, (unsigned long)&kctrl);
+-      set_fs(old_fs);
+-
+-      if (err >= 0 &&
+-          ((kctrl.bRequestType & 0x80) != 0)) {
+-              if (copy_to_user(uptr, kptr, kctrl.wLength))
+-                      err = -EFAULT;
+-      }
+-
+-out:
+-      free_page((unsigned long) kptr);
+-      return err;
+-}
+-
+-struct usbdevfs_bulktransfer32 {
+-      compat_uint_t ep;
+-      compat_uint_t len;
+-      compat_uint_t timeout; /* in milliseconds */
+-      compat_caddr_t data;
+-};
+-
+-#define USBDEVFS_BULK32              _IOWR('U', 2, struct usbdevfs_bulktransfer32)
+-
+-static int do_usbdevfs_bulk(unsigned int fd, unsigned int cmd, unsigned long arg)
+-{
+-      struct usbdevfs_bulktransfer kbulk;
+-      struct usbdevfs_bulktransfer32 *ubulk;
+-      mm_segment_t old_fs;
+-      __u32 udata;
+-      void *uptr, *kptr;
+-      int err;
+-
+-      ubulk = (struct usbdevfs_bulktransfer32 *) arg;
+-
+-      if (get_user(kbulk.ep, &ubulk->ep) ||
+-          get_user(kbulk.len, &ubulk->len) ||
+-          get_user(kbulk.timeout, &ubulk->timeout) ||
+-          get_user(udata, &ubulk->data))
+-              return -EFAULT;
+-
+-      uptr = compat_ptr(udata);
+-
+-      /* In usbdevice_fs, it limits the control buffer to a page,
+-       * for simplicity so do we.
+-       */
+-      if (!uptr || kbulk.len > PAGE_SIZE)
+-              return -EINVAL;
+-
+-      kptr = (void *) __get_free_page(GFP_KERNEL);
+-
+-      if ((kbulk.ep & 0x80) == 0) {
+-              err = -EFAULT;
+-              if (copy_from_user(kptr, uptr, kbulk.len))
+-                      goto out;
+-      }
+-
+-      kbulk.data = kptr;
+-
+-      old_fs = get_fs();
+-      set_fs(KERNEL_DS);
+-      err = sys_ioctl(fd, USBDEVFS_BULK, (unsigned long) &kbulk);
+-      set_fs(old_fs);
+-
+-      if (err >= 0 &&
+-          ((kbulk.ep & 0x80) != 0)) {
+-              if (copy_to_user(uptr, kptr, kbulk.len))
+-                      err = -EFAULT;
+-      }
+-
+-out:
+-      free_page((unsigned long) kptr);
+-      return err;
+-}
+-
+-/* This needs more work before we can enable it.  Unfortunately
+- * because of the fancy asynchronous way URB status/error is written
+- * back to userspace, we'll need to fiddle with USB devio internals
+- * and/or reimplement entirely the frontend of it ourselves. -DaveM
+- *
+- * The issue is:
+- *
+- *    When an URB is submitted via usbdevicefs it is put onto an
+- *    asynchronous queue.  When the URB completes, it may be reaped
+- *    via another ioctl.  During this reaping the status is written
+- *    back to userspace along with the length of the transfer.
+- *
+- *    We must translate into 64-bit kernel types so we pass in a kernel
+- *    space copy of the usbdevfs_urb structure.  This would mean that we
+- *    must do something to deal with the async entry reaping.  First we
+- *    have to deal somehow with this transitory memory we've allocated.
+- *    This is problematic since there are many call sites from which the
+- *    async entries can be destroyed (and thus when we'd need to free up
+- *    this kernel memory).  One of which is the close() op of usbdevicefs.
+- *    To handle that we'd need to make our own file_operations struct which
+- *    overrides usbdevicefs's release op with our own which runs usbdevicefs's
+- *    real release op then frees up the kernel memory.
+- *
+- *    But how to keep track of these kernel buffers?  We'd need to either
+- *    keep track of them in some table _or_ know about usbdevicefs internals
+- *    (ie. the exact layout of its file private, which is actually defined
+- *    in linux/usbdevice_fs.h, the layout of the async queues are private to
+- *    devio.c)
+- *
+- * There is one possible other solution I considered, also involving knowledge
+- * of usbdevicefs internals:
+- *
+- *    After an URB is submitted, we "fix up" the address back to the user
+- *    space one.  This would work if the status/length fields written back
+- *    by the async URB completion lines up perfectly in the 32-bit type with
+- *    the 64-bit kernel type.  Unfortunately, it does not because the iso
+- *    frame descriptors, at the end of the struct, can be written back.
+- *
+- * I think we'll just need to simply duplicate the devio URB engine here.
+- */
+-#if 0
+-struct usbdevfs_urb32 {
+-      unsigned char type;
+-      unsigned char endpoint;
+-      compat_int_t status;
+-      compat_uint_t flags;
+-      compat_caddr_t buffer;
+-      compat_int_t buffer_length;
+-      compat_int_t actual_length;
+-      compat_int_t start_frame;
+-      compat_int_t number_of_packets;
+-      compat_int_t error_count;
+-      compat_uint_t signr;
+-      compat_caddr_t usercontext; /* unused */
+-      struct usbdevfs_iso_packet_desc iso_frame_desc[0];
+-};
+-
+-#define USBDEVFS_SUBMITURB32       _IOR('U', 10, struct usbdevfs_urb32)
+-
+-static int get_urb32(struct usbdevfs_urb *kurb,
+-                   struct usbdevfs_urb32 *uurb)
+-{
+-      if (get_user(kurb->type, &uurb->type) ||
+-          __get_user(kurb->endpoint, &uurb->endpoint) ||
+-          __get_user(kurb->status, &uurb->status) ||
+-          __get_user(kurb->flags, &uurb->flags) ||
+-          __get_user(kurb->buffer_length, &uurb->buffer_length) ||
+-          __get_user(kurb->actual_length, &uurb->actual_length) ||
+-          __get_user(kurb->start_frame, &uurb->start_frame) ||
+-          __get_user(kurb->number_of_packets, &uurb->number_of_packets) ||
+-          __get_user(kurb->error_count, &uurb->error_count) ||
+-          __get_user(kurb->signr, &uurb->signr))
+-              return -EFAULT;
+-
+-      kurb->usercontext = 0; /* unused currently */
+-
+-      return 0;
+-}
+-
+-/* Just put back the values which usbdevfs actually changes. */
+-static int put_urb32(struct usbdevfs_urb *kurb,
+-                   struct usbdevfs_urb32 *uurb)
+-{
+-      if (put_user(kurb->status, &uurb->status) ||
+-          __put_user(kurb->actual_length, &uurb->actual_length) ||
+-          __put_user(kurb->error_count, &uurb->error_count))
+-              return -EFAULT;
+-
+-      if (kurb->number_of_packets != 0) {
+-              int i;
+-
+-              for (i = 0; i < kurb->number_of_packets; i++) {
+-                      if (__put_user(kurb->iso_frame_desc[i].actual_length,
+-                                     &uurb->iso_frame_desc[i].actual_length) ||
+-                          __put_user(kurb->iso_frame_desc[i].status,
+-                                     &uurb->iso_frame_desc[i].status))
+-                              return -EFAULT;
+-              }
+-      }
+-
+-      return 0;
+-}
+-
+-static int get_urb32_isoframes(struct usbdevfs_urb *kurb,
+-                             struct usbdevfs_urb32 *uurb)
+-{
+-      unsigned int totlen;
+-      int i;
+-
+-      if (kurb->type != USBDEVFS_URB_TYPE_ISO) {
+-              kurb->number_of_packets = 0;
+-              return 0;
+-      }
+-
+-      if (kurb->number_of_packets < 1 ||
+-          kurb->number_of_packets > 128)
+-              return -EINVAL;
+-
+-      if (copy_from_user(&kurb->iso_frame_desc[0],
+-                         &uurb->iso_frame_desc[0],
+-                         sizeof(struct usbdevfs_iso_packet_desc) *
+-                         kurb->number_of_packets))
+-              return -EFAULT;
+-
+-      totlen = 0;
+-      for (i = 0; i < kurb->number_of_packets; i++) {
+-              unsigned int this_len;
+-
+-              this_len = kurb->iso_frame_desc[i].length;
+-              if (this_len > 1023)
+-                      return -EINVAL;
+-
+-              totlen += this_len;
+-      }
+-
+-      if (totlen > 32768)
+-              return -EINVAL;
+-
+-      kurb->buffer_length = totlen;
+-
+-      return 0;
+-}
+-
+-static int do_usbdevfs_urb(unsigned int fd, unsigned int cmd, unsigned long arg)
+-{
+-      struct usbdevfs_urb *kurb;
+-      struct usbdevfs_urb32 *uurb;
+-      mm_segment_t old_fs;
+-      __u32 udata;
+-      void *uptr, *kptr;
+-      unsigned int buflen;
+-      int err;
+-
+-      uurb = (struct usbdevfs_urb32 *) arg;
+-
+-      err = -ENOMEM;
+-      kurb = kmalloc(sizeof(struct usbdevfs_urb) +
+-                     (sizeof(struct usbdevfs_iso_packet_desc) * 128),
+-                     GFP_KERNEL);
+-      if (!kurb)
+-              goto out;
+-
+-      err = -EFAULT;
+-      if (get_urb32(kurb, uurb))
+-              goto out;
+-
+-      err = get_urb32_isoframes(kurb, uurb);
+-      if (err)
+-              goto out;
+-
+-      err = -EFAULT;
+-      if (__get_user(udata, &uurb->buffer))
+-              goto out;
+-      uptr = compat_ptr(udata);
+-
+-      buflen = kurb->buffer_length;
+-      err = verify_area(VERIFY_WRITE, uptr, buflen);
+-      if (err) 
+-              goto out;
+-
+-
+-      old_fs = get_fs();
+-      set_fs(KERNEL_DS);
+-      err = sys_ioctl(fd, USBDEVFS_SUBMITURB, (unsigned long) kurb);
+-      set_fs(old_fs);
+-
+-      if (err >= 0) {
+-              /* RED-PEN Shit, this doesn't work for async URBs :-( XXX */
+-              if (put_urb32(kurb, uurb)) {
+-                      err = -EFAULT;
+-              }
+-      }
+-
+-out:
+-      kfree(kurb);
+-      return err;
+-}
+-#endif
+-
+-#define USBDEVFS_REAPURB32         _IOW('U', 12, u32)
+-#define USBDEVFS_REAPURBNDELAY32   _IOW('U', 13, u32)
+-
+-static int do_usbdevfs_reapurb(unsigned int fd, unsigned int cmd, unsigned long arg)
+-{
+-      mm_segment_t old_fs;
+-      void *kptr;
+-      int err;
+-
+-      old_fs = get_fs();
+-      set_fs(KERNEL_DS);
+-      err = sys_ioctl(fd,
+-                      (cmd == USBDEVFS_REAPURB32 ?
+-                       USBDEVFS_REAPURB :
+-                       USBDEVFS_REAPURBNDELAY),
+-                      (unsigned long) &kptr);
+-      set_fs(old_fs);
+-
+-      if (err >= 0 &&
+-          put_user((u32)(u64)kptr, (u32 *)arg))
+-              err = -EFAULT;
+-
+-      return err;
+-}
+-
+-struct usbdevfs_disconnectsignal32 {
+-      compat_int_t signr;
+-      compat_caddr_t context;
+-};
+-
+-#define USBDEVFS_DISCSIGNAL32      _IOR('U', 14, struct usbdevfs_disconnectsignal32)
+-
+-static int do_usbdevfs_discsignal(unsigned int fd, unsigned int cmd, unsigned long arg)
+-{
+-      struct usbdevfs_disconnectsignal kdis;
+-      struct usbdevfs_disconnectsignal32 *udis;
+-      mm_segment_t old_fs;
+-      u32 uctx;
+-      int err;
+-
+-      udis = (struct usbdevfs_disconnectsignal32 *) arg;
+-
+-      if (get_user(kdis.signr, &udis->signr) ||
+-          __get_user(uctx, &udis->context))
+-              return -EFAULT;
+-
+-      kdis.context = (void *) (long)uctx;
+-
+-      old_fs = get_fs();
+-      set_fs(KERNEL_DS);
+-      err = sys_ioctl(fd, USBDEVFS_DISCSIGNAL, (unsigned long) &kdis);
+-      set_fs(old_fs);
+-
+-      return err;
+-}
+ /* /proc/mtrr ioctls */
+@@ -726,27 +215,12 @@ COMPATIBLE_IOCTL(FIOQSIZE)
+ /* And these ioctls need translation */
+ HANDLE_IOCTL(TIOCGDEV, tiocgdev)
+-HANDLE_IOCTL(TIOCGSERIAL, serial_struct_ioctl)
+-HANDLE_IOCTL(TIOCSSERIAL, serial_struct_ioctl)
+-/* Raw devices */
+-HANDLE_IOCTL(RAW_SETBIND, raw_ioctl)
+ /* realtime device */
+ HANDLE_IOCTL(RTC_IRQP_READ,  rtc32_ioctl)
+ HANDLE_IOCTL(RTC_IRQP_READ32,rtc32_ioctl)
+ HANDLE_IOCTL(RTC_IRQP_SET32, rtc32_ioctl)
+ HANDLE_IOCTL(RTC_EPOCH_READ32, rtc32_ioctl)
+ HANDLE_IOCTL(RTC_EPOCH_SET32, rtc32_ioctl)
+-HANDLE_IOCTL(REISERFS_IOC_UNPACK32, reiserfs_ioctl32)
+-/* VFAT */
+-HANDLE_IOCTL(VFAT_IOCTL_READDIR_BOTH32, vfat_ioctl32)
+-HANDLE_IOCTL(VFAT_IOCTL_READDIR_SHORT32, vfat_ioctl32)
+-
+-HANDLE_IOCTL(USBDEVFS_CONTROL32, do_usbdevfs_control)
+-HANDLE_IOCTL(USBDEVFS_BULK32, do_usbdevfs_bulk)
+-/*HANDLE_IOCTL(USBDEVFS_SUBMITURB32, do_usbdevfs_urb)*/
+-HANDLE_IOCTL(USBDEVFS_REAPURB32, do_usbdevfs_reapurb)
+-HANDLE_IOCTL(USBDEVFS_REAPURBNDELAY32, do_usbdevfs_reapurb)
+-HANDLE_IOCTL(USBDEVFS_DISCSIGNAL32, do_usbdevfs_discsignal)
+ /* take care of sizeof(sizeof()) breakage */
+ /* mtrr */
+ HANDLE_IOCTL(MTRRIOC32_ADD_ENTRY, mtrr_ioctl32)
+--- linux-2.6.0-test6/arch/x86_64/kernel/i387.c        2003-06-14 12:18:05.000000000 -0700
++++ 25/arch/x86_64/kernel/i387.c       2003-10-05 00:33:23.000000000 -0700
+@@ -138,12 +138,3 @@ int dump_task_fpu(struct task_struct *ts
+ }
+       return fpvalid;
+ }
+-
+-#ifdef CONFIG_SMP
+-void dump_smp_unlazy_fpu(void)
+-{
+-      unlazy_fpu(current);
+-      return;
+-}
+-#endif
+-
+--- linux-2.6.0-test6/arch/x86_64/mm/ioremap.c 2003-06-14 12:18:34.000000000 -0700
++++ 25/arch/x86_64/mm/ioremap.c        2003-10-05 00:33:23.000000000 -0700
+@@ -159,7 +159,7 @@ void * __ioremap(unsigned long phys_addr
+       if (!area)
+               return NULL;
+       addr = area->addr;
+-      if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size, flags)) {
++      if (remap_area_pages((unsigned long) addr, phys_addr, size, flags)) {
+               vunmap(addr);
+               return NULL;
+       }
+--- linux-2.6.0-test6/CREDITS  2003-09-27 18:57:43.000000000 -0700
++++ 25/CREDITS 2003-10-05 00:33:23.000000000 -0700
+@@ -1459,6 +1459,13 @@ S: Ballinagard
+ S: Roscommon
+ S: Ireland
++N: Michael Hunold
++E: michael@mihu.de
++W: http://www.mihu.de/linux/
++D: Generic saa7146 video4linux-2 driver core,
++D: Driver for the "Multimedia eXtension Board", "dpc7146",
++D: "Hexium Orion", "Hexium Gemini"
++
+ N: Miguel de Icaza Amozurrutia
+ E: miguel@nuclecu.unam.mx
+ D: Linux/SPARC team, Midnight Commander maintainer
+--- linux-2.6.0-test6/Documentation/cachetlb.txt       2003-06-14 12:18:07.000000000 -0700
++++ 25/Documentation/cachetlb.txt      2003-10-05 00:33:23.000000000 -0700
+@@ -59,9 +59,9 @@ changes occur:
+       address translations from the TLB.  After running, this
+       interface must make sure that any previous page table
+       modifications for the address space 'vma->vm_mm' in the range
+-      'start' to 'end' will be visible to the cpu.  That is, after
++      'start' to 'end-1' will be visible to the cpu.  That is, after
+       running, here will be no entries in the TLB for 'mm' for
+-      virtual addresses in the range 'start' to 'end'.
++      virtual addresses in the range 'start' to 'end-1'.
+       The "vma" is the backing store being used for the region.
+       Primarily, this is used for munmap() type operations.
+@@ -100,7 +100,7 @@ changes occur:
+                          unsigned long start, unsigned long end)
+    The software page tables for address space 'mm' for virtual
+-   addresses in the range 'start' to 'end' are being torn down.
++   addresses in the range 'start' to 'end-1' are being torn down.
+    Some platforms cache the lowest level of the software page tables
+    in a linear virtually mapped array, to make TLB miss processing
+@@ -165,15 +165,7 @@ and have no dependency on translation in
+ Here are the routines, one by one:
+-1) void flush_cache_all(void)
+-
+-      The most severe flush of all.  After this interface runs,
+-      the entire cpu cache is flushed.
+-
+-      This is usually invoked when the kernel page tables are
+-      changed, since such translations are "global" in nature.
+-
+-2) void flush_cache_mm(struct mm_struct *mm)
++1) void flush_cache_mm(struct mm_struct *mm)
+       This interface flushes an entire user address space from
+       the caches.  That is, after running, there will be no cache
+@@ -183,13 +175,13 @@ Here are the routines, one by one:
+       page table operations such as what happens during
+       fork, exit, and exec.
+-3) void flush_cache_range(struct vm_area_struct *vma,
++2) void flush_cache_range(struct vm_area_struct *vma,
+                         unsigned long start, unsigned long end)
+       Here we are flushing a specific range of (user) virtual
+       addresses from the cache.  After running, there will be no
+       entries in the cache for 'vma->vm_mm' for virtual addresses in
+-      the range 'start' to 'end'.
++      the range 'start' to 'end-1'.
+       The "vma" is the backing store being used for the region.
+       Primarily, this is used for munmap() type operations.
+@@ -200,7 +192,7 @@ Here are the routines, one by one:
+       call flush_cache_page (see below) for each entry which may be
+       modified.
+-4) void flush_cache_page(struct vm_area_struct *vma, unsigned long addr)
++3) void flush_cache_page(struct vm_area_struct *vma, unsigned long addr)
+       This time we need to remove a PAGE_SIZE sized range
+       from the cache.  The 'vma' is the backing structure used by
+@@ -215,6 +207,30 @@ Here are the routines, one by one:
+       This is used primarily during fault processing.
++4) void flush_cache_kmaps(void)
++
++      This routine need only be implemented if the platform utilizes
++      highmem.  It will be called right before all of the kmaps
++      are invalidated.
++
++      After running, there will be no entries in the cache for
++      the kernel virtual address range PKMAP_ADDR(0) to
++      PKMAP_ADDR(LAST_PKMAP).
++
++      This routing should be implemented in asm/highmem.h
++
++5) void flush_cache_vmap(unsigned long start, unsigned long end)
++   void flush_cache_vunmap(unsigned long start, unsigned long end)
++
++      Here in these two interfaces we are flushing a specific range
++      of (kernel) virtual addresses from the cache.  After running,
++      there will be no entries in the cache for the kernel address
++      space for virtual addresses in the range 'start' to 'end-1'.
++
++      The first of these two routines is invoked after map_vm_area()
++      has installed the page table entries.  The second is invoked
++      before unmap_vm_area() deletes the page table entries.
++
+ There exists another whole class of cpu cache issues which currently
+ require a whole different set of interfaces to handle properly.
+ The biggest problem is that of virtual aliasing in the data cache
+@@ -317,6 +333,26 @@ maps this page at its virtual address.
+                       dirty.  Again, see sparc64 for examples of how
+                       to deal with this.
++  void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
++                         unsigned long user_vaddr,
++                         void *dst, void *src, int len)
++  void copy_from_user_page(struct vm_area_struct *vma, struct page *page,
++                           unsigned long user_vaddr,
++                           void *dst, void *src, int len)
++      When the kernel needs to copy arbitrary data in and out
++      of arbitrary user pages (f.e. for ptrace()) it will use
++      these two routines.
++
++      The page has been kmap()'d, and flush_cache_page() has
++      just been called for the user mapping of this page (if
++      necessary).
++
++      Any necessary cache flushing or other coherency operations
++      that need to occur should happen here.  If the processor's
++      instruction cache does not snoop cpu stores, it is very
++      likely that you will need to flush the instruction cache
++      for copy_to_user_page().
++
+   void flush_icache_range(unsigned long start, unsigned long end)
+       When the kernel stores into addresses that it will execute
+       out of (eg when loading modules), this function is called.
+@@ -324,17 +360,6 @@ maps this page at its virtual address.
+       If the icache does not snoop stores then this routine will need
+       to flush it.
+-  void flush_icache_user_range(struct vm_area_struct *vma,
+-                      struct page *page, unsigned long addr, int len)
+-      This is called when the kernel stores into addresses that are
+-      part of the address space of a user process (which may be some
+-      other process than the current process).  The addr argument
+-      gives the virtual address in that process's address space,
+-      page is the page which is being modified, and len indicates
+-      how many bytes have been modified.  The modified region must
+-      not cross a page boundary.  Currently this is only called from
+-      kernel/ptrace.c.
+-
+   void flush_icache_page(struct vm_area_struct *vma, struct page *page)
+       All the functionality of flush_icache_page can be implemented in
+       flush_dcache_page and update_mmu_cache. In 2.7 the hope is to
+--- linux-2.6.0-test6/Documentation/cpu-freq/user-guide.txt    2003-08-08 22:55:10.000000000 -0700
++++ 25/Documentation/cpu-freq/user-guide.txt   2003-10-05 00:33:23.000000000 -0700
+@@ -57,6 +57,8 @@ AMD mobile K6-2+
+ AMD mobile K6-3+
+ AMD mobile Duron
+ AMD mobile Athlon
++AMD Opteron
++AMD Athlon 64
+ Cyrix Media GXm
+ Intel mobile PIII and Intel mobile PIII-M on certain chipsets
+ Intel Pentium 4, Intel Xeon
+--- linux-2.6.0-test6/Documentation/crypto/api-intro.txt       2003-08-22 19:23:39.000000000 -0700
++++ 25/Documentation/crypto/api-intro.txt      2003-10-05 00:33:23.000000000 -0700
+@@ -126,7 +126,7 @@ might already be working on.
+ BUGS
+ Send bug reports to:
+-James Morris <jmorris@intercode.com.au>
++James Morris <jmorris@redhat.com>
+ Cc: David S. Miller <davem@redhat.com>
+@@ -220,5 +220,5 @@ CAST5 algorithm contributors:
+ Generic scatterwalk code by Adam J. Richter <adam@yggdrasil.com>
+ Please send any credits updates or corrections to:
+-James Morris <jmorris@intercode.com.au>
++James Morris <jmorris@redhat.com>
+--- linux-2.6.0-test6/Documentation/DocBook/kernel-api.tmpl    2003-09-27 18:57:43.000000000 -0700
++++ 25/Documentation/DocBook/kernel-api.tmpl   2003-10-05 00:33:23.000000000 -0700
+@@ -318,6 +318,5 @@ X!Idrivers/video/console/fonts.c
+ <!-- Needs ksyms to list additional exported symbols, but no specific doc.
+      docproc do not care about sgml commants.
+ !Dkernel/ksyms.c
+-!Dnet/netsyms.c
+ -->
+ </book>
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/Documentation/fb/neofb.txt      2003-10-05 00:34:22.000000000 -0700
+@@ -0,0 +1,27 @@
++the neofb framebuffer driver supports the following Neomagic chipsets:
++
++NM2070 MagicGraph 128
++NM2090 MagicGraph 128V
++NM2093 MagicGraph 128ZV
++NM2097 MagicGraph 128ZV+
++NM2160 MagicGraph 128XD
++NM2200 MagicGraph 256AV
++NM2230 MagicGraph 256AV+
++NM2360 MagicGraph 256ZX
++NM2380 MagicGraph 256XL+
++
++with the following options:
++
++disabled      Disable this driver's initialization.
++internal      Enable output on internal LCD Display.
++external      Enable output on external CRT.
++nostretch     Disable stretching of modes smaller than LCD.
++nopciburst    Disable PCI burst mode.
++libretto      Force Libretto 100/110 800x480 LCD.
++picturebook   Force Picturebook 1024x480 LCD.
++
++at the boot prompt:
++      video=neofb:picturebook
++
++as a module:
++      modprobe neofb picturebook=1
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/Documentation/i386/kgdb/andthen 2003-10-05 00:33:38.000000000 -0700
+@@ -0,0 +1,100 @@
++
++define        set_andthen
++      set var $thp=0
++      set var $thp=(struct kgdb_and_then_struct *)&kgdb_data[0]
++      set var $at_size = (sizeof kgdb_data)/(sizeof *$thp)
++      set var $at_oc=kgdb_and_then_count
++      set var $at_cc=$at_oc
++end
++
++define andthen_next
++      set var $at_cc=$arg0
++end
++
++define andthen
++      andthen_set_edge
++      if ($at_cc >= $at_oc)
++              printf "Outside window.  Window size is %d\n",($at_oc-$at_low)
++      else
++              printf "%d: ",$at_cc
++              output *($thp+($at_cc++ % $at_size ))
++              printf "\n"
++      end
++end
++define andthen_set_edge
++      set var $at_oc=kgdb_and_then_count
++      set var $at_low = $at_oc - $at_size
++      if ($at_low < 0 )
++              set var $at_low = 0
++      end
++      if (( $at_cc > $at_oc) || ($at_cc < $at_low))
++              printf "Count outside of window, setting count to "
++              if ($at_cc >= $at_oc)
++                      set var $at_cc = $at_oc
++              else
++                      set var $at_cc = $at_low
++              end
++              printf "%d\n",$at_cc
++      end
++end
++
++define beforethat
++      andthen_set_edge
++      if ($at_cc <= $at_low)
++              printf "Outside window.  Window size is %d\n",($at_oc-$at_low)
++      else
++              printf "%d: ",$at_cc-1
++              output *($thp+(--$at_cc % $at_size ))
++              printf "\n"
++      end
++end
++
++document andthen_next
++      andthen_next <count>
++      .       sets the number of the event to display next. If this event
++      .       is not in the event pool, either andthen or beforethat will
++      .       correct it to the nearest event pool edge.  The event pool
++      .       ends at the last event recorded and begins <number of events>
++      .       prior to that.  If beforethat is used next, it will display
++      .       event <count> -1.
++.
++      andthen commands are: set_andthen, andthen_next, andthen and beforethat
++end
++
++
++document andthen
++      andthen
++.     displays the next event in the list.  <set_andthen> sets up to display
++.     the oldest saved event first.
++.     <count> (optional) count of the event to display.
++.     note the number of events saved is specified at configure time.
++.     if events are saved between calls to andthen the index will change
++.     but the displayed event will be the next one (unless the event buffer
++.     is overrun).
++.
++.     andthen commands are: set_andthen, andthen_next, andthen and beforethat
++end
++
++document set_andthen
++      set_andthen
++.     sets up to use the <andthen> and <beforethat> commands.
++.             if you have defined your own struct, use the above and
++.             then enter the following:
++.             p $thp=(struct kgdb_and_then_structX *)&kgdb_data[0]
++.             where <kgdb_and_then_structX> is the name of your structure.
++.
++.     andthen commands are: set_andthen, andthen_next, andthen and beforethat
++end
++
++document beforethat
++      beforethat
++.     displays the next prior event in the list. <set_andthen> sets up to
++.     display the last occuring event first.
++.
++.     note the number of events saved is specified at configure time.
++.     if events are saved between calls to beforethat the index will change
++.     but the displayed event will be the next one (unless the event buffer
++.     is overrun).
++.
++.     andthen commands are: set_andthen, andthen_next, andthen and beforethat
++end
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/Documentation/i386/kgdb/debug-nmi.txt   2003-10-05 00:33:38.000000000 -0700
+@@ -0,0 +1,37 @@
++Subject: Debugging with NMI
++Date: Mon, 12 Jul 1999 11:28:31 -0500
++From: David Grothe <dave@gcom.com>
++Organization: Gcom, Inc
++To: David Grothe <dave@gcom.com>
++
++Kernel hackers:
++
++Maybe this is old hat, but it is new to me --
++
++On an ISA bus machine, if you short out the A1 and B1 pins of an ISA
++slot you will generate an NMI to the CPU.  This interrupts even a
++machine that is hung in a loop with interrupts disabled.  Used in
++conjunction with kgdb <
++ftp://ftp.gcom.com/pub/linux/src/kgdb-2.3.35/kgdb-2.3.35.tgz > you can
++gain debugger control of a machine that is hung in the kernel!  Even
++without kgdb the kernel will print a stack trace so you can find out
++where it was hung.
++
++The A1/B1 pins are directly opposite one another and the farthest pins
++towards the bracket end of the ISA bus socket.  You can stick a paper
++clip or multi-meter probe between them to short them out.
++
++I had a spare ISA bus to PC104 bus adapter around.  The PC104 end of the
++board consists of two rows of wire wrap pins.  So I wired a push button
++between the A1/B1 pins and now have an ISA board that I can stick into
++any ISA bus slot for debugger entry.
++
++Microsoft has a circuit diagram of a PCI card at
++http://www.microsoft.com/hwdev/DEBUGGING/DMPSW.HTM.  If you want to
++build one you will have to mail them and ask for the PAL equations.
++Nobody makes one comercially.
++
++[THIS TIP COMES WITH NO WARRANTY WHATSOEVER.  It works for me, but if
++your machine catches fire, it is your problem, not mine.]
++
++-- Dave (the kgdb guy)
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/Documentation/i386/kgdb/gdb-globals.txt 2003-10-05 00:33:38.000000000 -0700
+@@ -0,0 +1,71 @@
++Sender: akale@veritas.com
++Date: Fri, 23 Jun 2000 19:26:35 +0530
++From: "Amit S. Kale" <akale@veritas.com>
++Organization: Veritas Software (India)
++To: Dave Grothe <dave@gcom.com>, linux-kernel@vger.rutgers.edu
++CC: David Milburn <dmilburn@wirespeed.com>,
++        "Edouard G. Parmelan" <Edouard.Parmelan@quadratec.fr>,
++        ezannoni@cygnus.com, Keith Owens <kaos@ocs.com.au>
++Subject: Re: Module debugging using kgdb
++
++Dave Grothe wrote:
++>
++> Amit:
++>
++> There is a 2.4.0 version of kgdb on our ftp site:
++> ftp://ftp.gcom.com/pub/linux/src/kgdb.  I mirrored your version of gdb
++> and loadmodule.sh there.
++>
++> Have a look at the README file and see if I go it right.  If not, send
++> me some corrections and I will update it.
++>
++> Does your version of gdb solve the global variable problem?
++
++Yes.
++Thanks to Elena Zanoni, gdb (developement version) can now calculate
++correctly addresses  of dynamically loaded object files. I have not been
++following gdb developement for sometime and am not sure when symbol
++address calculation fix is going to appear in a gdb stable version.
++
++Elena, any idea when the fix will make it to a prebuilt gdb from a
++redhat release?
++
++For the time being I have built a gdb developement version. It can be
++used for module debugging with loadmodule.sh script.
++
++The problem with calculating of module addresses with previous versions
++of gdb was as follows:
++gdb did not use base address of a section while calculating address of
++a symbol in the section in an object file loaded via 'add-symbol-file'.
++It used address of .text segment instead. Due to this addresses of
++symbols in .data, .bss etc. (e.g. global variables) were calculated incorrectly.
++
++Above mentioned fix allow gdb to use base address of a segment while
++calculating address of a symbol in it. It adds a parameter '-s' to
++'add-symbol-file' command for specifying base address of a segment.
++
++loadmodule.sh script works as follows.
++
++1. Copy a module file to target machine.
++2. Load the module on the target machine using insmod with -m parameter.
++insmod produces a module load map which contains base addresses of all
++sections in the module and addresses of symbols in the module file.
++3. Find all sections and their base addresses in the module from
++the module map.
++4. Generate a script that loads the module file. The script uses
++'add-symbol-file' and specifies address of text segment followed by
++addresses of all segments in the module.
++
++Here is an example gdb script produced by loadmodule.sh script.
++
++add-symbol-file foo 0xd082c060 -s .text.lock 0xd08cbfb5
++-s .fixup 0xd08cfbdf -s .rodata 0xd08cfde0 -s __ex_table 0xd08e3b38
++-s .data 0xd08e3d00 -s .bss 0xd08ec8c0 -s __ksymtab 0xd08ee838
++
++With this command gdb can calculate addresses of symbols in ANY segment
++in a module file.
++
++Regards.
++--
++Amit Kale
++Veritas Software ( http://www.veritas.com )
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/Documentation/i386/kgdb/gdbinit 2003-10-05 00:33:38.000000000 -0700
+@@ -0,0 +1,14 @@
++shell echo -e "\003" >/dev/ttyS0
++set remotebaud 38400
++target remote /dev/ttyS0
++define si
++stepi
++printf "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n", $eax, $ebx, $ecx, $edx
++printf "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n", $esi, $edi, $ebp, $esp
++x/i $eip
++end
++define ni
++nexti
++printf "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n", $eax, $ebx, $ecx, $edx
++printf "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n", $esi, $edi, $ebp, $esp
++x/i $eip
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/Documentation/i386/kgdb/gdbinit.hw      2003-10-05 00:33:38.000000000 -0700
+@@ -0,0 +1,117 @@
++
++#Using ia-32 hardware breakpoints.
++#
++#4 hardware breakpoints are available in ia-32 processors. These breakpoints
++#do not need code modification. They are set using debug registers.
++#
++#Each hardware breakpoint can be of one of the
++#three types: execution, write, access.
++#1. An Execution breakpoint is triggered when code at the breakpoint address is
++#executed.
++#2. A write breakpoint ( aka watchpoints ) is triggered when memory location
++#at the breakpoint address is written.
++#3. An access breakpoint is triggered when memory location at the breakpoint
++#address is either read or written.
++#
++#As hardware breakpoints are available in limited number, use software
++#breakpoints ( br command in gdb ) instead of execution hardware breakpoints.
++#
++#Length of an access or a write breakpoint defines length of the datatype to
++#be watched. Length is 1 for char, 2 short , 3 int.
++#
++#For placing execution, write and access breakpoints, use commands
++#hwebrk, hwwbrk, hwabrk
++#To remove a breakpoint use hwrmbrk command.
++#
++#These commands take following types of arguments. For arguments associated
++#with each command, use help command.
++#1. breakpointno: 0 to 3
++#2. length: 1 to 3
++#3. address: Memory location in hex ( without 0x ) e.g c015e9bc
++#
++#Use the command exinfo to find which hardware breakpoint occured.
++
++#hwebrk breakpointno address
++define hwebrk
++      maintenance packet Y$arg0,0,0,$arg1
++end
++document hwebrk
++      hwebrk <breakpointno> <address>
++      Places a hardware execution breakpoint
++      <breakpointno> = 0 - 3
++      <address> = Hex digits without leading "0x".
++end
++
++#hwwbrk breakpointno length address
++define hwwbrk
++      maintenance packet Y$arg0,1,$arg1,$arg2
++end
++document hwwbrk
++      hwwbrk <breakpointno> <length> <address>
++      Places a hardware write breakpoint
++      <breakpointno> = 0 - 3
++      <length> = 1 (1 byte), 2 (2 byte), 3 (4 byte)
++      <address> = Hex digits without leading "0x".
++end
++
++#hwabrk breakpointno length address
++define hwabrk
++      maintenance packet Y$arg0,1,$arg1,$arg2
++end
++document hwabrk
++      hwabrk <breakpointno> <length> <address>
++      Places a hardware access breakpoint
++      <breakpointno> = 0 - 3
++      <length> = 1 (1 byte), 2 (2 byte), 3 (4 byte)
++      <address> = Hex digits without leading "0x".
++end
++
++#hwrmbrk breakpointno
++define hwrmbrk
++      maintenance packet y$arg0
++end
++document hwrmbrk
++      hwrmbrk <breakpointno>
++      <breakpointno> = 0 - 3
++      Removes a hardware breakpoint
++end
++
++define reboot
++        maintenance packet r
++end
++#exinfo
++define exinfo
++      maintenance packet qE
++end
++document exinfo
++      exinfo
++      Gives information about a breakpoint.
++end
++define get_th
++      p $th=(struct thread_info *)((int)$esp & ~8191)
++end
++document get_th
++      get_tu
++      Gets and prints the current thread_info pointer, Defines th to be it.
++end
++define get_cu
++      p $cu=((struct thread_info *)((int)$esp & ~8191))->task
++end
++document get_cu
++      get_cu
++      Gets and print the "current" value.  Defines $cu to be it.
++end
++define int_off
++      set var $flags=$eflags
++      set $eflags=$eflags&~0x200
++      end
++define int_on
++      set var $eflags|=$flags&0x200
++      end
++document int_off
++      saves the current interrupt state and clears the processor interrupt
++      flag.  Use int_on to restore the saved flag.
++end
++document int_on
++      Restores the interrupt flag saved by int_off.
++end
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/Documentation/i386/kgdb/gdbinit-modules 2003-10-05 00:33:38.000000000 -0700
+@@ -0,0 +1,146 @@
++#
++# Usefull GDB user-command to debug Linux Kernel Modules with gdbstub.
++#
++# This don't work for Linux-2.0 or older.
++#
++# Author Edouard G. Parmelan <Edouard.Parmelan@quadratec.fr>
++#
++#
++# Fri Apr 30 20:33:29 CEST 1999
++#   First public release.
++#
++#   Major cleanup after experiment Linux-2.0 kernel without success.
++#   Symbols of a module are not in the correct order, I can't explain
++#   why :(
++#
++# Fri Mar 19 15:41:40 CET 1999
++#   Initial version.
++#
++# Thu Jan  6 16:29:03 CST 2000
++#   A little fixing by Dave Grothe <dave@gcom.com>
++#
++# Mon Jun 19 09:33:13 CDT 2000
++#   Alignment changes from Edouard Parmelan
++#
++# The basic idea is to find where insmod load the module and inform
++# GDB to load the symbol table of the module with the GDB command
++# ``add-symbol-file <object> <address>''.
++#
++# The Linux kernel holds the list of all loaded modules in module_list,
++# this list end with &kernel_module (exactly with module->next == NULL,
++# but the last module is not a real module).
++#
++# Insmod allocates the struct module before the object file.  Since
++# Linux-2.1, this structure contain his size.  The real address of
++# the object file is then (char*)module + module->size_of_struct.
++#
++# You can use three user functions ``mod-list'', ``mod-print-symbols''
++# and ``add-module-symbols''.
++#
++# mod-list list all loaded modules with the format:
++#    <module-address> <module-name>
++#
++# As soon as you have found the address of your module, you can
++# print its exported symbols (mod-print-symbols) or inform GDB to add
++# symbols from your module file (mod-add-symbols).
++#
++# The argument that you give to mod-print-symbols or mod-add-symbols
++# is the <module-address> from the mod-list command.
++#
++# When using the mod-add-symbols command you must also give the full
++# pathname of the modules object code file.
++#
++# The command mod-add-lis is an example of how to make this easier.
++# You can edit this macro to contain the path name of your own
++# favorite module and then use it as a shorthand to load it.  You
++# still need the module-address, however.
++#
++# The internal function ``mod-validate'' set the GDB variable $mod
++# as a ``struct module*'' if the kernel known the module otherwise
++# $mod is set to NULL.  This ensure to not add symbols for a wrong
++# address.
++#
++# Have a nice hacking day !
++#
++#
++define mod-list
++    set $mod = (struct module*)module_list
++    # the last module is the kernel, ignore it
++    while $mod != &kernel_module
++      printf "%p\t%s\n", (long)$mod, ($mod)->name
++      set $mod = $mod->next
++    end
++end
++document mod-list
++List all modules in the form: <module-address> <module-name>
++Use the <module-address> as the argument for the other
++mod-commands: mod-print-symbols, mod-add-symbols.
++end
++
++define mod-validate
++    set $mod = (struct module*)module_list
++    while ($mod != $arg0) && ($mod != &kernel_module)
++      set $mod = $mod->next
++    end
++    if $mod == &kernel_module
++      set $mod = 0
++      printf "%p is not a module\n", $arg0
++    end
++end
++document mod-validate
++mod-validate <module-address>
++Internal user-command used to validate the module parameter.
++If <module> is a real loaded module, set $mod to it otherwise set $mod to 0.
++end
++
++
++define mod-print-symbols
++    mod-validate $arg0
++    if $mod != 0
++      set $i = 0
++      while $i < $mod->nsyms
++          set $sym = $mod->syms[$i]
++          printf "%p\t%s\n", $sym->value, $sym->name
++          set $i = $i + 1
++      end
++    end
++end
++document mod-print-symbols
++mod-print-symbols <module-address>
++Print all exported symbols of the module.  see mod-list
++end
++
++
++define mod-add-symbols-align
++    mod-validate $arg0
++    if $mod != 0
++      set $mod_base = ($mod->size_of_struct + (long)$mod)
++      if ($arg2 != 0) && (($mod_base & ($arg2 - 1)) != 0)
++          set $mod_base = ($mod_base | ($arg2 - 1)) + 1
++      end
++      add-symbol-file $arg1 $mod_base
++    end
++end
++document mod-add-symbols-align
++mod-add-symbols-align <module-address> <object file path name> <align>
++Load the symbols table of the module from the object file where
++first section aligment is <align>.
++To retreive alignment, use `objdump -h <object file path name>'.
++end
++
++define mod-add-symbols
++    mod-add-symbols-align $arg0 $arg1 sizeof(long)
++end
++document mod-add-symbols
++mod-add-symbols <module-address> <object file path name>
++Load the symbols table of the module from the object file.
++Default alignment is 4.  See mod-add-symbols-align.
++end
++
++define mod-add-lis
++    mod-add-symbols-align $arg0 /usr/src/LiS/streams.o 16
++end
++document mod-add-lis
++mod-add-lis <module-address>
++Does mod-add-symbols <module-address> /usr/src/LiS/streams.o
++end
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/Documentation/i386/kgdb/kgdbeth.txt     2003-10-05 00:33:46.000000000 -0700
+@@ -0,0 +1,118 @@
++KGDB over ethernet
++==================
++
++Authors
++-------
++
++Robert Walsh <rjwalsh@durables.org>  (2.6 port)
++wangdi <wangdi@clusterfs.com>        (2.6 port)
++San Mehat                            (original 2.4 code)
++
++
++Introduction
++------------
++
++KGDB supports debugging over ethernet.  Only a limited set of ethernet
++devices are supported right now, but adding support for new devices
++should not be too complicated.  See "New Devices" below for details.
++
++
++Terminology
++-----------
++
++This document uses the following terms:
++
++  TARGET: the machine being debugged.
++  HOST:   the machine running gdb.
++
++
++Usage
++-----
++
++You need to use the following command-line options on the TARGET kernel:
++
++  gdbeth=DEVICENUM
++  gdbeth_remoteip=HOSTIPADDR
++  gdbeth_remotemac=REMOTEMAC
++  gdbeth_localmac=LOCALMAC
++
++kgdbeth=DEVICENUM sets the ethernet device number to listen on for
++debugging packets.  e.g. kgdbeth=0 listens on eth0.
++
++kgdbeth_remoteip=HOSTIPADDR sets the IP address of the HOST machine.
++Only packets originating from this IP address will be accepted by the
++debugger.  e.g. kgdbeth_remoteip=192.168.2.2
++
++kgdbeth_remotemac=REMOTEMAC sets the ethernet address of the HOST machine.
++e.g. kgdbeth_remotemac=00:07:70:12:4E:F5
++
++kgdbeth_localmac=LOCALMAC sets the ethernet address of the TARGET machine.
++e.g. kgdbeth_localmac=00:10:9F:18:21:3C
++
++You can also set the following command-line option on the TARGET kernel:
++
++  kgdbeth_listenport=PORT
++
++kgdbeth_listenport sets the UDP port to listen on for gdb debugging
++packets.  The default value is "6443".  e.g. kgdbeth_listenport=7654
++causes the kernel to listen on UDP port 7654 for debugging packets.
++
++On the HOST side, run gdb as normal and use a remote UDP host as the
++target:
++
++   % gdb ./vmlinux
++   GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)
++   Copyright 2003 Free Software Foundation, Inc.
++   GDB is free software, covered by the GNU General Public License, and you are
++   welcome to change it and/or distribute copies of it under certain conditions.
++   Type "show copying" to see the conditions.
++   There is absolutely no warranty for GDB.  Type "show warranty" for details.
++   This GDB was configured as "i386-redhat-linux-gnu"...
++   (gdb) target remote udp:HOSTNAME:6443
++
++You can now continue as if you were debugging over a serial line.
++
++Observations
++------------
++
++I've used this with NFS and various other network applications (ssh,
++etc.) and it's doesn't appear to interfere with their operation in
++any way.  It doesn't seem to effect the NIC it uses - i.e. you don't
++need a dedicated NIC for this.
++
++Limitations
++-----------
++
++In the inital release of this code you _must_ break into the system with the
++debugger by hand, early after boot, as described above.
++
++Otherwise, the first time the kernel tries to enter the debugger (say, via an
++oops or a BUG), the kgdb stub will doublefault and die because things aren't
++fully set up yet.
++
++Supported devices
++-----------------
++
++Right now, the following drivers are supported:
++
++  e100 driver (drivers/net/e100/*)
++  3c59x driver (drivers/net/3c59x.c)
++
++
++New devices
++-----------
++
++Supporting a new device is straightforward.  Just add a "poll" routine to
++the driver and hook it into the poll_controller field in the netdevice
++structure.  For an example, look in drivers/net/3c59x.c and search
++for CONFIG_KGDB (two places.)
++
++The poll routine is usually quite simple - it's usually enough to just
++disable interrupts, call the device's interrupt routine and re-enable
++interrupts again.
++
++
++Bug reports
++-----------
++
++Send bug reports to Robert Walsh <rjwalsh@durables.org>.
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/Documentation/i386/kgdb/kgdb.txt        2003-10-05 00:33:38.000000000 -0700
+@@ -0,0 +1,775 @@
++Last edit: <20030806.1637.12>
++This file has information specific to the i386 kgdb option.  Other
++platforms with the kgdb option may behave in a similar fashion.
++
++New features:
++============
++20030806.1557.37
++This version was made against the 2.6.0-test2 kernel. We have made the
++following changes:
++
++- The getthread() code in the stub calls find_task_by_pid().  It fails
++  if we are early in the bring up such that the pid arrays have yet to
++  be allocated.  We have added a line to kernel/pid.c to make
++  "kgdb_pid_init_done" true once the arrays are allocated.  This way the
++  getthread() code knows not to call.  This is only used by the thread
++  debugging stuff and threads will not yet exist at this point in the
++  boot.
++
++- For some reason, gdb was not asking for a new thread list when the
++  "info thread" command was given.  We changed to the newer version of
++  the thread info command and gdb now seems to ask when needed.  Result,
++  we now get all threads in the thread list.
++
++- We now respond to the ThreadExtraInfo request from gdb with the thread
++  name from task_struct .comm.  This then appears in the thread list.
++  Thoughts on additional options for this are welcome.  Things such as
++  "has BKL" and "Preempted" come to mind.  I think we could have a flag
++  word that could enable different bits of info here.
++
++- We now honor, sort of, the C and S commands.  These are continue and
++  single set after delivering a signal.  We ignore the signal and do the
++  requested action.  This only happens when we told gdb that a signal
++  was the reason for entry, which is only done on memory faults.  The
++  result is that you can now continue into the Oops.
++
++- We changed the -g to -gdwarf-2.  This seems to be the same as -ggdb,
++  but it is more exact on what language to use.
++
++- We added two dwarf2 include files and a bit of code at the end of
++  entry.S.  This does not yet work, so it is disabled.  Still we want to
++  keep track of the code and "maybe" someone out there can fix it.
++
++- Randy Dunlap sent some fix ups for this file which are now merged.
++
++- Hugh Dickins sent a fix to a bit of code in traps.c that prevents a
++  compiler warning if CONFIG_KGDB is off (now who would do that :).
++
++- Andrew Morton sent a fix for the serial driver which is now merged.
++
++- Andrew also sent a change to the stub around the cpu managment code
++  which is also merged.
++
++- Andrew also sent a patch to make "f" as well as "g" work as SysRq
++  commands to enter kgdb, merged.
++
++- If CONFIG_KGDB and CONFIG_DEBUG_SPINLOCKS are both set we added a
++  "who" field to the spinlock data struct.  This is filled with
++  "current" when ever the spinlock suceeds.  Useful if you want to know
++  who has the lock.
++
++_ And last, but not least, we fixed the "get_cu" macro to properly get
++  the current value of "current".
++
++New features:
++============
++20030505.1827.27
++We are starting to align with the sourceforge version, at least in
++commands.  To this end, the boot command string to start kgdb at
++boot time has been changed from "kgdb" to "gdb".
++
++Andrew Morton sent a couple of patches which are now included as follows:
++1.) We now return a flag to the interrupt handler.
++2.) We no longer use smp_num_cpus (a conflict with the lock meter).
++3.) And from William Lee Irwin III <wli@holomorphy.com> code to make
++    sure high-mem is set up before we attempt to register our interrupt
++    handler.
++We now include asm/kgdb.h from config.h so you will most likely never
++have to include it.  It also 'NULLS' the kgdb macros you might have in
++your code when CONFIG_KGDB is not defined.  This allows you to just
++turn off CONFIG_KGDB to turn off all the kgdb_ts() calls and such.
++This include is conditioned on the machine being an x86 so as to not
++mess with other archs.
++
++20020801.1129.03
++This is currently the version for the 2.4.18 (and beyond?) kernel.
++
++We have several new "features" beginning with this version:
++
++1.) Kgdb now syncs the "other" CPUs with a cross-CPU NMI.  No more
++    waiting and it will pull that guy out of an IRQ off spin lock :)
++
++2.) We doctored up the code that tells where a task is waiting and
++    included it so that the "info thread" command will show a bit more
++    than "schedule()".  Try it...
++
++3.) Added the ability to call a function from gdb.  All the standard gdb
++    issues apply, i.e. if you hit a breakpoint in the function, you are
++    not allowed to call another (gdb limitation, not kgdb).  To help
++    this capability we added a memory allocation function.  Gdb does not
++    return this memory (it is used for strings that you pass to that function
++    you are calling from gdb) so we fixed up a way to allow you to
++    manually return the memory (see below).
++
++4.) Kgdb time stamps (kgdb_ts()) are enhanced to expand what was the
++    interrupt flag to now also include the preemption count and the
++    "in_interrupt" info.  The flag is now called "with_pif" to indicate
++    the order, preempt_count, in_interrupt, flag.  The preempt_count is
++    shifted left by 4 bits so you can read the count in hex by dropping
++    the low order digit.  In_interrupt is in bit 1, and the flag is in
++    bit 0.
++
++5.) The command: "p kgdb_info" is now expanded and prints something
++    like:
++(gdb) p kgdb_info
++$2 = {used_malloc = 0, called_from = 0xc0107506, entry_tsc = 67468627259,
++  errcode = 0, vector = 3, print_debug_info = 0, hold_on_sstep = 1,
++  cpus_waiting = {{task = 0xc027a000, pid = 32768, hold = 0,
++      regs = 0xc027bf84}, {task = 0x0, pid = 0, hold = 0, regs = 0x0}}}
++
++    Things to note here: a.) used_malloc is the amount of memory that
++    has been malloc'ed to do calls from gdb.  You can reclaim this
++    memory like this: "p kgdb_info.used_malloc=0" Cool, huh?  b.)
++    cpus_waiting is now "sized" by the number of CPUs you enter at
++    configure time in the kgdb configure section.  This is NOT used
++    anywhere else in the system, but it is "nice" here.  c.)  The task's
++    "pid" is now in the structure.  This is the pid you will need to use
++    to decode to the thread id to get gdb to look at that thread.
++    Remember that the "info thread" command prints a list of threads
++    wherein it numbers each thread with its reference number followed
++    by the thread's pid.  Note that the per-CPU idle threads actually
++    have pids of 0 (yes, there is more than one pid 0 in an SMP system).
++    To avoid confusion, kgdb numbers these threads with numbers beyond
++    the MAX_PID.  That is why you see 32768 and above.
++
++6.) A subtle change, we now provide the complete register set for tasks
++    that are active on the other CPUs.  This allows better trace back on
++    those tasks.
++
++    And, let's mention what we could not fix.  Back-trace from all but the
++    thread that we trapped will, most likely, have a bogus entry in it.
++    The problem is that gdb does not recognize the entry code for
++    functions that use "current" near (at all?) the entry.  The compiler
++    is putting the "current" decode as the first two instructions of the
++    function where gdb expects to find %ebp changing code.  Back trace
++    also has trouble with interrupt frames.  I am talking with Daniel
++    Jacobowitz about some way to fix this, but don't hold your breath.
++
++20011220.0050.35
++Major enhancement with this version is the ability to hold one or more
++CPUs in an SMP system while allowing the others to continue.  Also, by
++default only the current CPU is enabled on single-step commands (please
++note that gdb issues single-step commands at times other than when you
++use the si command).
++
++Another change is to collect some useful information in
++a global structure called "kgdb_info".  You should be able to just:
++
++p kgdb_info
++
++although I have seen cases where the first time this is done gdb just
++prints the first member but prints the whole structure if you then enter
++CR (carriage return or enter).  This also works:
++
++p *&kgdb_info
++
++Here is a sample:
++(gdb) p kgdb_info
++$4 = {called_from = 0xc010732c, entry_tsc = 32804123790856, errcode = 0,
++  vector = 3, print_debug_info = 0}
++
++"Called_from" is the return address from the current entry into kgdb.
++Sometimes it is useful to know why you are in kgdb, for example, was
++it an NMI or a real breakpoint?  The simple way to interrogate this
++return address is:
++
++l *0xc010732c
++
++which will print the surrounding few lines of source code.
++
++"Entry_tsc" is the CPU TSC on entry to kgdb (useful to compare to the
++kgdb_ts entries).
++
++"errcode" and "vector" are other entry parameters which may be helpful on
++some traps.
++
++"print_debug_info" is the internal debugging kgdb print enable flag.  Yes,
++you can modify it.
++
++In SMP systems kgdb_info also includes the "cpus_waiting" structure and
++"hold_on_step":
++
++(gdb) p kgdb_info
++$7 = {called_from = 0xc0112739, entry_tsc = 1034936624074, errcode = 0,
++  vector = 2, print_debug_info = 0, hold_on_sstep = 1, cpus_waiting = {{
++      task = 0x0, hold = 0, regs = 0x0}, {task = 0xc71b8000, hold = 0,
++      regs = 0xc71b9f70}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0,
++      hold = 0, regs = 0x0}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0,
++      hold = 0, regs = 0x0}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0,
++      hold = 0, regs = 0x0}}}
++
++"Cpus_waiting" has an entry for each CPU other than the current one that
++has been stopped.  Each entry contains the task_struct address for that
++CPU, the address of the regs for that task and a hold flag.  All these
++have the proper typing so that, for example:
++
++p *kgdb_info.cpus_waiting[1].regs
++
++will print the registers for CPU 1.
++
++"Hold_on_sstep" is a new feature with this version and comes up set or
++true.  What this means is that whenever kgdb is asked to single-step all
++other CPUs are held (i.e. not allowed to execute).  The flag applies to
++all but the current CPU and, again, can be changed:
++
++p kgdb_info.hold_on_sstep=0
++
++restores the old behavior of letting all CPUs run during single-stepping.
++
++Likewise, each CPU has a "hold" flag, which if set, locks that CPU out
++of execution.  Note that this has some risk in cases where the CPUs need
++to communicate with each other.  If kgdb finds no CPU available on exit,
++it will push a message thru gdb and stay in kgdb.  Note that it is legal
++to hold the current CPU as long as at least one CPU can execute.
++
++20010621.1117.09
++This version implements an event queue.  Events are signaled by calling
++a function in the kgdb stub and may be examined from gdb.  See EVENTS
++below for details.  This version also tightens up the interrupt and SMP
++handling to not allow interrupts on the way to kgdb from a breakpoint
++trap.  It is fine to allow these interrupts for user code, but not
++system debugging.
++
++Version
++=======
++
++This version of the kgdb package was developed and tested on
++kernel version 2.4.16.  It will not install on any earlier kernels.
++It is possible that it will continue to work on later versions
++of 2.4 and then versions of 2.5 (I hope).
++
++
++Debugging Setup
++===============
++
++Designate one machine as the "development" machine.  This is the
++machine on which you run your compiles and which has your source
++code for the kernel.  Designate a second machine as the "target"
++machine.  This is the machine that will run your experimental
++kernel.
++
++The two machines will be connected together via a serial line out
++one or the other of the COM ports of the PC.  You will need the
++appropriate modem eliminator (null modem) cable(s) for this.
++
++Decide on which tty port you want the machines to communicate, then
++connect them up back-to-back using the null modem cable.  COM1 is
++/dev/ttyS0 and COM2 is /dev/ttyS1. You should test this connection
++with the two machines prior to trying to debug a kernel.  Once you
++have it working, on the TARGET machine, enter:
++
++setserial /dev/ttyS0 (or what ever tty you are using)
++
++and record the port address and the IRQ number.
++
++On the DEVELOPMENT machine you need to apply the patch for the kgdb
++hooks.  You have probably already done that if you are reading this
++file.
++
++On your DEVELOPMENT machine, go to your kernel source directory and do
++"make Xconfig" where X is one of "x", "menu", or "".  If you are
++configuring in the standard serial driver, it must not be a module.
++Either yes or no is ok, but making the serial driver a module means it
++will initialize after kgdb has set up the UART interrupt code and may
++cause a failure of the control-C option discussed below.  The configure
++question for the serial driver is under the "Character devices" heading
++and is:
++
++"Standard/generic (8250/16550 and compatible UARTs) serial support"
++
++Go down to the kernel debugging menu item and open it up.  Enable the
++kernel kgdb stub code by selecting that item.  You can also choose to
++turn on the "-ggdb -O1" compile options.  The -ggdb causes the compiler
++to put more debug info (like local symbols) in the object file.  On the
++i386 -g and -ggdb are the same so this option just reduces to "O1".  The
++-O1 reduces the optimization level.  This may be helpful in some cases,
++be aware, however, that this may also mask the problem you are looking
++for.
++
++The baud rate.  Default is 115200.  What ever you choose be sure that
++the host machine is set to the same speed.  I recommend the default.
++
++The port.  This is the I/O address of the serial UART that you should
++have gotten using setserial as described above.  The standard COM1 port
++(3f8) using IRQ 4 is default.  COM2 is 2f8 which by convention uses IRQ
++3.
++
++The port IRQ (see above).
++
++Stack overflow test.  This option makes a minor change in the trap,
++system call and interrupt code to detect stack overflow and transfer
++control to kgdb if it happens.  (Some platforms have this in the
++baseline code, but the i386 does not.)
++
++You can also configure the system to recognize the boot option
++"console=kgdb" which if given will cause all console output during
++booting to be put thru gdb as well as other consoles.  This option
++requires that gdb and kgdb be connected prior to sending console output
++so, if they are not, a breakpoint is executed to force the connection.
++This will happen before any kernel output (it is going thru gdb, right),
++and will stall the boot until the connection is made.
++
++You can also configure in a patch to SysRq to enable the kGdb SysRq.
++This request generates a breakpoint.  Since the serial port IRQ line is
++set up after any serial drivers, it is possible that this command will
++work when the control-C will not.
++
++Save and exit the Xconfig program.  Then do "make clean" , "make dep"
++and "make bzImage" (or whatever target you want to make).  This gets the
++kernel compiled with the "-g" option set -- necessary for debugging.
++
++You have just built the kernel on your DEVELOPMENT machine that you
++intend to run on your TARGET machine.
++
++To install this new kernel, use the following installation procedure.
++Remember, you are on the DEVELOPMENT machine patching the kernel source
++for the kernel that you intend to run on the TARGET machine.
++
++Copy this kernel to your target machine using your usual procedures.  I
++usually arrange to copy development:
++/usr/src/linux/arch/i386/boot/bzImage to /vmlinuz on the TARGET machine
++via a LAN based NFS access.  That is, I run the cp command on the target
++and copy from the development machine via the LAN.  Run Lilo (see "man
++lilo" for details on how to set this up) on the new kernel on the target
++machine so that it will boot!  Then boot the kernel on the target
++machine.
++
++On the DEVELOPMENT machine, create a file called .gdbinit in the
++directory /usr/src/linux.  An example .gdbinit file looks like this:
++
++shell echo -e "\003" >/dev/ttyS0
++set remotebaud 38400 (or what ever speed you have chosen)
++target remote /dev/ttyS0
++
++
++Change the "echo" and "target" definition so that it specifies the tty
++port that you intend to use.  Change the "remotebaud" definition to
++match the data rate that you are going to use for the com line.
++
++You are now ready to try it out.
++
++Boot your target machine with "kgdb" in the boot command i.e. something
++like:
++
++lilo> test kgdb
++
++or if you also want console output thru gdb:
++
++lilo> test kgdb console=kgdb
++
++You should see the lilo message saying it has loaded the kernel and then
++all output stops.  The kgdb stub is trying to connect with gdb.  Start
++gdb something like this:
++
++
++On your DEVELOPMENT machine, cd /usr/src/linux and enter "gdb vmlinux".
++When gdb gets the symbols loaded it will read your .gdbinit file and, if
++everything is working correctly, you should see gdb print out a few
++lines indicating that a breakpoint has been taken.  It will actually
++show a line of code in the target kernel inside the kgdb activation
++code.
++
++The gdb interaction should look something like this:
++
++    linux-dev:/usr/src/linux# gdb vmlinux
++    GDB is free software and you are welcome to distribute copies of it
++     under certain conditions; type "show copying" to see the conditions.
++    There is absolutely no warranty for GDB; type "show warranty" for details.
++    GDB 4.15.1 (i486-slackware-linux),
++    Copyright 1995 Free Software Foundation, Inc...
++    breakpoint () at i386-stub.c:750
++    750     }
++    (gdb)
++
++You can now use whatever gdb commands you like to set breakpoints.
++Enter "continue" to start your target machine executing again.  At this
++point the target system will run at full speed until it encounters
++your breakpoint or gets a segment violation in the kernel, or whatever.
++
++If you have the kgdb console enabled when you continue, gdb will print
++out all the console messages.
++
++The above example caused a breakpoint relatively early in the boot
++process.  For the i386 kgdb it is possible to code a break instruction
++as the first C-language point in init/main.c, i.e. as the first instruction
++in start_kernel().  This could be done as follows:
++
++#include <asm/kgdb.h>
++       breakpoint();
++
++This breakpoint() is really a function that sets up the breakpoint and
++single-step hardware trap cells and then executes a breakpoint.  Any
++early hard coded breakpoint will need to use this function.  Once the
++trap cells are set up they need not be set again, but doing it again
++does not hurt anything, so you don't need to be concerned about which
++breakpoint is hit first.  Once the trap cells are set up (and the kernel
++sets them up in due course even if breakpoint() is never called) the
++macro:
++
++BREAKPOINT;
++
++will generate an inline breakpoint.  This may be more useful as it stops
++the processor at the instruction instead of in a function a step removed
++from the location of interest.  In either case <asm/kgdb.h> must be
++included to define both breakpoint() and BREAKPOINT.
++
++Triggering kgdbstub at other times
++==================================
++
++Often you don't need to enter the debugger until much later in the boot
++or even after the machine has been running for some time.  Once the
++kernel is booted and interrupts are on, you can force the system to
++enter the debugger by sending a control-C to the debug port. This is
++what the first line of the recommended .gdbinit file does.  This allows
++you to start gdb any time after the system is up as well as when the
++system is already at a breakpoint.  (In the case where the system is
++already at a breakpoint the control-C is not needed, however, it will
++be ignored by the target so no harm is done.  Also note the the echo
++command assumes that the port speed is already set.  This will be true
++once gdb has connected, but it is best to set the port speed before you
++run gdb.)
++
++Another simple way to do this is to put the following file in you ~/bin
++directory:
++
++#!/bin/bash
++echo  -e "\003"  > /dev/ttyS0
++
++Here, the ttyS0 should be replaced with what ever port you are using.
++The "\003" is control-C.  Once you are connected with gdb, you can enter
++control-C at the command prompt.
++
++An alternative way to get control to the debugger is to enable the kGdb
++SysRq command.  Then you would enter Alt-SysRq-g (all three keys at the
++same time, but push them down in the order given).  To refresh your
++memory of the available SysRq commands try Alt-SysRq-=.  Actually any
++undefined command could replace the "=", but I like to KNOW that what I
++am pushing will never be defined.
++
++Debugging hints
++===============
++
++You can break into the target machine at any time from the development
++machine by typing ^C (see above paragraph).  If the target machine has
++interrupts enabled this will stop it in the kernel and enter the
++debugger.
++
++There is unfortunately no way of breaking into the kernel if it is
++in a loop with interrupts disabled, so if this happens to you then
++you need to place exploratory breakpoints or printk's into the kernel
++to find out where it is looping.  The exploratory breakpoints can be
++entered either thru gdb or hard coded into the source.  This is very
++handy if you do something like:
++
++if (<it hurts>) BREAKPOINT;
++
++
++There is a copy of an e-mail in the Documentation/i386/kgdb/ directory
++(debug-nmi.txt) which describes how to create an NMI on an ISA bus
++machine using a paper clip.  I have a sophisticated version of this made
++by wiring a push button switch into a PC104/ISA bus adapter card.  The
++adapter card nicely furnishes wire wrap pins for all the ISA bus
++signals.
++
++When you are done debugging the kernel on the target machine it is a
++good idea to leave it in a running state.  This makes reboots faster,
++bypassing the fsck.  So do a gdb "continue" as the last gdb command if
++this is possible.  To terminate gdb itself on the development machine
++and leave the target machine running, first clear all breakpoints and
++continue, then type ^Z to suspend gdb and then kill it with "kill %1" or
++something similar.
++
++If gdbstub Does Not Work
++========================
++
++If it doesn't work, you will have to troubleshoot it.  Do the easy
++things first like double checking your cabling and data rates.  You
++might try some non-kernel based programs to see if the back-to-back
++connection works properly.  Just something simple like cat /etc/hosts
++>/dev/ttyS0 on one machine and cat /dev/ttyS0 on the other will tell you
++if you can send data from one machine to the other.  Make sure it works
++in both directions.  There is no point in tearing out your hair in the
++kernel if the line doesn't work.
++
++All of the real action takes place in the file
++/usr/src/linux/arch/i386/kernel/kgdb_stub.c.  That is the code on the target
++machine that interacts with gdb on the development machine.  In gdb you can
++turn on a debug switch with the following command:
++
++      set remotedebug
++
++This will print out the protocol messages that gdb is exchanging with
++the target machine.
++
++Another place to look is /usr/src/arch/i386/lib/kgdb_serial.c. This is
++the code that talks to the serial port on the target side.  There might
++be a problem there.  In particular there is a section of this code that
++tests the UART which will tell you what UART you have if you define
++"PRNT" (just remove "_off" from the #define PRNT_off).  To view this
++report you will need to boot the system without any beakpoints.  This
++allows the kernel to run to the point where it calls kgdb to set up
++interrupts.  At this time kgdb will test the UART and print out the type
++it finds.  (You need to wait so that the printks are actually being
++printed.  Early in the boot they are cached, waiting for the console to
++be enabled.  Also, if kgdb is entered thru a breakpoint it is possible
++to cause a dead lock by calling printk when the console is locked.  The
++stub thus avoids doing printks from breakpoints, especially in the
++serial code.)  At this time, if the UART fails to do the expected thing,
++kgdb will print out (using printk) information on what failed.  (These
++messages will be buried in all the other boot up messages.  Look for
++lines that start with "gdb_hook_interrupt:".  You may want to use dmesg
++once the system is up to view the log.  If this fails or if you still
++don't connect, review your answers for the port address.  Use:
++
++setserial /dev/ttyS0
++
++to get the current port and IRQ information.  This command will also
++tell you what the system found for the UART type. The stub recognizes
++the following UART types:
++
++16450, 16550, and 16550A
++
++If you are really desperate you can use printk debugging in the
++kgdbstub code in the target kernel until you get it working.  In particular,
++there is a global variable in /usr/src/linux/arch/i386/kernel/kgdb_stub.c
++named "remote_debug".  Compile your kernel with this set to 1, rather
++than 0 and the debug stub will print out lots of stuff as it does
++what it does.  Likewise there are debug printks in the kgdb_serial.c
++code that can be turned on with simple changes in the macro defines.
++
++
++Debugging Loadable Modules
++==========================
++
++This technique comes courtesy of Edouard Parmelan
++<Edouard.Parmelan@quadratec.fr>
++
++When you run gdb, enter the command
++
++source gdbinit-modules
++
++This will read in a file of gdb macros that was installed in your
++kernel source directory when kgdb was installed.  This file implements
++the following commands:
++
++mod-list
++    Lists the loaded modules in the form <module-address> <module-name>
++
++mod-print-symbols <module-address>
++    Prints all the symbols in the indicated module.
++
++mod-add-symbols <module-address> <object-file-path-name>
++    Loads the symbols from the object file and associates them
++    with the indicated module.
++
++After you have loaded the module that you want to debug, use the command
++mod-list to find the <module-address> of your module.  Then use that
++address in the mod-add-symbols command to load your module's symbols.
++From that point onward you can debug your module as if it were a part
++of the kernel.
++
++The file gdbinit-modules also contains a command named mod-add-lis as
++an example of how to construct a command of your own to load your
++favorite module.  The idea is to "can" the pathname of the module
++in the command so you don't have to type so much.
++
++Threads
++=======
++
++Each process in a target machine is seen as a gdb thread. gdb thread
++related commands (info threads, thread n) can be used.
++
++ia-32 hardware breakpoints
++==========================
++
++kgdb stub contains support for hardware breakpoints using debugging features
++of ia-32(x86) processors. These breakpoints do not need code modification.
++They use debugging registers. 4 hardware breakpoints are available in ia-32
++processors.
++
++Each hardware breakpoint can be of one of the following three types.
++
++1. Execution breakpoint - An Execution breakpoint is triggered when code
++      at the breakpoint address is executed.
++
++      As limited number of hardware breakpoints are available, it is
++      advisable to use software breakpoints ( break command ) instead
++      of execution hardware breakpoints, unless modification of code
++      is to be avoided.
++
++2. Write breakpoint - A write breakpoint is triggered when memory
++      location at the breakpoint address is written.
++
++      A write or can be placed for data of variable length. Length of
++      a write breakpoint indicates length of the datatype to be
++      watched. Length is 1 for 1 byte data , 2 for 2 byte data, 3 for
++      4 byte data.
++
++3. Access breakpoint - An access breakpoint is triggered when memory
++      location at the breakpoint address is either read or written.
++
++      Access breakpoints also have lengths similar to write breakpoints.
++
++IO breakpoints in ia-32 are not supported.
++
++Since gdb stub at present does not use the protocol used by gdb for hardware
++breakpoints, hardware breakpoints are accessed through gdb macros. gdb macros
++for hardware breakpoints are described below.
++
++hwebrk        - Places an execution breakpoint
++      hwebrk breakpointno address
++hwwbrk        - Places a write breakpoint
++      hwwbrk breakpointno length address
++hwabrk        - Places an access breakpoint
++      hwabrk breakpointno length address
++hwrmbrk       - Removes a breakpoint
++      hwrmbrk breakpointno
++exinfo        - Tells whether a software or hardware breakpoint has occurred.
++      Prints number of the hardware breakpoint if a hardware breakpoint has
++      occurred.
++
++Arguments required by these commands are as follows
++breakpointno  - 0 to 3
++length                - 1 to 3
++address               - Memory location in hex digits ( without 0x ) e.g c015e9bc
++
++SMP support
++==========
++
++When a breakpoint occurs or user issues a break ( Ctrl + C ) to gdb
++client, all the processors are forced to enter the debugger. Current
++thread corresponds to the thread running on the processor where
++breakpoint occurred.  Threads running on other processor(s) appear
++similar to other non-running threads in the 'info threads' output.
++Within the kgdb stub there is a structure "waiting_cpus" in which kgdb
++records the values of "current" and "regs" for each CPU other than the
++one that hit the breakpoint.  "current" is a pointer to the task
++structure for the task that CPU is running, while "regs" points to the
++saved registers for the task.  This structure can be examined with the
++gdb "p" command.
++
++ia-32 hardware debugging registers on all processors are set to same
++values.  Hence any hardware breakpoints may occur on any processor.
++
++gdb troubleshooting
++===================
++
++1. gdb hangs
++Kill it. restart gdb. Connect to target machine.
++
++2. gdb cannot connect to target machine (after killing a gdb and
++restarting another) If the target machine was not inside debugger when
++you killed gdb, gdb cannot connect because the target machine won't
++respond.  In this case echo "Ctrl+C"(ASCII 3) to the serial line.
++e.g. echo -e "\003" > /dev/ttyS1
++This forces that target machine into the debugger, after which you
++can connect.
++
++3. gdb cannot connect even after echoing Ctrl+C into serial line
++Try changing serial line settings min to 1 and time to 0
++e.g. stty min 1 time 0 < /dev/ttyS1
++Try echoing again
++
++Check serial line speed and set it to correct value if required
++e.g. stty ispeed 115200 ospeed 115200 < /dev/ttyS1
++
++EVENTS
++======
++
++Ever want to know the order of things happening?  Which CPU did what and
++when?  How did the spinlock get the way it is?  Then events are for
++you.  Events are defined by calls to an event collection interface and
++saved for later examination.  In this case, kgdb events are saved by a
++very fast bit of code in kgdb which is fully SMP and interrupt protected
++and they are examined by using gdb to display them.  Kgdb keeps only
++the last N events, where N must be a power of two and is defined at
++configure time.
++
++
++Events are signaled to kgdb by calling:
++
++kgdb_ts(data0,data1)
++
++For each call kgdb records each call in an array along with other info.
++Here is the array definition:
++
++struct kgdb_and_then_struct {
++#ifdef CONFIG_SMP
++      int     on_cpu;
++#endif
++      long long at_time;
++      int     from_ln;
++      char    * in_src;
++      void    *from;
++        int     with_if;
++      int     data0;
++      int     data1;
++};
++
++For SMP machines the CPU is recorded, for all machines the TSC is
++recorded (gets a time stamp) as well as the line number and source file
++the call was made from.  The address of the (from), the "if" (interrupt
++flag) and the two data items are also recorded.  The macro kgdb_ts casts
++the types to int, so you can put any 32-bit values here.  There is a
++configure option to select the number of events you want to keep.  A
++nice number might be 128, but you can keep up to 1024 if you want.  The
++number must be a power of two.  An "andthen" macro library is provided
++for gdb to help you look at these events.  It is also possible to define
++a different structure for the event storage and cast the data to this
++structure.  For example the following structure is defined in kgdb:
++
++struct kgdb_and_then_struct2 {
++#ifdef CONFIG_SMP
++      int     on_cpu;
++#endif
++      long long at_time;
++      int     from_ln;
++      char    * in_src;
++      void    *from;
++        int     with_if;
++      struct task_struct *t1;
++      struct task_struct *t2;
++};
++
++If you use this for display, the data elements will be displayed as
++pointers to task_struct entries.  You may want to define your own
++structure to use in casting.  You should only change the last two items
++and you must keep the structure size the same.  Kgdb will handle these
++as 32-bit ints, but within that constraint you can define a structure to
++cast to any 32-bit quantity.  This need only be available to gdb and is
++only used for casting in the display code.
++
++Final Items
++===========
++
++I picked up this code from Amit S. Kale and enhanced it.
++
++If you make some really cool modification to this stuff, or if you
++fix a bug, please let me know.
++
++George Anzinger
++<george@mvista.com>
++
++Amit S. Kale
++<akale@veritas.com>
++
++(First kgdb by David Grothe <dave@gcom.com>)
++
++(modified by Tigran Aivazian <tigran@sco.com>)
++    Putting gdbstub into the kernel config menu.
++
++(modified by Scott Foehner <sfoehner@engr.sgi.com>)
++    Hooks for entering gdbstub at boot time.
++
++(modified by Amit S. Kale <akale@veritas.com>)
++    Threads, ia-32 hw debugging, mp support, console support,
++    nmi watchdog handling.
++
++(modified by George Anzinger <george@mvista.com>)
++    Extended threads to include the idle threads.
++    Enhancements to allow breakpoint() at first C code.
++    Use of module_init() and __setup() to automate the configure.
++    Enhanced the cpu "collection" code to work in early bring-up.
++    Added ability to call functions from gdb
++    Print info thread stuff without going back to schedule()
++    Now collect the "other" cpus with an IPI/ NMI.
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/Documentation/i386/kgdb/loadmodule.sh   2003-10-05 00:33:38.000000000 -0700
+@@ -0,0 +1,78 @@
++#/bin/sh
++# This script loads a module on a target machine and generates a gdb script.
++# source generated gdb script to load the module file at appropriate addresses
++# in gdb.
++#
++# Usage:
++# Loading the module on target machine and generating gdb script)
++#     [foo]$ loadmodule.sh <modulename>
++#
++# Loading the module file into gdb
++#     (gdb) source <gdbscriptpath>
++#
++# Modify following variables according to your setup.
++#     TESTMACHINE - Name of the target machine
++#     GDBSCRIPTS - The directory where a gdb script will be generated
++#
++# Author: Amit S. Kale (akale@veritas.com).
++#
++# If you run into problems, please check files pointed to by following
++# variables.
++#     ERRFILE - /tmp/<modulename>.errs contains stderr output of insmod
++#     MAPFILE - /tmp/<modulename>.map contains stdout output of insmod
++#     GDBSCRIPT - $GDBSCRIPTS/load<modulename> gdb script.
++
++TESTMACHINE=foo
++GDBSCRIPTS=/home/bar
++
++if [ $# -lt 1 ] ; then {
++      echo Usage: $0 modulefile
++      exit
++} ; fi
++
++MODULEFILE=$1
++MODULEFILEBASENAME=`basename $1`
++
++if [ $MODULEFILE = $MODULEFILEBASENAME ] ; then {
++      MODULEFILE=`pwd`/$MODULEFILE
++} fi
++
++ERRFILE=/tmp/$MODULEFILEBASENAME.errs
++MAPFILE=/tmp/$MODULEFILEBASENAME.map
++GDBSCRIPT=$GDBSCRIPTS/load$MODULEFILEBASENAME
++
++function findaddr() {
++      local ADDR=0x$(echo "$SEGMENTS" | \
++              grep "$1" | sed 's/^[^ ]*[ ]*[^ ]*[ ]*//' | \
++              sed 's/[ ]*[^ ]*$//')
++      echo $ADDR
++}
++
++function checkerrs() {
++      if [ "`cat $ERRFILE`" != "" ] ; then {
++              cat $ERRFILE
++              exit
++      } fi
++}
++
++#load the module
++echo Copying $MODULEFILE to $TESTMACHINE
++rcp $MODULEFILE root@${TESTMACHINE}:
++
++echo Loading module $MODULEFILE
++rsh -l root $TESTMACHINE  /sbin/insmod -m ./`basename $MODULEFILE` \
++      > $MAPFILE 2> $ERRFILE
++checkerrs
++
++SEGMENTS=`head -n 11 $MAPFILE | tail -n 10`
++TEXTADDR=$(findaddr "\\.text[^.]")
++LOADSTRING="add-symbol-file $MODULEFILE $TEXTADDR"
++SEGADDRS=`echo "$SEGMENTS" | awk '//{
++      if ($1 != ".text" && $1 != ".this" &&
++          $1 != ".kstrtab" && $1 != ".kmodtab") {
++              print " -s " $1 " 0x" $3 " "
++      }
++}'`
++LOADSTRING="$LOADSTRING $SEGADDRS"
++echo Generating script $GDBSCRIPT
++echo $LOADSTRING > $GDBSCRIPT
+--- linux-2.6.0-test6/Documentation/ioctl-number.txt   2003-09-08 13:58:55.000000000 -0700
++++ 25/Documentation/ioctl-number.txt  2003-10-05 00:33:23.000000000 -0700
+@@ -175,10 +175,6 @@ Code      Seq#    Include File            Comments
+                                       <mailto:buk@buks.ipn.de>
+ 0xA0  all     linux/sdp/sdp.h         Industrial Device Project
+                                       <mailto:kenji@bitgate.com>
+-0xA2    00-0F   DVD decoder driver      in development:
+-                                        <http://linuxtv.org/developer/dvdapi.html>
+-0xA3  00-1F   Philips SAA7146 dirver  in development:
+-                                      <mailto:Andreas.Beckmann@hamburg.sc.philips.com>
+ 0xA3  80-8F   Port ACL                in development:
+                                       <mailto:tlewis@mindspring.com>
+ 0xA3  90-9F   linux/dtlk.h
+--- linux-2.6.0-test6/Documentation/iostats.txt        2003-06-14 12:18:06.000000000 -0700
++++ 25/Documentation/iostats.txt       2003-10-05 00:33:23.000000000 -0700
+@@ -1,22 +1,22 @@
+ I/O statistics fields
+ ---------------
+-Last modified 5/15/03
++Last modified Sep 30, 2003
+-In 2.4.20 (and some versions before, with patches), and 2.5.45,
+-more extensive disk statistics were introduced to help measure disk
++Since 2.4.20 (and some versions before, with patches), and 2.5.45,
++more extensive disk statistics have been introduced to help measure disk
+ activity. Tools such as sar and iostat typically interpret these and do
+ the work for you, but in case you are interested in creating your own
+ tools, the fields are explained here.
+-In most versions of the 2.4 patch, the information is found as additional
+-fields in /proc/partitions.  In 2.5, the same information is found in
+-two places: one is in the file /proc/diskstats (appears in 2.5.69 and
+-beyond), and the other is within the sysfs file system, which must be
+-mounted in order to obtain the information. Throughout this document
+-we'll assume that sysfs is mounted on /sys, although of course it may
+-be mounted anywhere.  In 2.5, both /proc/diskstats and sysfs use the
+-same source for the information and so should not differ.
++In 2.4 now, the information is found as additional fields in
++/proc/partitions.  In 2.6, the same information is found in two
++places: one is in the file /proc/diskstats, and the other is within
++the sysfs file system, which must be mounted in order to obtain
++the information. Throughout this document we'll assume that sysfs
++is mounted on /sys, although of course it may be mounted anywhere.
++Both /proc/diskstats and sysfs use the same source for the information
++and so should not differ.
+ Here are examples of these different formats:
+@@ -25,15 +25,15 @@ Here are examples of these different for
+    3     1    9221278 hda1 35486 0 35496 38030 0 0 0 0 0 38030 38030
+-2.5 sysfs:
++2.6 sysfs:
+    446216 784926 9550688 4382310 424847 312726 5922052 19310380 0 3376340 23705160
+    35486    38030    38030    38030
+-2.5 diskstats:
++2.6 diskstats:
+    3    0   hda 446216 784926 9550688 4382310 424847 312726 5922052 19310380 0 3376340 23705160
+    3    1   hda1 35486 38030 38030 38030
+-On 2.4 you might execute "grep 'hda ' /proc/partitions". On 2.5, you have
++On 2.4 you might execute "grep 'hda ' /proc/partitions". On 2.6, you have
+ a choice of "cat /sys/block/hda/stat" or "grep 'hda ' /proc/diskstats".
+ The advantage of one over the other is that the sysfs choice works well
+ if you are watching a known, small set of disks.  /proc/diskstats may
+@@ -43,7 +43,7 @@ each snapshot of your disk statistics.
+ In 2.4, the statistics fields are those after the device name. In
+ the above example, the first field of statistics would be 446216.
+-By contrast, in 2.5 if you look at /sys/block/hda/stat, you'll
++By contrast, in 2.6 if you look at /sys/block/hda/stat, you'll
+ find just the eleven fields, beginning with 446216.  If you look at
+ /proc/diskstats, the eleven fields will be preceded by the major and
+ minor device numbers, and device name.  Each of these formats provide
+@@ -93,35 +93,35 @@ Field 11 -- weighted # of milliseconds s
+ To avoid introducing performance bottlenecks, no locks are held while
+ modifying these counters.  This implies that minor inaccuracies may be
+ introduced when changes collide, so (for instance) adding up all the
+-read I/Os issued per partition should equal those made to the disks
+-... but due to the lack of locking it may only be very close.
++read I/Os issued per partition should equal those made to the disks ...
++but due to the lack of locking it may only be very close.
+-In release 2.5.65 the 2.5 counters were made per-cpu, which made the lack
+-of locking almost a non-issue.  When the statistics are read, the per-cpu
+-counters are summed (possibly overflowing the unsigned 32-bit variable
+-they are summed to) and the result given to the user.  There is no
+-convenient user interface for accessing the per-cpu counters themselves.
++In 2.6, there are counters for each cpu, which made the lack of locking
++almost a non-issue.  When the statistics are read, the per-cpu counters
++are summed (possibly overflowing the unsigned 32-bit variable they are
++summed to) and the result given to the user.  There is no convenient
++user interface for accessing the per-cpu counters themselves.
+ Disks vs Partitions
+ -------------------
+-There were significant changes between 2.4 and 2.5 in the I/O subsystem.
++There were significant changes between 2.4 and 2.6 in the I/O subsystem.
+ As a result, some statistic information disappeared. The translation from
+ a disk address relative to a partition to the disk address relative to
+ the host disk happens much earlier.  All merges and timings now happen
+ at the disk level rather than at both the disk and partition level as
+-in 2.4.  Consequently, you'll see a different statistics output on 2.5 for
++in 2.4.  Consequently, you'll see a different statistics output on 2.6 for
+ partitions from that for disks.  There are only *four* fields available
+-for partitions on 2.5 machines.  This is reflected in the examples above.
++for partitions on 2.6 machines.  This is reflected in the examples above.
+ Field  1 -- # of reads issued
+     This is the total number of reads issued to this partition.
+ Field  2 -- # of sectors read
+     This is the total number of sectors requested to be read from this
+     partition.
+-Field  3 -- # of reads issued
++Field  3 -- # of writes issued
+     This is the total number of writes issued to this partition.
+-Field  4 -- # of sectors read
++Field  4 -- # of sectors written
+     This is the total number of sectors requested to be written to
+     this partition.
+@@ -135,14 +135,16 @@ a subtle distinction that is probably un
+ Additional notes
+ ----------------
+-In 2.5, sysfs is not mounted by default.  Here's the line you'll want
+-to add to your /etc/fstab:
++In 2.6, sysfs is not mounted by default.  If your distribution of
++Linux hasn't added it already, here's the line you'll want to add to
++your /etc/fstab:
+ none /sys sysfs defaults 0 0
+-In 2.5, at the same time that disk statistics appeared in sysfs, they were
+-removed from /proc/stat.  In 2.4, they appear in both /proc/partitions
+-and /proc/stat.
++In 2.6, all disk statistics were removed from /proc/stat.  In 2.4, they
++appear in both /proc/partitions and /proc/stat, although the ones in
++/proc/stat take a very different format from those in /proc/partitions
++(see proc(5), if your system has it.)
+ -- ricklind@us.ibm.com
+--- linux-2.6.0-test6/Documentation/kernel-parameters.txt      2003-09-27 18:57:43.000000000 -0700
++++ 25/Documentation/kernel-parameters.txt     2003-10-05 00:34:33.000000000 -0700
+@@ -460,6 +460,10 @@ running once the system is up.
+       logibm_irq=     [HW,MOUSE] Logitech Bus Mouse Driver
+                       Format: <irq>
++      log_buf_len=n   Sets the size of the printk ring buffer, in bytes.
++                      Format is n, nk, nM.  n must be a power of two.  The
++                      default is set in kernel config.
++
+       lp=0            [LP]    Specify parallel ports to use, e.g,
+       lp=port[,port...]       lp=none,parport0 (lp0 not configured, lp1 uses
+       lp=reset                first parallel port). 'lp=0' disables the
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/Documentation/MSI-HOWTO.txt     2003-10-05 00:36:20.000000000 -0700
+@@ -0,0 +1,321 @@
++              The MSI Driver Guide HOWTO
++      Tom L Nguyen tom.l.nguyen@intel.com
++                      10/03/2003
++
++1. About this guide
++
++This guide describes the basics of Message Signaled Interrupts(MSI), the
++advantages of using MSI over traditional interrupt mechanisms, and how
++to enable your driver to use MSI or MSI-X. Also included is a Frequently
++Asked Questions.
++
++2. Copyright 2003 Intel Corporation
++
++3. What is MSI/MSI-X?
++
++Message Signaled Interrupt (MSI), as described in the PCI Local Bus
++Specification Revision 2.3 or latest, is an optional feature, and a
++required feature for PCI Express devices. MSI enables a device function
++to request service by sending an Inbound Memory Write on its PCI bus to
++the FSB as a Message Signal Interrupt transaction. Because MSI is
++generated in the form of a Memory Write, all transaction conditions,
++such as a Retry, Master-Abort, Target-Abort or normal completion, are
++supported.
++
++A PCI device that supports MSI must also support pin IRQ assertion
++interrupt mechanism to provide backward compatibility for systems that
++do not support MSI. In Systems, which support MSI, the bus driver is
++responsible for initializing the message address and message data of
++the device function's MSI/MSI-X capability structure during device
++initial configuration.
++
++An MSI capable device function indicates MSI support by implementing
++the MSI/MSI-X capability structure in its PCI capability list. The
++device function may implement both the MSI capability structure and
++the MSI-X capability structure; however, the bus driver should not
++enable both, but instead enable only the MSI-X capability structure.
++
++The MSI capability structure contains Message Control register,
++Message Address register and Message Data register. These registers
++provide the bus driver control over MSI. The Message Control register
++indicates the MSI capability supported by the device. The Message
++Address register specifies the target address and the Message Data
++register specifies the characteristics of the message. To request
++service, the device function writes the content of the Message Data
++register to the target address. The device and its software driver
++are prohibited from writing to these registers.
++
++The MSI-X capability structure is an optional extension to MSI. It
++uses an independent and separate capability structure. There are
++some key advantages to implementing the MSI-X capability structure
++over the MSI capability structure as described below.
++
++      - Support a larger maximum number of vectors per function.
++
++      - Provide the ability for system software to configure
++      each vector with an independent message address and message
++      data, specified by a table that resides in Memory Space.
++
++        - MSI and MSI-X both support per-vector masking. Per-vector
++      masking is an optional extension of MSI but a required
++      feature for MSI-X. Per-vector masking provides the kernel
++      the ability to mask/unmask MSI when servicing its software
++      interrupt service routing handler. If per-vector masking is
++      not supported, then the device driver should provide the
++      hardware/software synchronization to ensure that the device
++      generates MSI when the driver wants it to do so.
++
++4. Why use MSI?
++
++As a benefit the simplification of board design, MSI allows board
++designers to remove out of band interrupt routing. MSI is another
++step towards a legacy-free environment.
++
++Due to increasing pressure on chipset and processor packages to
++reduce pin count, the need for interrupt pins is expected to
++diminish over time. Devices, due to pin constraints, may implement
++messages to increase performance.
++
++PCI Express endpoints uses INTx emulation (in-band messages) instead
++of IRQ pin assertion. Using INTx emulation requires interrupt
++sharing among devices connected to the same node (PCI bridge) while
++MSI is unique (non-shared) and does not require BIOS configuration
++support. As a result, the PCI Express technology requires MSI
++support for better interrupt performance.
++
++Using MSI enables the device functions to support two or more
++vectors, which can be configure to target different CPU's to
++increase scalability.
++
++5. Configuring a driver to use MSI/MSI-X
++
++By default, the kernel will not enable MSI/MSI-X on all devices that
++support this capability once the patch is installed. A kernel
++configuration option must be selected to enable MSI/MSI-X support.
++
++5.1 Including MSI support into the kernel
++
++To include MSI support into the kernel requires users to patch the
++VECTOR-base patch first and then the MSI patch because the MSI
++support needs VECTOR based scheme. Once these patches are installed,
++setting CONFIG_PCI_USE_VECTOR enables the VECTOR based scheme and
++the option for MSI-capable device drivers to selectively enable MSI
++(using pci_enable_msi as desribed below).
++
++Since the target of the inbound message is the local APIC, providing
++CONFIG_PCI_USE_VECTOR is dependent on whether CONFIG_X86_LOCAL_APIC
++is enabled or not.
++
++int pci_enable_msi(struct pci_dev *)
++
++With this new API, any existing device driver, which like to have
++MSI enabled on its device function, must call this explicitly. A
++successful call will initialize the MSI/MSI-X capability structure
++with ONE vector, regardless of whether the device function is
++capable of supporting multiple messages. This vector replaces the
++pre-assigned dev->irq with a new MSI vector. To avoid the conflict
++of new assigned vector with existing pre-assigned vector requires
++the device driver to call this API before calling request_irq(...).
++
++The below diagram shows the events, which switches the interrupt
++mode on the MSI-capable device function between MSI mode and
++PIN-IRQ assertion mode.
++
++       ------------   pci_enable_msi   ------------------------
++      |            | <=============== |                        |
++      | MSI MODE   |                  | PIN-IRQ ASSERTION MODE |
++      |            | ===============> |                        |
++       ------------   free_irq         ------------------------
++
++5.2 Configuring for MSI support
++
++Due to the non-contiguous fashion in vector assignment of the
++existing Linux kernel, this patch does not support multiple
++messages regardless of the device function is capable of supporting
++more than one vector. The bus driver initializes only entry 0 of
++this capability if pci_enable_msi(...) is called successfully by
++the device driver.
++
++5.3 Configuring for MSI-X support
++
++Both the MSI capability structure and the MSI-X capability structure
++share the same above semantics; however, due to the ability of the
++system software to configure each vector of the MSI-X capability
++structure with an independent message address and message data, the
++non-contiguous fashion in vector assignment of the existing Linux
++kernel has no impact on supporting multiple messages on an MSI-X
++capable device functions. By default, as mentioned above, ONE vector
++should be always allocated to the MSI-X capability structure at
++entry 0. The bus driver does not initialize other entries of the
++MSI-X table.
++
++Note that the PCI subsystem should have full control of a MSI-X
++table that resides in Memory Space. The software device driver
++should not access this table.
++
++To request for additional vectors, the device software driver should
++call function msi_alloc_vectors(). It is recommended that the
++software driver should call this function once during the
++initialization phase of the device driver.
++
++The function msi_alloc_vectors(), once invoked, enables either
++all or nothing, depending on the current availability of vector
++resources. If no vector resources are available, the device function
++still works with ONE vector. If the vector resources are available
++for the number of vectors requested by the driver, this function
++will reconfigure the MSI-X capability structure of the device with
++additional messages, starting from entry 1. To emphasize this
++reason, for example, the device may be capable for supporting the
++maximum of 32 vectors while its software driver usually may request
++4 vectors.
++
++For each vector, after this successful call, the device driver is
++responsible to call other functions like request_irq(), enable_irq(),
++etc. to enable this vector with its corresponding interrupt service
++handler. It is the device driver's choice to have all vectors shared
++the same interrupt service handler or each vector with a unique
++interrupt service handler.
++
++In addition to the function msi_alloc_vectors(), another function
++msi_free_vectors() is provided to allow the software driver to
++release a number of vectors back to the vector resources. Once
++invoked, the PCI subsystem disables (masks) each vector released.
++These vectors are no longer valid for the hardware device and its
++software driver to use. Like free_irq, it recommends that the
++device driver should also call msi_free_vectors to release all
++additional vectors previously requested.
++
++int msi_alloc_vectors(struct pci_dev *dev, int *vector, int nvec)
++
++This API enables the software driver to request the PCI subsystem
++for additional messages. Depending on the number of vectors
++available, the PCI subsystem enables either all or nothing.
++
++Argument dev points to the device (pci_dev) structure.
++Argument vector is a pointer of integer type. The number of
++elements is indicated in argument nvec.
++Argument nvec is an integer indicating the number of messages
++requested.
++A return of zero indicates that the number of allocated vector is
++successfully allocated. Otherwise, indicate resources not
++available.
++
++int msi_free_vectors(struct pci_dev* dev, int *vector, int nvec)
++
++This API enables the software driver to inform the PCI subsystem
++that it is willing to release a number of vectors back to the
++MSI resource pool. Once invoked, the PCI subsystem disables each
++MSI-X entry associated with each vector stored in the argument 2.
++These vectors are no longer valid for the hardware device and
++its software driver to use.
++
++Argument dev points to the device (pci_dev) structure.
++Argument vector is a pointer of integer type. The number of
++elements is indicated in argument nvec.
++Argument nvec is an integer indicating the number of messages
++released.
++A return of zero indicates that the number of allocated vectors
++is successfully released. Otherwise, indicates a failure.
++
++5.4 Hardware requirements for MSI support
++MSI support requires support from both system hardware and
++individual hardware device functions.
++
++5.4.1 System hardware support
++Since the target of MSI address is the local APIC CPU, enabling
++MSI support in Linux kernel is dependent on whether existing
++system hardware supports local APIC. Users should verify their
++system whether it runs when CONFIG_X86_LOCAL_APIC=y.
++
++In SMP environment, CONFIG_X86_LOCAL_APIC is automatically set;
++however, in UP environment, users must manually set
++CONFIG_X86_LOCAL_APIC. Once CONFIG_X86_LOCAL_APIC=y, setting
++CONFIG_PCI_USE_VECTOR enables the VECTOR based scheme and
++the option for MSI-capable device drivers to selectively enable
++MSI (using pci_enable_msi as desribed below).
++
++Note that CONFIG_X86_IO_APIC setting is irrelevant because MSI
++vector is allocated new during runtime and MSI support does not
++depend on BIOS support. This key independency enables MSI support
++on future IOxAPIC free platform.
++
++5.4.2 Device hardware support
++The hardware device function supports MSI by indicating the
++MSI/MSI-X capability structure on its PCI capability list. By
++default, this capability structure will not be initialized by
++the kernel to enable MSI during the system boot. In other words,
++the device function is running on its default pin assertion mode.
++Note that in many cases the hardware supporting MSI have bugs,
++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 mode.
++
++5.5 How to tell whether MSI is enabled on device function
++
++At the driver level, a return of zero from pci_enable_msi(...)
++indicates to the device driver that its device function is
++initialized successfully and ready to run in MSI mode.
++
++At the user level, users can use command 'cat /proc/interrupts'
++to display the vector allocated for the device and its interrupt
++mode, as shown below.
++
++           CPU0       CPU1
++  0:     324639          0    IO-APIC-edge  timer
++  1:       1186          0    IO-APIC-edge  i8042
++  2:          0          0          XT-PIC  cascade
++ 12:       2797          0    IO-APIC-edge  i8042
++ 14:       6543          0    IO-APIC-edge  ide0
++ 15:          1          0    IO-APIC-edge  ide1
++169:          0          0   IO-APIC-level  uhci-hcd
++185:          0          0   IO-APIC-level  uhci-hcd
++193:        138         10         PCI MSI  aic79xx
++201:         30          0         PCI MSI  aic79xx
++225:         30          0   IO-APIC-level  aic7xxx
++233:         30          0   IO-APIC-level  aic7xxx
++NMI:          0          0
++LOC:     324553     325068
++ERR:          0
++MIS:          0
++
++6. FAQ
++
++Q1. Are there any limitations on using the MSI?
++
++A1. If the PCI device supports MSI and conforms to the
++specification and the platform supports the APIC local bus,
++then using MSI should work.
++
++Q2. Will it work on all the Pentium processors (P3, P4, Xeon,
++AMD processors)? In P3 IPI's are transmitted on the APIC local
++bus and in P4 and Xeon they are transmitted on the system
++bus. Are there any implications with this?
++
++A2. MSI support enables a PCI device sending an inbound
++memory write (0xfeexxxxx as target address) on its PCI bus
++directly to the FSB. Since the message address has a
++redirection hint bit cleared, it should work.
++
++Q3. The target address 0xfeexxxxx will be translated by the
++Host Bridge into an interrupt message. Are there any
++limitations on the chipsets such as Intel 8xx, Intel e7xxx,
++or VIA?
++
++A3. If these chipsets support an inbound memory write with
++target address set as 0xfeexxxxx, as conformed to PCI
++specification 2.3 or latest, then it should work.
++
++Q4. From the driver point of view, if the MSI is lost because
++of the errors occur during inbound memory write, then it may
++wait for ever. Is there a mechanism for it to recover?
++
++A4. Since the target of the transaction is an inbound memory
++write, all transaction termination conditions (Retry,
++Master-Abort, Target-Abort, or normal completion) are
++supported. A device sending an MSI must abide by all the PCI
++rules and conditions regarding that inbound memory write. So,
++if a retry is signaled it must retry, etc... We believe that
++the recommendation for Abort is also a retry (refer to PCI
++specification 2.3 or latest).
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/Documentation/must-fix.txt      2003-10-05 00:33:51.000000000 -0700
+@@ -0,0 +1,354 @@
++
++Must-fix bugs
++=============
++
++drivers/char/
++~~~~~~~~~~~~~
++
++o TTY locking is broken.
++
++  o see FIXME in do_tty_hangup().  This causes ppp BUGs in local_bh_enable()
++
++  o Other problems: aviro, dipankar, Alan have details.
++
++  o somebody will have to document the tty driver and ldisc API
++
++o Lack of test cases and/or stress tests is a problem.  Contributions and
++  suggestions are sought.
++
++o Lots of drivers are using cli/sti and are broken.
++
++drivers/tty
++~~~~~~~~~~~
++
++o viro: we need to fix refcounting for tty_driver (oopsable race, must fix
++  anyway, hopefully about a week until it's merged) then we can do
++  tty/misc/upper levels of sound.
++
++drivers/block/
++~~~~~~~~~~~~~~
++
++o ideraid hasn't been ported to 2.5 at all yet.
++
++  We need to understand whether the proposed BIO split code will suffice
++  for this.
++
++o CD burning.  There are still a few quirks to solve wrt SG_IO and ide-cd.
++
++  Jens: The basic hang has been solved (double fault in ide-cd), there still
++  seems to be some cases that don't work too well.  Don't really have a
++  handle on those :/
++
++o lmb: Last time I looked at the multipath code (2.5.50 or so) it also
++  looked pretty broken; I plan to port forward the changes we did on 2.4
++  before KS.
++
++drivers/input/
++~~~~~~~~~~~~~~
++
++o rmk: unconverted keyboard/mouse drivers (there's a deadline of 2.6.0
++  currently on these remaining in my/Linus' tree.)
++
++o viro: large absence of locking.
++
++o viro: parport is nearly as bad as that and there the code is more hairy. 
++  IMO parport is more of "figure out what API changes are needed for its
++  users, get them done ASAP, then fix generic layer at leisure"
++
++o (Albert Cahalan) Lots of people (check Google) get this message from the
++  kernel:
++
++  psmouse.c: Lost synchronization, throwing 2 bytes away.
++
++  (the number of bytes will be 1, 2, or 3)
++
++  At work, I get it when there is heavy NFS traffic.  The mouse goes crazy,
++  jumping around and doing random cut-and-paste all over everything.  This
++  is with a decently fast and modern PC.
++
++o There seem to be too many reports of keyboards and mice failing or acting
++  strangely.
++
++
++drivers/misc/
++~~~~~~~~~~~~~
++
++o rmk: UCB1[23]00 drivers, currently sitting in drivers/misc in the ARM
++  tree.  (touchscreen, audio, gpio, type device.)
++
++  These need to be moved out of drivers/misc/ and into real places
++
++o viro: actually, misc.c has a good chance to die.  With cdev-cidr that's
++  trivial.
++
++drivers/net/
++~~~~~~~~~~~~
++
++o rmk: network drivers.  ARM people like to add tonnes of #ifdefs into
++  these to customise them to their hardware platform (eg, chip access
++  methods, addresses, etc.) I cope with this by not integrating them into my
++  tree.  The result is that many ARM platforms can't be built from even my
++  tree without extra patches.  This isn't sane, and has bred a culture of
++  network drivers not being submitted.  I don't see this changing for 2.6
++  though.
++
++drivers/net/irda/
++~~~~~~~~~~~~~~~~~
++
++o dongle drivers need to be converted to sir-dev
++
++o irport need to be converted to sir-kthread
++
++o new drivers (irtty-sir/smsc-ircc2/donauboe) need more testing
++
++o rmk: Refuse IrDA initialisation if sizeof(structures) is incorrect (I'm
++  not sure if we still need this; I think gcc 2.95.3 on ARM shows this
++  problem though.)
++
++drivers/pci/
++~~~~~~~~~~~~
++
++o alan: Some cardbus crashes the system
++
++  (bugzilla, please?)
++
++drivers/pcmcia/
++~~~~~~~~~~~~~~~
++
++o alan: This is a locking disaster.
++
++  (rmk, brodo: in progress)
++
++drivers/pld/
++~~~~~~~~~~~~
++
++o rmk: EPXA (ARM platform) PLD hotswap drivers (drivers/pld)
++
++  (rmk: will work out what to do here.  maybe drivers/arm/)
++
++drivers/video/
++~~~~~~~~~~~~~~
++
++o Lots of drivers don't compile, others do but don't work.
++
++drivers/scsi/
++~~~~~~~~~~~~~
++
++o hch: large parts of the locking are hosed or not existant
++
++  (Mike Anderson, Patrick Mansfield, Badari Pulavarty)
++
++  o shost->my_devices isn't locked down at all
++
++  o there are lots of members of struct Scsi_Host/scsi_device/scsi_cmnd
++    with very unclear locking, many of them probably want to become
++    atomic_t's or bitmaps (for the 1bit bitfields).
++
++  o there's lots of volatile abuse in the scsi code that needs to be
++    thought about.
++
++  o there's some global variables incremented without any locks
++
++o Convert am53c974, dpt_i2o, initio and pci2220i to DMA-mapping
++
++o Make inia100, cpqfc, pci2000 and dc390t compile
++
++o Convert
++
++   wd33c99 based: a2091 a3000 gpv11 mvme174 sgiwd93
++
++   53c7xx based: amiga7xxx bvme6000 mvme16x initio am53c974 pci2000
++   pci2220i dc390t
++
++  To new error handling
++
++  It also might be possible to shift the 53c7xx based drivers over to
++  53c700 which does the new EH stuff, but I don't have the hardware to check
++  such a shift.
++
++  For the non-compiling stuff, I've probably missed a few that just aren't
++  compilable on my platforms, so any updates would be welcome.  Also, are
++  some of our non-compiling or unconverted drivers obsolete?
++
++o rmk: I have a pending todo: I need to put the scsi error handling through
++  a workout on my scsi bus from hell to make sure it does the right thing
++  and doesn't get wedged.
++
++o James B: USB hot-removal crash: "It's a known scsi refcounting issue."
++
++fs/
++~~~
++
++o AIO/direct-IO writes can race with truncate and wreck filesystems.
++  (Badari has a patch)
++
++o hch: devfs: there's a fundamental lookup vs devfsd race that's only
++  fixable by introducing a lookup vs devfs deadlock.  I can't see how this is
++  fixable without getting rid of the current devfsd design.  Mandrake seems
++  to have a workaround for this so this is at least not triggered so easily,
++  but that's not what I'd consider a fix..
++
++o viro: fs/char_dev.c needs removal of aeb stuff and merge of cdev-cidr. 
++  In progress.
++
++o forward-port sct's O_DIRECT fixes (Badari has a patch)
++
++o viro: there is some generic stuff for namei/namespace/super, but that's a
++  slow-merge and can go in 2.6 just fine
++
++o andi: also soft needs to be fixed - there are quite a lot of
++  uninterruptible waits in sunrpc/nfs
++
++o trond: NFS has a mmap-versus-truncate problem
++
++kernel/sched.c
++~~~~~~~~~~~~~~
++
++o Starvation, general interactivity need close monitoring.
++
++kernel/
++~~~~~~~
++
++o Alan: 32bit uid support is *still* broken for process accounting.
++
++  Create a 32bit uid, turn accounting on.  Shock horror it doesn't work
++  because the field is 16bit.  We need an acct structure flag day for 2.6
++  IMHO
++
++  (alan has patch)
++
++o viro: core sysctl code is racy.  And its interaction wiuth sysfs
++
++o (ingo) rwsems (on x86) are limited to 32766 waiting processes.  This
++  means that setting pid_max to above 32K is unsafe :-(
++
++  An option is to use CONFIG_RWSEM_GENERIC_SPINLOCK variant all the time,
++  for all archs, and not inline any part of the ops.
++
++lib/kobject.c
++~~~~~~~~~~~~~
++
++o kobject refcounting (comments from Al Viro):
++
++  _anything_ can grab a temporary reference to kobject.  IOW, if kobject is
++  embedded into something that could be freed - it _MUST_ have a destructor
++  and that destructor _MUST_ be the destructor for containing object.
++
++  Any violation of the above (and we already have a bunch of those) is a
++  user-triggerable memory corruption.
++
++  We can tolerate it for a while in 2.5 (e.g.  during work on susbsystem we
++  can decide to switch to that way of handling objects and have subsystem
++  vulnerable for a while), but all such windows must be closed before 2.6
++  and during 2.6 we can't open them at all.
++
++o All block drivers which control multiple gendisks with a single
++  request_queue are broken, due to one-to-one assumptions in the request
++  queue sysfs hookup.
++
++mm/
++~~~
++
++o GFP_DMA32 (or something like that).  Lots of ideas.  jejb, zaitcev,
++  willy, arjan, wli.
++
++  Specifically, 64-bit systems need to be able to enforce 32-bit addressing
++  limits for device metadata like network cards' ring buffers and SCSI
++  command descriptors.
++
++o access_process_vm() doesn't flush right.  We probably need new flushing
++  primitives to do this (davem?)
++
++
++modules
++~~~~~~~
++
++  (Rusty)
++
++net/
++~~~~
++
++  (davem)
++
++o UDP apps can in theory deadlock, because the ip_append_data path can end
++  up sleeping while the socket lock is held.
++
++  It is OK to sleep with the socket held held, normally.  But in this case
++  the sleep happens while waiting for socket memory/space to become
++  available, if another context needs to take the socket lock to free up the
++  space we could hang.
++
++  I sent a rough patch on how to fix this to Alexey, and he is analyzing
++  the situation.  I expect a final fix from him next week or so.
++
++o Semantics for IPSEC during operations such as TCP connect suck currently.
++
++  When we first try to connect to a destination, we may need to ask the
++  IPSEC key management daemon to resolve the IPSEC routes for us.  For the
++  purposes of what the kernel needs to do, you can think of it like ARP.  We
++  can't send the packet out properly until we resolve the path.
++
++  What happens now for IPSEC is basically this:
++
++  O_NONBLOCK: returns -EAGAIN over and over until route is resolved
++
++  !O_NONBLOCK: Sleeps until route is resolved
++
++  These semantics are total crap.  The solution, which Alexey is working
++  on, is to allow incomplete routes to exist.  These "incomplete" routes
++  merely put the packet onto a "resolution queue", and once the key manager
++  does it's thing we finish the output of the packet.  This is precisely how
++  ARP works.
++
++  I don't know when Alexey will be done with this.
++
++net/*/netfilter/
++~~~~~~~~~~~~~~~~
++
++  (Rusty)
++
++o Rework conntrack hashing.
++
++o Module relationship bogosity fix (trivial, have patch).
++
++sound/
++~~~~~~
++
++o rmk: several OSS drivers for SA11xx-based hardware in need of
++  ALSA-ification and L3 bus support code for these.
++
++o rmk: linux/sound/drivers/mpu401/mpu401.c and
++  linux/sound/drivers/virmidi.c complained about 'errno' at some time in the
++  past, need to confirm whether this is still a problem.
++
++o rmk: need to complete ALSA-ification of the WaveArtist driver for both
++  NetWinder and other stuff (there's some fairly fundamental differences in
++  the way the mixer needs to be handled for the NetWinder.)
++
++
++  (Issues with forward-porting 2.4 bugfixes.)
++  (Killing off OSS is 2.7 material)
++
++
++global
++~~~~~~
++
++o 64-bit dev_t.  Seems almost ready, but it's not really known how much
++  work is still to do.  Patches exist in -mm but with the recent rise of the
++  neo-viro I'm not sure where things are at.
++
++o Lots of 2.4 fixes including some security are not in 2.5
++
++o There are about 60 or 70 security related checks that need doing
++  (copy_user etc) from Stanford tools.  (badari is looking into this, and
++  hollisb)
++
++o A couple of hundred real looking bugzilla bugs
++
++o viro: cdev rework.  Main group is pretty stable and I hope to feed it to
++  Linus RSN.  That's cdev-cidr and ->i_cdev/->i_cindex stuff
++
++o Athlon prefetch oopses sometimes.  It is currently disabled, and needs to
++  be fixed.
++
++
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/Documentation/should-fix.txt    2003-10-05 00:33:52.000000000 -0700
+@@ -0,0 +1,611 @@
++Not-ready features and speedups
++===============================
++
++Legend:
++
++PRI1: We're totally lame if this doesn't get in
++PRI2: Would be nice
++PRI3: Not very important
++
++drivers/block/
++~~~~~~~~~~~~~~
++
++o Framework for selecting IO schedulers.  This is the main one really. 
++  Once this is in place we can drop in new schedulers any old time, no risk.
++  Nick Piggin has code for this.
++
++  PRI1
++
++o viro: paride drivers need a big cleanup
++
++  PRI2
++
++drivers/char/rtc/
++~~~~~~~~~~~~~~~~~
++
++o rmk, trini: add support for alarms to the existing generic rtc driver.
++
++  PRI2
++
++console drivers
++~~~~~~~~~~~~~~~
++  (Pavel Machek <pavel@ucw.cz>)
++
++o There are few must-fix bugs in cursor handling.
++
++o Play with gpm selection for a while and your cursor gets corrupted with
++  random dots. Ouch.
++
++device mapper
++~~~~~~~~~~~~~
++
++o ioctl interface cleanup patch is ready (redo the structure layouts)
++
++  PRI1
++
++o A port of the 2.4 snapshot and mirror targets is in progress
++
++  PRI1
++
++o the fs interface to dm needs to be redone.  gregkh was going to work on
++  this.  viro is interested in seeing work thus-far.
++
++  PRI2
++
++drivers/net/wireless/
++~~~~~~~~~~~~~~~~~~~~~
++
++  (Jean Tourrilhes <jt@bougret.hpl.hp.com>)
++
++o get latest orinoco changes from David.
++
++  PRI1
++
++o get the latest airo.c fixes from CVS.  This will hopefully fix problems
++  people have reported on the LKML.
++
++  PRI1
++
++o get HostAP driver in the kernel.  No consolidation of the 802.11
++  management across driver can happen until this one is in (which is probably
++  2.7.X material).  I think Jouni is mostly ready but didn't find time for
++  it.
++
++  PRI2
++
++o get more wireless drivers into the kernel.  The most "integrable" drivers
++  at this point seem the NWN driver, Pavel's Spectrum driver and the Atmel
++  driver.
++
++  PRI1
++
++o The last two drivers mentioned above are held up by firmware issues (see
++  flamewar on LKML a few days ago).  So maybe fixing those firmware issues
++  should be a requirement for 2.6.X, because we can expect more wireless
++  devices to need firmware upload at startup coming to market.
++
++  (in progress?)
++
++  PRI1
++
++drivers/usb/gadget/
++~~~~~~~~~~~~~~~~~~~
++
++o rmk: SA11xx USB client/gadget code (David B has been doing some work on
++  this, and keeps trying to prod me, but unfortunately I haven't had the time
++  to look at his work, sorry David.)
++
++  PRI3
++
++fs/
++~~~
++
++o ext3 and ext2 block allocators have serious failure modes - interleaved
++  allocations.
++
++  PRI3
++
++o Integrate Chris Mason's 2.4 reiserfs ordered data and data journaling
++  patches.  They make reiserfs a lot safer.
++
++  Ordered: PRI2
++  data journalled: PRI3
++
++o (Trond:) Yes: I'm still working on an atomic "open()", i.e.  one
++           where we short-circuit the usual VFS path_walk() + lookup() +
++           permission() + create() + ....  bullsh*t...
++
++           I have several reasons for wanting to do this (all of
++           them related to NFS of course, but much of the reasoning applies
++           to *all* networked file systems).
++
++   1) The above sequence is simply not atomic on *any* networked
++      filesystem.
++
++   2) It introduces a sh*tload of completely unnecessary RPC calls (why
++      do a 'permission' RPC call when the server is in *any* case going to
++      tell you whether or not this operations is allowed.  Why do a
++      'lookup()' when the 'create()' call can be made to tell you whether or
++      not a file already exists).
++
++   3) It is incompatible with some operations: the current create()
++      doesn't pass an 'EXCLUSIVE' flag down to the filesystems.
++
++   4) (NFS specific?) open() has very different cache consistency
++      requirements when compared to most other VFS operations.
++
++   I'd very much like for something like Peter Braam's 'lookup with
++   intent' or (better yet) for a proper dentry->open() to be integrated with
++   path_walk()/open_namei().  I'm still working on the latter (Peter has
++   already completed the lookup with intent stuff).
++
++   (All this is in progress, see http://www.fys.uio.no/~trondmy/src)
++
++   (Is awaiting Pater Braam's intent patches.  Applicable to CIFS)
++
++   PRI2 (?)
++
++o (Chuck Lever <cel@citi.umich.edu>): NFS O_DIRECT support must be
++  completed.  The best approach is to fall back to something like the 2.4 NFS
++  O_DIRECT support, which issues RPCs synchronously and uses the RPC
++  completion mechanism to wait for I/O completion.
++
++  PRI2
++
++o viro: cleaning up options-parsers in filesystems.  (patch exists, needs
++  porting).
++
++  PRI2
++
++o aio: fs IO isn't async at present.  suparna has restart patches, they're
++  in -mm.  Need to get Ben to review/comment.
++
++  PRI1.
++
++o drepper: various filesystems use ->pid wrongly
++
++kernel/
++~~~~~~~
++
++o rusty: Zippel's Reference count simplification.  Tricky code, but cuts
++  about 120 lines from module.c.  Patch exists, needs stressing.
++
++  PRI3
++
++o rusty: Fix module-failed-init races by starting module "disabled".  Patch
++  exists, requires some subsystems (ie.  add_partition) to explicitly say
++  "make module live now".  Without patch we are no worse off than 2.4 etc.  
++
++  PRI1
++
++o Integrate userspace irq balancing daemon.
++
++  PRI2
++
++o kexec.  Seems to work, was in -mm.
++
++  PRI3
++
++o rmk: lib/inflate.c must not use static variables (causes these to be
++  referenced via GOTOFF relocations in PIC decompressor.  We have a PIC
++  decompressor to avoid having to hard code a per platform zImage link
++  address into the makefiles.)
++
++  PRI2
++
++o klibc merge?
++
++  PRI2
++
++mm/
++~~~
++
++o objrmap: concerns over page reclaim performance at high sharing levels,
++  and interoperation with nonlinear mappings is hairy.
++
++o oxymoron's async write-error-handling patch
++
++  PRI1
++
++o dropbehind for large files
++
++  PRI2
++
++net/
++~~~~
++
++  (davem)
++
++o Real serious use of IPSEC is hampered by lack of MPLS support.  MPLS is a
++  switching technology that works by switching based upon fixed length labels
++  prepended to packets.  Many people use this and IPSEC to implement VPNs
++  over public networks, it is also used for things like traffic engineering.
++
++  A good reference site is:
++
++      http://www.mplsrc.com/
++
++  Anyways, an existing (crappy) implementation exists.  I've almost
++  completed a rewrite, I should have something in the tree next week.
++
++  PRI1
++
++o Sometimes we generate IP fragments when it truly isn't necessary.
++
++  The way IP fragmentation is specified, each fragment must be modulo 8
++  bytes in length.  So suppose the device has an MTU that is not 0 modulo 8,
++  ethernet even classifies in this way.  1500 == (8 * 187) + 4
++
++  Our IP fragmenting engine can fragment on packets that are sized within
++  the last modulo 8 bytes of the MTU.  This happens in obscure cases, but it
++  does happen.
++
++  I've proposed a fix to Alexey, whereby very late in the output path we
++  check the packet, if we fragmented but the data length would fit into the
++  MTU we unfragment the packet.
++
++  This is low priority, because technically it creates suboptimal behavior
++  rather than mis-operation.
++
++  PRI1
++
++net/*/netfilter/
++~~~~~~~~~~~~~~~~
++
++o Lots of misc. cleanups, which are happening slowly.
++
++  PRI2
++
++power management
++~~~~~~~~~~~~~~~~
++
++o PM code in mainline is currently b0rked. Fixes in -mm
++
++  PRI1
++
++o Pat and Pavel disagree over swsusp. Need to sort that out.
++
++  PRI2
++
++o Frame buffer restore codepaths (that requires some deep PCI magic)
++
++  PRI2
++
++o XFree86 hooks
++
++  PRI2
++
++o AGP restoration
++
++  PRI2
++
++o DRI restoration
++
++  (davej/Alan: not super-critical, can crash laptop on restore.  davej
++  looking into it.)
++
++  PRI2
++
++o IDE suspend/resume without races (Ben is looking at this a little)
++
++  PRI2
++
++o Pat: There are already CPU device structures; MTRRs should be a
++  dynamically registered interface of CPUs, which implies there needs
++  to be some other glue to know that there are MTRRs that need to be
++  saved/restored.
++
++  PRI1
++
++global
++~~~~~~
++
++o We need a kernel side API for reporting error events to userspace (could
++  be async to 2.6 itself)
++
++  (Prototype core based on netlink exists)
++
++  PRI2
++
++o Kai: Introduce a sane, easy and standard way to build external modules
++  - make clean and make modules_install are both broken
++
++  PRI2
++
++drivers
++~~~~~~~
++
++o Alan: Cardbus/PCMCIA requires all Russell's stuff is merged to do
++  multiheader right and so on
++
++  PRI1
++
++drivers/acpi/
++~~~~~~~~~~~~~
++
++o Fix acpi for all newer IBM Thinkpads see
++  http://bugme.osdl.org/show_bug.cgi?id=1038 for more information
++
++o alan: VIA APIC stuff is one bit of this, there are also some other
++  reports that were caused by ACPI not setting level v edge trigger some
++  times
++
++  PRI1
++
++o mochel: it seems the acpi irq routing code could use a serious rewrite.
++
++  grover: The problem is the ACPI irq routing code is trying to piggyback
++  on the existing MPS-specific data structures, and it's generally a hack. 
++  So yes mochel is right, but it is also purging MPS-ities from common code
++  as well.  I've done some preliminary work in this area and it doesn't seem
++  to break anything (yet) but a rewrite in this area imho should not be
++  rushed out the door.  And, I think the above bugs can be fixed w/o the
++  rewrite.
++
++  PRI2
++
++o mochel: ACPI suspend doesn't work.  Important, not cricital.  Pat is
++  working it.
++
++  PRI2
++
++drivers/block/
++~~~~~~~~~~~~~~
++
++o Floppy is almost unusably buggy still
++
++  akpm: we need more people to test & report.
++
++  alan: "Floppy has worked for me since the patches that went in 2.5.69-ac
++  and I think -bk somewhere"
++
++  PRI1
++
++drivers/char/
++~~~~~~~~~~~~~
++
++
++drivers/ide/
++~~~~~~~~~~~~
++
++  (Alan)
++
++o IDE PIO has occasional unexplained PIO disk eating reports
++
++  PRI1
++
++o IDE has multiple zillions of races/hangs in 2.5 still
++
++  PRI1
++
++o IDE scsi needs rewriting
++
++  PRI2
++
++o IDE needs significant reworking to handle Simplex right
++
++  PRI2
++
++o IDE hotplug handling for 2.5 is completely broken still
++
++  PRI2
++
++o There are lots of other IDE bugs that wont go away until the taskfile
++  stuff is included, the locking bugs that allow any user to hang the IDE
++  layer in 2.5, and some other updates are forward ported.  (esp.  HPT372N).
++
++  PRI1
++
++drivers/isdn/
++~~~~~~~~~~~~~
++
++  (Kai, rmk)
++
++o isdn_tty locking is completely broken (cli() and friends)
++
++  PRI2
++
++o fix other drivers
++
++  PRI2
++
++o lots more cleanups, adaption to recent APIs etc
++
++  PRI3
++
++o fixup tty-based ISDN drivers which provide TIOCM* ioctls (see my recent
++  3-set patch for serial stuff)
++
++  Alternatively, we could re-introduce the fallback to driver ioctl parsing
++  for these if not enough drivers get updated.
++
++  PRI3
++
++drivers/net/
++~~~~~~~~~~~~
++
++o davej: Either Wireless network drivers or PCMCIA broke somewhen.  A
++  configuration that worked fine under 2.4 doesn't receive any packets.  Need
++  to look into this more to make sure I don't have any misconfiguration that
++  just 'happened to work' under 2.4
++
++  PRI1
++
++drivers/scsi/
++~~~~~~~~~~~~~
++
++o jejb: qlogic -
++
++  o Merge the feral driver.  It covers all qlogic chips: 1020 all the way
++    up to 23xxx. http://linux-scsi.bkbits.net/scsi-isp-2.5
++
++  o qla2xxx: only for FC chips.  Has significant build issues.  hch
++    promises to send me a "must fix" list for this.
++    http://linux-scsi.bkbits.net/scsi-qla2xxx-2.5
++
++  PRI2
++
++arch/i386/
++~~~~~~~~~~
++
++o Also PC9800 merge needs finishing to the point we want for 2.6 (not all).
++
++  PRI3
++
++o davej: PAT support (for mtrr exhaustion w/ AGP)
++
++  PRI2
++
++o 2.5.x won't boot on some 440GX
++
++  alan: Problem understood now, feasible fix in 2.4/2.4-ac.  (440GX has two
++  IRQ routers, we use the $PIR table with the PIIX, but the 440GX doesnt use
++  the PIIX for its IRQ routing).  Fall back to BIOS for 440GX works and Intel
++  concurs.
++
++  PRI1
++
++o 2.5.x doesn't handle VIA APIC right yet.
++
++  1. We must write the PCI_INTERRUPT_LINE
++
++  2. We have quirk handlers that seem to trash it.
++
++  PRI1
++
++o ACPI needs the relax patches merging to work on lots of laptops
++
++  alan: ACPI relax stuff is in 2.4-ac, compaq workaround is in next -ac
++  coming.  These seem to deliver the goods - toshibas now work a treat.  Some
++  other relax bits are being discussed (assume local0 starts 0 etc) and
++  progress looks great.  This can occur before 2.6 or during.
++
++  PRI1
++
++o ECC driver questions are not yet sorted (DaveJ is working on this) (Dan
++  Hollis)
++
++  alan: ECC - I have some test bits from Dan's stuff - they need no kernel
++  core changes for most platforms.  That means we can treat it as a random
++  driver merge.
++
++  PRI3
++
++o alan: 2.4 has some fixes for tsc handling bugs.  One where some bioses in
++  SMM mode mess up our toggle on the time high/low or mangle the counter and
++  one where a few chips need religious use of _p for timer access and we
++  don't do that.  This is forward porting little bits of fixup.
++
++  ACPI HZ stuff we can't trap - a lot of ACPI is implemented as outb's
++  triggering SMM traps
++
++  PRI1
++
++arch/x86_64/
++~~~~~~~~~~~~
++
++  (Andi)
++
++o time handling is broken. Need to move up 2.4 time.c code.
++
++  PRI1
++
++o NMI watchdog seems to tick too fast
++
++  PRI2
++
++o not very well tested. probably more bugs lurking.
++
++  PRI1
++
++o need to coredump 64bit vsyscall code with dwarf2
++
++  PRI2
++
++o Consider merging of Erich Focht's very clean and simple homenode NUMA
++  scheduler (I have my own in 2.4, but Erich's 2.5 version is much cleaner)
++
++  PRI2
++  
++o Consider port of the Simple NUMA API from 2.4/homenode.
++
++  PRI3
++
++o move 64bit signal trampolines into vsyscall code and add dwarf2 for it.
++  (in progress)
++
++  PRI1
++
++o describe kernel assembly with dwarf2 annotations for kgdb
++
++  PRI3
++
++arch/alpha/
++~~~~~~~~~~~
++
++o rth: Ptrace writes are broken.  This means we can't (reliably) set
++  breakpoints or modify variables from gdb.
++
++  PRI1
++
++arch/arm/
++~~~~~~~~~
++
++o rmk: missing raw keyboard translation tables for all ARM machines. 
++  Haven't even looked into this at all.  This could be messy since there
++  isn't an ARM architecture standard.  I'm presently hoping that it won't be
++  an issue.  If it does, I guess we'll see drivers/char/keyboard.c explode.
++
++  PRI2
++
++arch/others/
++~~~~~~~~~~~~
++
++o SH needs resyncing, as do some other ports. SH64 needs merging.
++  No impact on mainstream platforms hopefully.
++
++  PRI2
++
++arch/s390/
++~~~~~~~~~
++
++o A nastly memory management problem causes random crashes.  These appear
++  to be fixed/hidden by the objrmap patch, more investigation is needed.
++
++  PRI1
++
++drivers/s390/
++~~~~~~~~~~~~~
++
++o Early userspace and 64 bit dev_t will allow the removal of most of
++  dasd_devmap.c and dasd_genhd.c.
++
++  PRI2
++
++o The 3270 console driver needs to be replaced with a working one
++  (prototype is there, needs to be finished).
++
++  PRI2
++
++o Minor interface changes are pending in cio/ when the z990 machines are
++  out.
++
++  PRI2
++
++o Jan Glauber is working on a fix for the timer issues related to running
++  on virtualized CPUs (wall-clock vs.  cpu time).
++
++  PRI1
++
++o a block device driver for ramdisks shared among virtual machines
++
++  PRI3
++
++o driver for crypto hardware
++
++  PRI3
++
++o 'claw' network device driver
++
++  PRI3
++
+--- linux-2.6.0-test6/Documentation/zorro.txt  2003-07-27 12:14:38.000000000 -0700
++++ 25/Documentation/zorro.txt 2003-10-05 00:33:23.000000000 -0700
+@@ -2,7 +2,7 @@
+               ----------------------------------------
+ Written by Geert Uytterhoeven <geert@linux-m68k.org>
+-Last revised: February 27, 2000
++Last revised: September 5, 2003
+ 1. Introduction
+@@ -75,7 +75,7 @@ they are CPU physical addresses as well.
+ The treatment of these regions depends on the type of Zorro space:
+   - Zorro II address space is always mapped and does not have to be mapped
+-    explicitly using ioremap().
++    explicitly using z_ioremap().
+     
+     Conversion from bus/physical Zorro II addresses to kernel virtual addresses
+     and vice versa is done using:
+@@ -83,22 +83,20 @@ The treatment of these regions depends o
+       virt_addr = ZTWO_VADDR(bus_addr);
+       bus_addr = ZTWO_PADDR(virt_addr);
+-  - Zorro III address space must be mapped explicitly using ioremap() first
++  - Zorro III address space must be mapped explicitly using z_ioremap() first
+     before it can be accessed:
+  
+-      virt_addr = ioremap(bus_addr, size);
++      virt_addr = z_ioremap(bus_addr, size);
+       ...
+-      iounmap(virt_addr);
++      z_iounmap(virt_addr);
+ 5. References
+ -------------
+ linux/include/linux/zorro.h
+-linux/include/linux/ioport.h
+-linux/include/asm-m68k/io.h
+-linux/include/asm-m68k/amigahw.h
+-linux/include/asm-ppc/io.h
++linux/include/asm-{m68k,ppc}/zorro.h
++linux/include/linux/zorro_ids.h
+ linux/drivers/zorro
+ /proc/bus/zorro
+--- linux-2.6.0-test6/drivers/acorn/block/fd1772.c     2003-09-08 13:58:56.000000000 -0700
++++ 25/drivers/acorn/block/fd1772.c    2003-10-05 00:34:00.000000000 -0700
+@@ -365,13 +365,12 @@ static void finish_fdc_done(int dummy);
+ static void floppy_off(unsigned int nr);
+ static void setup_req_params(int drive);
+ static void redo_fd_request(void);
+-static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int
++static int fd_ioctl(struct block_device *bdev, struct file *filp, unsigned int
+                   cmd, unsigned long param);
+ static void fd_probe(int drive);
+ static int fd_test_drive_present(int drive);
+ static void config_types(void);
+-static int floppy_open(struct inode *inode, struct file *filp);
+-static int floppy_release(struct inode *inode, struct file *filp);
++static int floppy_open(struct block_device *bdev, struct file *filp);
+ static void do_fd_request(request_queue_t *);
+ /************************* End of Prototypes **************************/
+@@ -1309,11 +1308,9 @@ static int invalidate_drive(struct block
+       return 0;
+ }
+-static int fd_ioctl(struct inode *inode, struct file *filp,
++static int fd_ioctl(struct block_device *bdev, struct file *filp,
+                   unsigned int cmd, unsigned long param)
+ {
+-      struct block_device *bdev = inode->i_bdev;
+-
+       switch (cmd) {
+       case FDFMTEND:
+       case FDFLUSH:
+@@ -1453,10 +1450,11 @@ static void config_types(void)
+  * drive with different device numbers.
+  */
+-static int floppy_open(struct inode *inode, struct file *filp)
++static int floppy_open(struct block_device *bdev, struct file *filp)
+ {
+-      int drive = iminor(inode) & 3;
+-      int type =  iminor(inode) >> 2;
++      struct archy_floppy_struct *p = bdev->bd_disk->private_data;
++      int drive = p - unit;
++      int type =  MINOR(bdev->bd_dev) >> 2;
+       int old_dev = fd_device[drive];
+       if (fd_ref[drive] && old_dev != type)
+@@ -1476,10 +1474,13 @@ static int floppy_open(struct inode *ino
+               return 0;
+       if (filp->f_mode & 3) {
+-              check_disk_change(inode->i_bdev);
++              check_disk_change(bdev);
+               if (filp->f_mode & 2) {
+-                      if (unit[drive].wpstat) {
+-                              floppy_release(inode, filp);
++                      if (p->wpstat) {
++                              if (fd_ref[drive] < 0)
++                                      fd_ref[drive] = 0;
++                              else
++                                      fd_ref[drive]--;
+                               return -EROFS;
+                       }
+               }
+@@ -1487,10 +1488,10 @@ static int floppy_open(struct inode *ino
+       return 0;
+ }
+-
+-static int floppy_release(struct inode *inode, struct file *filp)
++static int floppy_release(struct gendisk *disk)
+ {
+-      int drive = iminor(inode) & 3;
++      struct archy_floppy_struct *p = disk->private_data;
++      int drive = p - unit;
+       if (fd_ref[drive] < 0)
+               fd_ref[drive] = 0;
+--- linux-2.6.0-test6/drivers/acorn/block/mfmhd.c      2003-08-08 22:55:11.000000000 -0700
++++ 25/drivers/acorn/block/mfmhd.c     2003-10-05 00:33:54.000000000 -0700
+@@ -1153,9 +1153,9 @@ static int mfm_initdrives(void)
+  * The 'front' end of the mfm driver follows...
+  */
+-static int mfm_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg)
++static int mfm_ioctl(struct block_device *bdev, struct file *file, u_int cmd, u_long arg)
+ {
+-      struct mfm_info *p = inode->i_bdev->bd_disk->private_data;
++      struct mfm_info *p = bdev->bd_disk->private_data;
+       struct hd_geometry *geo = (struct hd_geometry *) arg;
+       if (cmd != HDIO_GETGEO)
+               return -EINVAL;
+@@ -1167,7 +1167,7 @@ static int mfm_ioctl(struct inode *inode
+               return -EFAULT;
+       if (put_user (p->cylinders, &geo->cylinders))
+               return -EFAULT;
+-      if (put_user (get_start_sect(inode->i_bdev), &geo->start))
++      if (put_user (get_start_sect(bdev), &geo->start))
+               return -EFAULT;
+       return 0;
+ }
+--- linux-2.6.0-test6/drivers/acpi/asus_acpi.c 2003-06-22 12:04:44.000000000 -0700
++++ 25/drivers/acpi/asus_acpi.c        2003-10-05 00:33:23.000000000 -0700
+@@ -26,13 +26,17 @@
+  *  Johann Wiesner - Small compile fixes
+  *  John Belmonte  - ACPI code for Toshiba laptop was a good starting point.
+  *
+- *  TODO
++ *  TODO:
+  *  add Fn key status
+- *  Add mode selection on module loading (parameter) -> still necessary ?
++ *  Add mode selection on module loading (parameter) -> still necessary?
+  *  Complete display switching -- may require dirty hacks?
+- *
+  */
++#include <linux/config.h>
++#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) && defined (MODULE)
++#include <linux/modversions.h>
++#endif
++
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/init.h>
+@@ -41,7 +45,7 @@
+ #include <acpi/acpi_drivers.h>
+ #include <acpi/acpi_bus.h>
+-#define ASUS_ACPI_VERSION "0.24a"
++#define ASUS_ACPI_VERSION "0.26"
+ #define PROC_ASUS       "asus"        //the directory
+ #define PROC_MLED       "mled"
+@@ -110,20 +114,24 @@ struct asus_hotk {
+       struct model_data *methods;     //methods available on the laptop
+       u8 brightness;                  //brighness level
+       enum {
+-              L2X = 0,        //L200D -> TODO check Q11 (Fn+F8)
+-                              //         Calling this method simply hang the
++              A1X=0,          //A1340D, A1300F
++              A2X,            //A2500H
++              D1X,            //D1
++              L1X,            //L1400B
++              L2X,            //L2000D -> TODO check Q11 (Fn+F8)
++                              //         Calling this method simply hangs the
+                               //         computer, ISMI method hangs the laptop.
+-              L3X,            //L3C
+               L3D,            //L3400D
++              L3X,            //L3C
++              L5X,            //L5C TODO this model seems to have one more
++                              //         LED, add support
+               M2X,            //M2400E
++              M3N,            //M3700N, but also S1300N -> TODO WLED
+               S1X,            //S1300A -> TODO special keys do not work ?
+-              D1X,            //D1
+-              L1X,            //L1400B
+-              A1X,            //A1340D, A1300F
+-              J1X,            //S200 (J1)
+-                              //TODO  A1370D does not seems to have a ATK device 
++              S2X,            //S200 (J1 reported), Victor MP-XP7210
++                              //TODO  A1370D does not seem to have an ATK device 
+                               //      L8400 model doesn't have ATK
+-              END_MODEL,
++              END_MODEL
+       } model;                //Models currently supported
+       u16 event_count[128];   //count for each event TODO make this better
+ };
+@@ -133,7 +141,8 @@ struct asus_hotk {
+ #define S1X_PREFIX "\\_SB.PCI0.PX40."
+ #define L1X_PREFIX S1X_PREFIX
+ #define A1X_PREFIX "\\_SB.PCI0.ISA.EC0."
+-#define J1X_PREFIX A1X_PREFIX
++#define S2X_PREFIX A1X_PREFIX
++#define M3N_PREFIX "\\_SB.PCI0.SBRG.EC0."
+ static struct model_data model_conf[END_MODEL] = {
+         /*
+@@ -147,33 +156,43 @@ static struct model_data model_conf[END_
+        * it seems to be a kind of switch, but what for ?
+        *
+        */
++      {"A1X", "MLED", "\\MAIL", NULL, NULL, A1X_PREFIX "_Q10", "\\BKLI",
++       A1X_PREFIX "_Q0E", A1X_PREFIX "_Q0F", NULL, NULL, NULL, NULL, NULL},
++
++      {"A2X", "MLED", NULL, "WLED", "\\SG66", "\\Q10", "\\BAOF",
++       "\\Q0E", "\\Q0F", "SPLV", "GPLV", "\\CMOD", "SDSP", "\\INFB"},
++
++      {"D1X", "MLED", NULL, NULL, NULL, "\\Q0D", "\\GP11", 
++       "\\Q0C", "\\Q0B", NULL, NULL, "\\BLVL", "SDSP","\\INFB"},
++
++      {"L1X", "MLED", NULL, "WLED", NULL, L1X_PREFIX "Q10", "\\PNOF", 
++       L1X_PREFIX "Q0F", L1X_PREFIX "Q0E", "SPLV", "GPLV", "\\BRIT", NULL, NULL},
++       
+       {"L2X", "MLED", "\\SGP6", "WLED", "\\RCP3", "\\Q10", "\\SGP0", 
+        "\\Q0E", "\\Q0F", NULL, NULL, NULL, "SDSP", "\\INFB"},
++      {"L3D", "MLED", "\\MALD", "WLED", NULL, "\\Q10", "\\BKLG",
++       "\\Q0E", "\\Q0F", "SPLV", "GPLV", "\\BLVL", "SDSP", "\\INFB"},
++
+       {"L3X", "MLED", NULL, "WLED", NULL, L3X_PREFIX "_Q10", "\\GL32", 
+        L3X_PREFIX "_Q0F", L3X_PREFIX "_Q0E", "SPLV", "GPLV", "\\BLVL", "SDSP", 
+        "\\_SB.PCI0.PCI1.VGAC.NMAP"},
+-      {"L3D", "MLED", "\\MALD", "WLED", NULL, "\\Q10", "\\BKLG",
+-       "\\Q0E", "\\Q0F", "SPLV", "GPLV", "\\BLVL", "SDSP", "\\INFB"},
+-
++      {"L5X", "MLED", NULL, "WLED", "WRED", "\\Q0D", "\\BAOF", 
++       "\\Q0C","\\Q0B", "SPLV", "GPLV", NULL, "SDSP", "\\INFB"},
++       
+       {"M2X", "MLED", NULL, "WLED", NULL, "\\Q10", "\\GP06", 
+        "\\Q0E","\\Q0F", "SPLV", "GPLV", NULL, "SDSP", "\\INFB"},
++
++      {"M3N", "MLED", NULL, "WLED", "\\PO33", M3N_PREFIX "_Q10", "\\BKLT", 
++       M3N_PREFIX "_Q0F", M3N_PREFIX "_Q0E", "SPLV", "GPLV", "\\LBTN", "SDSP", 
++       "\\ADVG"},
+       
+       {"S1X", "MLED", "\\EMLE", "WLED", NULL, S1X_PREFIX "Q10", "\\PNOF", 
+        S1X_PREFIX "Q0F", S1X_PREFIX "Q0E", "SPLV", "GPLV", "\\BRIT", NULL, NULL},
+       
+-      {"D1X", "MLED", NULL, NULL, NULL, "\\Q0D", "\\GP11", 
+-       "\\Q0C", "\\Q0B", NULL, NULL, "\\BLVL", "SDSP","\\INFB"},
+-
+-      {"L1X", "MLED", NULL, "WLED", NULL, L1X_PREFIX "Q10", "\\PNOF", 
+-       L1X_PREFIX "Q0F", L1X_PREFIX "Q0E", "SPLV", "GPLV", "\\BRIT", NULL, NULL},
+-
+-      {"A1X", "MLED", "\\MAIL", NULL, NULL, A1X_PREFIX "_Q10", "\\BKLI",
+-       A1X_PREFIX "_Q0E", A1X_PREFIX "_Q0F", NULL, NULL, NULL, NULL, NULL},
+-
+-      {"J1X", "MLED", "\\MAIL", NULL, NULL, J1X_PREFIX "_Q10", "\\BKLI",
+-       J1X_PREFIX "_Q0B", J1X_PREFIX "_Q0A", NULL, NULL, NULL, NULL, NULL}
++      {"S2X", "MLED", "\\MAIL", NULL, NULL, S2X_PREFIX "_Q10", "\\BKLI",
++       S2X_PREFIX "_Q0B", S2X_PREFIX "_Q0A", NULL, NULL, NULL, NULL, NULL}
+ };
+ /* procdir we use */
+@@ -234,7 +253,7 @@ static int read_acpi_int(acpi_handle han
+       output.length = sizeof(out_obj);
+       output.pointer = &out_obj;
+-      status = acpi_evaluate_object(handle, (char*) method, NULL, &output);
++      status = acpi_evaluate_object(handle, (char *) method, NULL, &output);
+       *val = out_obj.integer.value;
+       return (status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER);
+ }
+@@ -249,6 +268,7 @@ proc_read_info(char *page, char **start,
+               void *data)
+ {
+       int len = 0;
++      int sfun;
+       struct asus_hotk *hotk = (struct asus_hotk *) data;
+       char buf[16];           //enough for all info
+       /*
+@@ -257,28 +277,27 @@ proc_read_info(char *page, char **start,
+        */
+       len += sprintf(page, ACPI_HOTK_NAME " " ASUS_ACPI_VERSION "\n");
+-      len +=
+-          sprintf(page + len, "Model reference    : %s\n",
+-                  hotk->methods->name);
++      len += sprintf(page + len, "Model reference    : %s\n", 
++                     hotk->methods->name);
++      if(read_acpi_int(hotk->handle, "SFUN", &sfun))
++              len += sprintf(page + len, "SFUN value         : 0x%04x\n", sfun);
+       if (asus_info) {
+-              snprintf(buf, 5, "%s", asus_info->signature);
+-              len += sprintf(page + len, "ACPI signature     : %s\n", buf);
+               snprintf(buf, 16, "%d", asus_info->length);
+-              len += sprintf(page + len, "Table length       : %s\n", buf);
+-              snprintf(buf, 16, "%d", asus_info->revision);
+-              len += sprintf(page + len, "ACPI minor version : %s\n", buf);
++              len += sprintf(page + len, "DSDT length        : %s\n", buf);
+               snprintf(buf, 16, "%d", asus_info->checksum);
+-              len += sprintf(page + len, "Checksum           : %s\n", buf);
++              len += sprintf(page + len, "DSDT checksum      : %s\n", buf);
++              snprintf(buf, 16, "%d", asus_info->revision);
++              len += sprintf(page + len, "DSDT revision      : %s\n", buf);
+               snprintf(buf, 7, "%s", asus_info->oem_id);
+-              len += sprintf(page + len, "OEM identification : %s\n", buf);
++              len += sprintf(page + len, "OEM id             : %s\n", buf);
+               snprintf(buf, 9, "%s", asus_info->oem_table_id);
+               len += sprintf(page + len, "OEM table id       : %s\n", buf);
+               snprintf(buf, 16, "%x", asus_info->oem_revision);
+-              len += sprintf(page + len, "OEM rev number     : 0x%s\n", buf);
++              len += sprintf(page + len, "OEM revision       : 0x%s\n", buf);
+               snprintf(buf, 5, "%s", asus_info->asl_compiler_id);
+-              len += sprintf(page + len, "ASL comp vendor ID : %s\n", buf);
++              len += sprintf(page + len, "ASL comp vendor id : %s\n", buf);
+               snprintf(buf, 16, "%x", asus_info->asl_compiler_revision);
+-              len += sprintf(page + len, "ASL comp rev number: 0x%s\n", buf);
++              len += sprintf(page + len, "ASL comp revision  : 0x%s\n", buf);
+       }
+       return len;
+@@ -304,7 +323,7 @@ proc_read_mled(char *page, char **start,
+                                 &led_status))
+                       len =  sprintf(page, "%d\n", led_status);
+               else
+-                      printk(KERN_NOTICE "Asus ACPI: Error reading MLED "
++                      printk(KERN_WARNING "Asus ACPI: Error reading MLED "
+                              "status\n");
+       } else {
+               len = sprintf(page, "%d\n", (hotk->status & MLED_ON) ? 1 : 0);
+@@ -334,7 +353,7 @@ proc_write_mled(struct file *file, const
+       /* We don't have to check mt_mled exists if we are here :) */
+       if (!write_acpi_int(hotk->handle, hotk->methods->mt_mled, led_out,
+                           NULL))
+-              printk(KERN_NOTICE "Asus ACPI: MLED write failed\n");
++              printk(KERN_WARNING "Asus ACPI: MLED write failed\n");
+@@ -355,11 +374,11 @@ proc_read_wled(char *page, char **start,
+       int led_status;
+       if (hotk->methods->wled_status) {
+-              if (read_acpi_int(NULL, hotk->methods->mled_status, 
++              if (read_acpi_int(NULL, hotk->methods->wled_status, 
+                                 &led_status))
+                       len = sprintf(page, "%d\n", led_status);
+               else
+-                      printk(KERN_NOTICE "Asus ACPI: Error reading WLED "
++                      printk(KERN_WARNING "Asus ACPI: Error reading WLED "
+                              "status\n");
+       } else {
+               len = sprintf(page, "%d\n", (hotk->status & WLED_ON) ? 1 : 0);
+@@ -386,7 +405,7 @@ proc_write_wled(struct file *file, const
+       /* We don't have to check if mt_wled exists if we are here :) */
+       if (!write_acpi_int(hotk->handle, hotk->methods->mt_wled, led_out,
+                           NULL))
+-              printk(KERN_NOTICE "Asus ACPI: WLED write failed\n");
++              printk(KERN_WARNING "Asus ACPI: WLED write failed\n");
+       return count;
+@@ -399,7 +418,7 @@ static int get_lcd_state(struct asus_hot
+       /* We don't have to check anything, if we are here */
+       if (!read_acpi_int(NULL, hotk->methods->lcd_status, &lcd))
+-              printk(KERN_NOTICE "Asus ACPI: Error reading LCD status\n");
++              printk(KERN_WARNING "Asus ACPI: Error reading LCD status\n");
+       
+       if (hotk->model == L2X)
+               lcd = ~lcd;
+@@ -438,7 +457,7 @@ proc_write_lcd(struct file *file, const 
+                   acpi_evaluate_object(NULL, hotk->methods->mt_lcd_switch,
+                                        NULL, NULL);
+               if (ACPI_FAILURE(status))
+-                      printk(KERN_NOTICE "Asus ACPI: Error switching LCD\n");
++                      printk(KERN_WARNING "Asus ACPI: Error switching LCD\n");
+       }
+       return count;
+@@ -452,15 +471,15 @@ static void set_brightness(int value, st
+ {
+       acpi_status status = 0;
+-      /* ATKD laptop */
++      /* SPLV laptop */
+       if(hotk->methods->brightness_set) {
+               if (!write_acpi_int(hotk->handle, hotk->methods->brightness_set, 
+                                   value, NULL))
+-                      printk(KERN_NOTICE "Asus ACPI: Error changing brightness\n");
++                      printk(KERN_WARNING "Asus ACPI: Error changing brightness\n");
+               return;
+       }
+-      /* HOTK laptop if we are here, act as appropriate */
++      /* No SPLV method if we are here, act as appropriate */
+       value -= hotk->brightness;
+       while (value != 0) {
+               status = acpi_evaluate_object(NULL, (value > 0) ? 
+@@ -469,7 +488,7 @@ static void set_brightness(int value, st
+                                             NULL, NULL);
+               (value > 0) ? value-- : value++;
+               if (ACPI_FAILURE(status))
+-                      printk(KERN_NOTICE "Asus ACPI: Error changing brightness\n");
++                      printk(KERN_WARNING "Asus ACPI: Error changing brightness\n");
+       }
+       return;
+ }
+@@ -478,15 +497,15 @@ static int read_brightness(struct asus_h
+ {
+       int value;
+       
+-      if(hotk->methods->brightness_get) { /* ATKD laptop */
++      if(hotk->methods->brightness_get) { /* SPLV/GPLV laptop */
+               if (!read_acpi_int(hotk->handle, hotk->methods->brightness_get, 
+                                  &value))
+-                      printk(KERN_NOTICE "Asus ACPI: Error reading brightness\n");
++                      printk(KERN_WARNING "Asus ACPI: Error reading brightness\n");
+       } else if (hotk->methods->brightness_status) { /* For D1 for example */
+               if (!read_acpi_int(NULL, hotk->methods->brightness_status, 
+                                  &value))
+-                      printk(KERN_NOTICE "Asus ACPI: Error reading brightness\n");
+-      } else /* HOTK laptop */
++                      printk(KERN_WARNING "Asus ACPI: Error reading brightness\n");
++      } else /* No GPLV method */
+               value = hotk->brightness;
+       return value;
+ }
+@@ -512,7 +531,7 @@ proc_write_brn(struct file *file, const 
+                       /* 0 <= value <= 15 */
+               set_brightness(value, hotk);
+       } else {
+-              printk(KERN_NOTICE "Asus ACPI: Error reading user input\n");
++              printk(KERN_WARNING "Asus ACPI: Error reading user input\n");
+       }
+       return count;
+@@ -523,7 +542,7 @@ static void set_display(int value, struc
+       /* no sanity check needed for now */
+       if (!write_acpi_int(hotk->handle, hotk->methods->display_set, 
+                           value, NULL))
+-              printk(KERN_NOTICE "Asus ACPI: Error setting display\n");
++              printk(KERN_WARNING "Asus ACPI: Error setting display\n");
+       return;
+ }
+@@ -540,12 +559,12 @@ proc_read_disp(char *page, char **start,
+       struct asus_hotk *hotk = (struct asus_hotk *) data;
+       
+       if (!read_acpi_int(hotk->handle, hotk->methods->display_get, &value))
+-              printk(KERN_NOTICE "Asus ACPI: Error reading display status\n");
++              printk(KERN_WARNING "Asus ACPI: Error reading display status\n");
+       return sprintf(page, "%d\n", value);
+ }
+ /*
+- * Preliminary support for display switching. As of now: 0x01 should activate 
++ * Experimental support for display switching. As of now: 0x01 should activate 
+  * the LCD output, 0x02 should do for CRT, and 0x04 for TV-Out. Any combination 
+  * (bitwise) of these will suffice. I never actually tested 3 displays hooked up 
+  * simultaneously, so be warned.
+@@ -562,13 +581,13 @@ proc_write_disp(struct file *file, const
+       if (sscanf(buffer, "%d", &value) == 1)
+               set_display(value, hotk);
+       else {
+-              printk(KERN_NOTICE "Asus ACPI: Error reading user input\n");
++              printk(KERN_WARNING "Asus ACPI: Error reading user input\n");
+       }
+       return count;
+ }
+-static int asus_hotk_add_fs(struct acpi_device *device)
++static int __init asus_hotk_add_fs(struct acpi_device *device)
+ {
+       struct proc_dir_entry *proc;
+       struct asus_hotk *hotk = acpi_driver_data(device);
+@@ -582,7 +601,7 @@ static int asus_hotk_add_fs(struct acpi_
+       if ((asus_uid == 0) && (asus_gid == 0)){
+               mode = S_IFREG | S_IRUGO | S_IWUGO;
+-      }else{
++      } else {
+               mode = S_IFREG | S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP;
+       }
+@@ -598,7 +617,7 @@ static int asus_hotk_add_fs(struct acpi_
+               proc->uid = asus_uid;
+               proc->gid = asus_gid;;
+       } else {
+-              printk(KERN_NOTICE "  Unable to create " PROC_INFOS
++              printk(KERN_WARNING "  Unable to create " PROC_INFOS
+                      " fs entry\n");
+       }
+@@ -612,7 +631,7 @@ static int asus_hotk_add_fs(struct acpi_
+                       proc->uid = asus_uid;
+                       proc->gid = asus_gid;;
+               } else {
+-                      printk(KERN_NOTICE "  Unable to create " PROC_WLED
++                      printk(KERN_WARNING "  Unable to create " PROC_WLED
+                              " fs entry\n");
+               }
+       }
+@@ -627,7 +646,7 @@ static int asus_hotk_add_fs(struct acpi_
+                       proc->uid = asus_uid;
+                       proc->gid = asus_gid;;
+               } else {
+-                      printk(KERN_NOTICE "  Unable to create " PROC_MLED
++                      printk(KERN_WARNING "  Unable to create " PROC_MLED
+                              " fs entry\n");
+               }
+       }
+@@ -646,7 +665,7 @@ static int asus_hotk_add_fs(struct acpi_
+                       proc->uid = asus_uid;
+                       proc->gid = asus_gid;;
+               } else {
+-                      printk(KERN_NOTICE "  Unable to create " PROC_LCD
++                      printk(KERN_WARNING "  Unable to create " PROC_LCD
+                              " fs entry\n");
+               }
+       }
+@@ -662,7 +681,7 @@ static int asus_hotk_add_fs(struct acpi_
+                       proc->uid = asus_uid;
+                       proc->gid = asus_gid;;
+               } else {
+-                      printk(KERN_NOTICE "  Unable to create " PROC_BRN
++                      printk(KERN_WARNING "  Unable to create " PROC_BRN
+                              " fs entry\n");
+               }
+       }
+@@ -677,19 +696,19 @@ static int asus_hotk_add_fs(struct acpi_
+                       proc->uid = asus_uid;
+                       proc->gid = asus_gid;;
+               } else {
+-                      printk(KERN_NOTICE "  Unable to create " PROC_DISP
++                      printk(KERN_WARNING "  Unable to create " PROC_DISP
+                              " fs entry\n");
+               }
+       }
+-      return (AE_OK);
++      return 0;
+ }
+ static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
+ {
+       /* TODO Find a better way to handle events count. Here, in data, we receive
+-       * the hotk, so we can make anything !!
++       * the hotk, so we can do anything!
+        */
+       struct asus_hotk *hotk = (struct asus_hotk *) data;
+@@ -712,19 +731,40 @@ static void asus_hotk_notify(acpi_handle
+  * This function is used to initialize the hotk with right values. In this
+  * method, we can make all the detection we want, and modify the hotk struct
+  */
+-static int asus_hotk_get_info(struct asus_hotk *hotk)
++static int __init asus_hotk_get_info(struct asus_hotk *hotk)
+ {
+       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
++      struct acpi_buffer dsdt = { ACPI_ALLOCATE_BUFFER, NULL };
+       union acpi_object *model = NULL;
++      int bsts_result;
++      acpi_status status;
+-      /* 
+-       * We have to write 0 on init this far for all ASUS models
++      /*
++       * Get DSDT headers early enough to allow for differentiating between 
++       * models, but late enough to allow acpi_bus_register_driver() to fail 
++       * before doing anything ACPI-specific. Should we encounter a machine,
++       * which needs special handling (i.e. its hotkey device has a different
++       * HID), this bit will be moved. A global variable asus_info contains
++       * the DSDT header.
+        */
++      status = acpi_get_table(ACPI_TABLE_DSDT, 1, &dsdt);
++      if (ACPI_FAILURE(status))
++              printk(KERN_WARNING "  Couldn't get the DSDT table header\n");
++      else
++              asus_info = (struct acpi_table_header *) dsdt.pointer;
++
++      /* We have to write 0 on init this far for all ASUS models */
+       if (!write_acpi_int(hotk->handle, "INIT", 0, &buffer)) {
+-              printk(KERN_NOTICE "  Hotkey initialization failed\n");
++              printk(KERN_ERR "  Hotkey initialization failed\n");
+               return -ENODEV;
+       }
++      /* For testing purposes */
++      if (!read_acpi_int(hotk->handle, "BSTS", &bsts_result))
++              printk(KERN_WARNING "  Error calling BSTS\n");
++      else if (bsts_result)
++              printk(KERN_NOTICE "  BSTS called, 0x%02x returned\n", bsts_result);
++
+       /*
+        * Here, we also use asus_info to make decision. For example, on INIT
+        * method, S1X and L1X models both reports to be L84F, but they don't
+@@ -749,26 +789,34 @@ static int asus_hotk_get_info(struct asu
+               hotk->model = L3X;
+       else if (strncmp(model->string.pointer, "M2", 2) == 0)
+               hotk->model = M2X;
++      else if (strncmp(model->string.pointer, "M3N", 3) == 0 ||
++               strncmp(model->string.pointer, "S1N", 3) == 0)
++              hotk->model = M3N; /* S1300N is similar enough */
+       else if (strncmp(model->string.pointer, "L2", 2) == 0)
+               hotk->model = L2X;
+-      else if (strncmp(model->string.pointer, "L8", 2) == 0)
++      else if (strncmp(model->string.pointer, "L8", 2) == 0) {
+               /* S1300A reports L84F, but L1400B too */
+-              if (strncmp(asus_info->oem_table_id, "L1", 2) == 0)
+-                      hotk->model = L1X;
+-              else
++              if (asus_info) {
++                      if (strncmp(asus_info->oem_table_id, "L1", 2) == 0)
++                              hotk->model = L1X;
++              } else
+                       hotk->model = S1X;
++      }
+       else if (strncmp(model->string.pointer, "D1", 2) == 0)
+               hotk->model = D1X;
+       else if (strncmp(model->string.pointer, "A1", 2) == 0)
+               hotk->model = A1X;
++      else if (strncmp(model->string.pointer, "A2", 2) == 0)
++              hotk->model = A2X;
+       else if (strncmp(model->string.pointer, "J1", 2) == 0)
+-              hotk->model = J1X;
+-
++              hotk->model = S2X;
++      else if (strncmp(model->string.pointer, "L5", 2) == 0)
++              hotk->model = L5X;
+       if (hotk->model == END_MODEL) {
+               /* By default use the same values, as I don't know others */
+-              printk("unsupported, trying default values, contact the "
+-                     "developers\n");
++              printk("unsupported, trying default values, supply the "
++                     "developers with your DSDT\n");
+               hotk->model = L2X;
+       } else {
+               printk("supported\n");
+@@ -783,7 +831,7 @@ static int asus_hotk_get_info(struct asu
+-static int asus_hotk_check(struct asus_hotk *hotk)
++static int __init asus_hotk_check(struct asus_hotk *hotk)
+ {
+       int result = 0;
+@@ -797,7 +845,7 @@ static int asus_hotk_check(struct asus_h
+       if (hotk->device->status.present) {
+               result = asus_hotk_get_info(hotk);
+       } else {
+-              printk(KERN_NOTICE "  Hotkey device not present, aborting\n");
++              printk(KERN_ERR "  Hotkey device not present, aborting\n");
+               return(-EINVAL);
+       }
+@@ -806,7 +854,7 @@ static int asus_hotk_check(struct asus_h
+-static int asus_hotk_add(struct acpi_device *device)
++static int __init asus_hotk_add(struct acpi_device *device)
+ {
+       struct asus_hotk *hotk = NULL;
+       acpi_status status = AE_OK;
+@@ -815,6 +863,9 @@ static int asus_hotk_add(struct acpi_dev
+       if (!device)
+               return(-EINVAL);
++      printk(KERN_NOTICE "Asus Laptop ACPI Extras version %s\n",
++             ASUS_ACPI_VERSION);
++
+       hotk =
+           (struct asus_hotk *) kmalloc(sizeof(struct asus_hotk), GFP_KERNEL);
+       if (!hotk)
+@@ -842,25 +893,23 @@ static int asus_hotk_add(struct acpi_dev
+        */
+       status = acpi_install_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY,
+                                            asus_hotk_notify, hotk);
+-      if (ACPI_FAILURE(status)) {
+-              printk(KERN_NOTICE
+-                     "  Error installing notify handler\n");
+-      } else {
+-              printk(KERN_DEBUG
+-                     "  Notify Handler installed successfully\n");
+-      }
++      if (ACPI_FAILURE(status))
++              printk(KERN_ERR "  Error installing notify handler\n");
+-      /* For HOTK laptops: init the hotk->brightness value */
++      /* For laptops without GPLV: init the hotk->brightness value */
+       if ((!hotk->methods->brightness_get) && (!hotk->methods->brightness_status) &&
+           (hotk->methods->brightness_up && hotk->methods->brightness_down)) {
+               status = acpi_evaluate_object(NULL, hotk->methods->brightness_down,
+                                             NULL, NULL);
+               if (ACPI_FAILURE(status))
+-                      printk(KERN_NOTICE "  Error changing brightness\n");
+-              status = acpi_evaluate_object(NULL, hotk->methods->brightness_up,
+-                                            NULL, NULL);
+-              if (ACPI_FAILURE(status))
+-                      printk(KERN_NOTICE "  Error changing brightness\n");
++                      printk(KERN_WARNING "  Error changing brightness\n");
++              else {
++                      status = acpi_evaluate_object(NULL, hotk->methods->brightness_up,
++                                                    NULL, NULL);
++                      if (ACPI_FAILURE(status))
++                              printk(KERN_WARNING "  Strange, error changing" 
++                                     " brightness\n");
++              }
+       }
+       end:
+@@ -887,7 +936,7 @@ static int asus_hotk_remove(struct acpi_
+       status = acpi_remove_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY,
+                                           asus_hotk_notify);
+       if (ACPI_FAILURE(status))
+-              printk(KERN_NOTICE "Error removing notify handler\n");
++              printk(KERN_ERR "Asus ACPI: Error removing notify handler\n");
+       kfree(hotk);
+@@ -899,35 +948,17 @@ static int asus_hotk_remove(struct acpi_
+ static int __init asus_acpi_init(void)
+ {
+-      int result = 0;
+-      acpi_status status = 0;
+-      struct acpi_buffer dsdt = { ACPI_ALLOCATE_BUFFER, NULL };
+-
+-      printk(KERN_NOTICE "Asus Laptop ACPI Extras version %s\n",
+-             ASUS_ACPI_VERSION);
+-      /*
+-       * Here is the code to know the model we are running on. We need to
+-       * know this before calling the acpi_bus_register_driver function, in
+-       * case the HID for the laptop we are running on is different from
+-       * ACPI_HOTK_HID, which I have never seen yet :)
+-       * 
+-       * This information is then available in the global var asus_info
+-       */
+-      status = acpi_get_table(ACPI_TABLE_DSDT, 1, &dsdt);
+-      if (ACPI_FAILURE(status)) {
+-              printk(KERN_NOTICE "  Couldn't get the DSDT table header\n");
+-      } else {
+-              asus_info = (struct acpi_table_header *) dsdt.pointer;
+-      }
++      int result;
+       asus_proc_dir = proc_mkdir(PROC_ASUS, acpi_root_dir);
+-      if (!asus_proc_dir)
++      if (!asus_proc_dir) {
++              printk(KERN_ERR "Asus ACPI: Unable to create /proc entry");
+               return(-ENODEV);
++      }
+       asus_proc_dir->owner = THIS_MODULE;
+       result = acpi_bus_register_driver(&asus_hotk_driver);
+       if (result < 0) {
+-              printk(KERN_NOTICE "  Error registering " ACPI_HOTK_NAME " \n");
+               remove_proc_entry(PROC_ASUS, acpi_root_dir);
+               return(-ENODEV);
+       }
+--- linux-2.6.0-test6/drivers/acpi/bus.c       2003-08-22 19:23:40.000000000 -0700
++++ 25/drivers/acpi/bus.c      2003-10-05 00:33:23.000000000 -0700
+@@ -634,8 +634,7 @@ acpi_bus_init (void)
+        * the EC parameters out of that.
+        */
+       status = acpi_ec_ecdt_probe();
+-      if (ACPI_FAILURE(status))
+-              goto error1;
++      /* Ignore result. Not having an ECDT is not fatal. */
+ #endif
+       status = acpi_initialize_objects(ACPI_FULL_INITIALIZATION);
+--- linux-2.6.0-test6/drivers/acpi/dispatcher/dsfield.c        2003-06-14 12:18:25.000000000 -0700
++++ 25/drivers/acpi/dispatcher/dsfield.c       2003-10-05 00:33:23.000000000 -0700
+@@ -105,27 +105,33 @@ acpi_ds_create_buffer_field (
+               return_ACPI_STATUS (AE_AML_NO_OPERAND);
+       }
+-      /*
+-       * During the load phase, we want to enter the name of the field into
+-       * the namespace.  During the execute phase (when we evaluate the size
+-       * operand), we want to lookup the name
+-       */
+-      if (walk_state->parse_flags & ACPI_PARSE_EXECUTE) {
+-              flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE;
++      if (walk_state->deferred_node) {
++              node = walk_state->deferred_node;
++              status = AE_OK;
+       }
+       else {
+-              flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND;
+-      }
++              /*
++               * During the load phase, we want to enter the name of the field into
++               * the namespace.  During the execute phase (when we evaluate the size
++               * operand), we want to lookup the name
++               */
++              if (walk_state->parse_flags & ACPI_PARSE_EXECUTE) {
++                      flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE;
++              }
++              else {
++                      flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND;
++              }
+-      /*
+-       * Enter the name_string into the namespace
+-       */
+-      status = acpi_ns_lookup (walk_state->scope_info, arg->common.value.string,
+-                       ACPI_TYPE_ANY, ACPI_IMODE_LOAD_PASS1,
+-                       flags, walk_state, &(node));
+-      if (ACPI_FAILURE (status)) {
+-              ACPI_REPORT_NSERROR (arg->common.value.string, status);
+-              return_ACPI_STATUS (status);
++              /*
++               * Enter the name_string into the namespace
++               */
++              status = acpi_ns_lookup (walk_state->scope_info, arg->common.value.string,
++                               ACPI_TYPE_ANY, ACPI_IMODE_LOAD_PASS1,
++                               flags, walk_state, &(node));
++              if (ACPI_FAILURE (status)) {
++                      ACPI_REPORT_NSERROR (arg->common.value.string, status);
++                      return_ACPI_STATUS (status);
++              }
+       }
+       /* We could put the returned object (Node) on the object stack for later, but
+--- linux-2.6.0-test6/drivers/acpi/dispatcher/dsinit.c 2003-06-14 12:18:34.000000000 -0700
++++ 25/drivers/acpi/dispatcher/dsinit.c        2003-10-05 00:33:23.000000000 -0700
+@@ -135,7 +135,7 @@ acpi_ds_init_one_object (
+               }
+               /*
+-               * Always parse methods to detect errors, we may delete
++               * Always parse methods to detect errors, we will delete
+                * the parse tree below
+                */
+               status = acpi_ds_parse_method (obj_handle);
+@@ -150,7 +150,7 @@ acpi_ds_init_one_object (
+               }
+               /*
+-               * Delete the parse tree.  We simple re-parse the method
++               * Delete the parse tree.  We simply re-parse the method
+                * for every execution since there isn't much overhead
+                */
+               acpi_ns_delete_namespace_subtree (obj_handle);
+--- linux-2.6.0-test6/drivers/acpi/dispatcher/dsopcode.c       2003-06-14 12:18:30.000000000 -0700
++++ 25/drivers/acpi/dispatcher/dsopcode.c      2003-10-05 00:33:23.000000000 -0700
+@@ -65,7 +65,7 @@
+  *
+  * RETURN:      Status.
+  *
+- * DESCRIPTION: Late execution of region or field arguments
++ * DESCRIPTION: Late (deferred) execution of region or field arguments
+  *
+  ****************************************************************************/
+@@ -111,7 +111,10 @@ acpi_ds_execute_arguments (
+               return_ACPI_STATUS (status);
+       }
++      /* Mark this parse as a deferred opcode */
++
+       walk_state->parse_flags = ACPI_PARSE_DEFERRED_OP;
++      walk_state->deferred_node = node;
+       /* Pass1: Parse the entire declaration */
+@@ -128,7 +131,7 @@ acpi_ds_execute_arguments (
+       arg->common.node = node;
+       acpi_ps_delete_parse_tree (op);
+-      /* Evaluate the address and length arguments for the Buffer Field */
++      /* Evaluate the deferred arguments */
+       op = acpi_ps_alloc_op (AML_INT_EVAL_SUBTREE_OP);
+       if (!op) {
+@@ -144,6 +147,8 @@ acpi_ds_execute_arguments (
+               return_ACPI_STATUS (AE_NO_MEMORY);
+       }
++      /* Execute the opcode and arguments */
++
+       status = acpi_ds_init_aml_walk (walk_state, op, NULL, aml_start,
+                         aml_length, NULL, NULL, 3);
+       if (ACPI_FAILURE (status)) {
+@@ -151,6 +156,9 @@ acpi_ds_execute_arguments (
+               return_ACPI_STATUS (status);
+       }
++      /* Mark this execution as a deferred opcode */
++
++      walk_state->deferred_node = node;
+       status = acpi_ps_parse_aml (walk_state);
+       acpi_ps_delete_parse_tree (op);
+       return_ACPI_STATUS (status);
+@@ -192,7 +200,7 @@ acpi_ds_get_buffer_field_arguments (
+       node = obj_desc->buffer_field.node;
+       ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname (ACPI_TYPE_BUFFER_FIELD, node, NULL));
+-      ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[%4.4s] buffer_field JIT Init\n",
++      ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[%4.4s] buffer_field Arg Init\n",
+               node->name.ascii));
+       /* Execute the AML code for the term_arg arguments */
+@@ -207,7 +215,7 @@ acpi_ds_get_buffer_field_arguments (
+  *
+  * FUNCTION:    acpi_ds_get_buffer_arguments
+  *
+- * PARAMETERS:  obj_desc        - A valid Bufferobject
++ * PARAMETERS:  obj_desc        - A valid Buffer object
+  *
+  * RETURN:      Status.
+  *
+@@ -240,7 +248,7 @@ acpi_ds_get_buffer_arguments (
+               return_ACPI_STATUS (AE_AML_INTERNAL);
+       }
+-      ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Buffer JIT Init\n"));
++      ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Buffer Arg Init\n"));
+       /* Execute the AML code for the term_arg arguments */
+@@ -254,7 +262,7 @@ acpi_ds_get_buffer_arguments (
+  *
+  * FUNCTION:    acpi_ds_get_package_arguments
+  *
+- * PARAMETERS:  obj_desc        - A valid Packageobject
++ * PARAMETERS:  obj_desc        - A valid Package object
+  *
+  * RETURN:      Status.
+  *
+@@ -287,7 +295,7 @@ acpi_ds_get_package_arguments (
+               return_ACPI_STATUS (AE_AML_INTERNAL);
+       }
+-      ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Package JIT Init\n"));
++      ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Package Arg Init\n"));
+       /* Execute the AML code for the term_arg arguments */
+@@ -335,11 +343,12 @@ acpi_ds_get_region_arguments (
+       node = obj_desc->region.node;
+-      ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname (ACPI_TYPE_REGION, node, NULL));
++      ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_REGION, node, NULL));
+-      ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[%4.4s] op_region Init at AML %p\n",
++      ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[%4.4s] op_region Arg Init at AML %p\n",
+               node->name.ascii, extra_desc->extra.aml_start));
++      /* Execute the argument AML */
+       status = acpi_ds_execute_arguments (node, acpi_ns_get_parent_node (node),
+                        extra_desc->extra.aml_length, extra_desc->extra.aml_start);
+@@ -505,14 +514,16 @@ acpi_ds_init_buffer_field (
+               goto cleanup;
+       }
+-
+       /* Entire field must fit within the current length of the buffer */
+       if ((bit_offset + bit_count) >
+               (8 * (u32) buffer_desc->buffer.length)) {
+               ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+-                      "Field size %d exceeds Buffer size %d (bits)\n",
+-                       bit_offset + bit_count, 8 * (u32) buffer_desc->buffer.length));
++                      "Field [%4.4s] size %d exceeds Buffer [%4.4s] size %d (bits)\n",
++                      ((struct acpi_namespace_node *) result_desc)->name.ascii,
++                       bit_offset + bit_count,
++                       buffer_desc->buffer.node->name.ascii,
++                       8 * (u32) buffer_desc->buffer.length));
+               status = AE_AML_BUFFER_LIMIT;
+               goto cleanup;
+       }
+--- linux-2.6.0-test6/drivers/acpi/dispatcher/dsutils.c        2003-06-14 12:18:09.000000000 -0700
++++ 25/drivers/acpi/dispatcher/dsutils.c       2003-10-05 00:33:23.000000000 -0700
+@@ -53,6 +53,7 @@
+ #define _COMPONENT          ACPI_DISPATCHER
+        ACPI_MODULE_NAME    ("dsutils")
++
+ #ifndef ACPI_NO_METHOD_EXECUTION
+ /*******************************************************************************
+@@ -196,7 +197,6 @@ result_not_used:
+                       acpi_ps_get_opcode_name (op->common.parent->common.aml_opcode), op));
+       return_VALUE (FALSE);
+-
+ }
+@@ -239,7 +239,6 @@ acpi_ds_delete_result_if_not_used (
+               return_VOID;
+       }
+-
+       if (!acpi_ds_is_result_used (op, walk_state)) {
+               /*
+                * Must pop the result stack (obj_desc should be equal to result_obj)
+@@ -389,61 +388,77 @@ acpi_ds_create_operand (
+                * in name_string
+                */
++
+               /*
+-               * Differentiate between a namespace "create" operation
+-               * versus a "lookup" operation (IMODE_LOAD_PASS2 vs.
+-               * IMODE_EXECUTE) in order to support the creation of
+-               * namespace objects during the execution of control methods.
++               * Special handling for buffer_field declarations. This is a deferred
++               * opcode that unfortunately defines the field name as the last
++               * parameter instead of the first.  We get here when we are performing
++               * the deferred execution, so the actual name of the field is already
++               * in the namespace.  We don't want to attempt to look it up again
++               * because we may be executing in a different scope than where the
++               * actual opcode exists.
+                */
+-              parent_op = arg->common.parent;
+-              op_info = acpi_ps_get_opcode_info (parent_op->common.aml_opcode);
+-              if ((op_info->flags & AML_NSNODE) &&
+-                      (parent_op->common.aml_opcode != AML_INT_METHODCALL_OP) &&
+-                      (parent_op->common.aml_opcode != AML_REGION_OP) &&
+-                      (parent_op->common.aml_opcode != AML_INT_NAMEPATH_OP)) {
+-                      /* Enter name into namespace if not found */
+-
+-                      interpreter_mode = ACPI_IMODE_LOAD_PASS2;
++              if ((walk_state->deferred_node) &&
++                      (walk_state->deferred_node->type == ACPI_TYPE_BUFFER_FIELD) &&
++                      (arg_index != 0)) {
++                      obj_desc = ACPI_CAST_PTR (union acpi_operand_object, walk_state->deferred_node);
++                      status = AE_OK;
+               }
++              else    /* All other opcodes */ {
++                      /*
++                       * Differentiate between a namespace "create" operation
++                       * versus a "lookup" operation (IMODE_LOAD_PASS2 vs.
++                       * IMODE_EXECUTE) in order to support the creation of
++                       * namespace objects during the execution of control methods.
++                       */
++                      parent_op = arg->common.parent;
++                      op_info = acpi_ps_get_opcode_info (parent_op->common.aml_opcode);
++                      if ((op_info->flags & AML_NSNODE) &&
++                              (parent_op->common.aml_opcode != AML_INT_METHODCALL_OP) &&
++                              (parent_op->common.aml_opcode != AML_REGION_OP) &&
++                              (parent_op->common.aml_opcode != AML_INT_NAMEPATH_OP)) {
++                              /* Enter name into namespace if not found */
+-              else {
+-                      /* Return a failure if name not found */
+-
+-                      interpreter_mode = ACPI_IMODE_EXECUTE;
+-              }
++                              interpreter_mode = ACPI_IMODE_LOAD_PASS2;
++                      }
++                      else {
++                              /* Return a failure if name not found */
+-              status = acpi_ns_lookup (walk_state->scope_info, name_string,
+-                               ACPI_TYPE_ANY, interpreter_mode,
+-                               ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE,
+-                               walk_state,
+-                               ACPI_CAST_INDIRECT_PTR (struct acpi_namespace_node, &obj_desc));
+-              /*
+-               * The only case where we pass through (ignore) a NOT_FOUND
+-               * error is for the cond_ref_of opcode.
+-               */
+-              if (status == AE_NOT_FOUND) {
+-                      if (parent_op->common.aml_opcode == AML_COND_REF_OF_OP) {
+-                              /*
+-                               * For the Conditional Reference op, it's OK if
+-                               * the name is not found;  We just need a way to
+-                               * indicate this to the interpreter, set the
+-                               * object to the root
+-                               */
+-                              obj_desc = ACPI_CAST_PTR (union acpi_operand_object, acpi_gbl_root_node);
+-                              status = AE_OK;
++                              interpreter_mode = ACPI_IMODE_EXECUTE;
+                       }
+-                      else {
+-                              /*
+-                               * We just plain didn't find it -- which is a
+-                               * very serious error at this point
+-                               */
+-                              status = AE_AML_NAME_NOT_FOUND;
++                      status = acpi_ns_lookup (walk_state->scope_info, name_string,
++                                       ACPI_TYPE_ANY, interpreter_mode,
++                                       ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE,
++                                       walk_state,
++                                       ACPI_CAST_INDIRECT_PTR (struct acpi_namespace_node, &obj_desc));
++                      /*
++                       * The only case where we pass through (ignore) a NOT_FOUND
++                       * error is for the cond_ref_of opcode.
++                       */
++                      if (status == AE_NOT_FOUND) {
++                              if (parent_op->common.aml_opcode == AML_COND_REF_OF_OP) {
++                                      /*
++                                       * For the Conditional Reference op, it's OK if
++                                       * the name is not found;  We just need a way to
++                                       * indicate this to the interpreter, set the
++                                       * object to the root
++                                       */
++                                      obj_desc = ACPI_CAST_PTR (union acpi_operand_object, acpi_gbl_root_node);
++                                      status = AE_OK;
++                              }
++                              else {
++                                      /*
++                                       * We just plain didn't find it -- which is a
++                                       * very serious error at this point
++                                       */
++                                      status = AE_AML_NAME_NOT_FOUND;
++                              }
+                       }
+-              }
+-              if (ACPI_FAILURE (status)) {
+-                      ACPI_REPORT_NSERROR (name_string, status);
++                      if (ACPI_FAILURE (status)) {
++                              ACPI_REPORT_NSERROR (name_string, status);
++                      }
+               }
+               /* Free the namestring created above */
+@@ -464,8 +479,6 @@ acpi_ds_create_operand (
+               }
+               ACPI_DEBUGGER_EXEC (acpi_db_display_argument_object (obj_desc, walk_state));
+       }
+-
+-
+       else {
+               /* Check for null name case */
+@@ -480,7 +493,6 @@ acpi_ds_create_operand (
+                       ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Null namepath: Arg=%p\n", arg));
+               }
+-
+               else {
+                       opcode = arg->common.aml_opcode;
+               }
+--- linux-2.6.0-test6/drivers/acpi/dispatcher/dswload.c        2003-06-14 12:17:57.000000000 -0700
++++ 25/drivers/acpi/dispatcher/dswload.c       2003-10-05 00:33:23.000000000 -0700
+@@ -248,6 +248,14 @@ acpi_ds_load1_begin_op (
+                *       buffer_field, or Package), the name of the object is already
+                *       in the namespace.
+                */
++              if (walk_state->deferred_node) {
++                      /* This name is already in the namespace, get the node */
++
++                      node = walk_state->deferred_node;
++                      status = AE_OK;
++                      break;
++              }
++
+               flags = ACPI_NS_NO_UPSEARCH;
+               if ((walk_state->opcode != AML_SCOPE_OP) &&
+                       (!(walk_state->parse_flags & ACPI_PARSE_DEFERRED_OP))) {
+@@ -589,7 +597,17 @@ acpi_ds_load2_begin_op (
+                * Enter the named type into the internal namespace.  We enter the name
+                * as we go downward in the parse tree.  Any necessary subobjects that involve
+                * arguments to the opcode must be created as we go back up the parse tree later.
++               *
++               * Note: Name may already exist if we are executing a deferred opcode.
+                */
++              if (walk_state->deferred_node) {
++                      /* This name is already in the namespace, get the node */
++
++                      node = walk_state->deferred_node;
++                      status = AE_OK;
++                      break;
++              }
++
+               status = acpi_ns_lookup (walk_state->scope_info, buffer_ptr, object_type,
+                                 ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, walk_state, &(node));
+               break;
+--- linux-2.6.0-test6/drivers/acpi/dispatcher/dswscope.c       2003-06-14 12:18:51.000000000 -0700
++++ 25/drivers/acpi/dispatcher/dswscope.c      2003-10-05 00:33:23.000000000 -0700
+@@ -121,10 +121,9 @@ acpi_ds_scope_stack_push (
+       /* Make sure object type is valid */
+       if (!acpi_ut_valid_object_type (type)) {
+-              ACPI_REPORT_WARNING (("ds_scope_stack_push: type code out of range\n"));
++              ACPI_REPORT_WARNING (("ds_scope_stack_push: Invalid object type: 0x%X\n", type));
+       }
+-
+       /* Allocate a new scope object */
+       scope_info = acpi_ut_create_generic_state ();
+@@ -146,13 +145,13 @@ acpi_ds_scope_stack_push (
+       old_scope_info = walk_state->scope_info;
+       if (old_scope_info) {
+               ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC,
+-                      "[%4.4s] (%10s)",
++                      "[%4.4s] (%s)",
+                       old_scope_info->scope.node->name.ascii,
+                       acpi_ut_get_type_name (old_scope_info->common.value)));
+       }
+       else {
+               ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC,
+-                      "[\\___] (%10s)", "ROOT"));
++                      "[\\___] (%s)", "ROOT"));
+       }
+       ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC,
+@@ -163,7 +162,6 @@ acpi_ds_scope_stack_push (
+       /* Push new scope object onto stack */
+       acpi_ut_push_generic_state (&walk_state->scope_info, scope_info);
+-
+       return_ACPI_STATUS (AE_OK);
+ }
+@@ -207,7 +205,7 @@ acpi_ds_scope_stack_pop (
+       walk_state->scope_depth--;
+       ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+-              "[%.2d] Popped scope [%4.4s] (%10s), New scope -> ",
++              "[%.2d] Popped scope [%4.4s] (%s), New scope -> ",
+               (u32) walk_state->scope_depth,
+               scope_info->scope.node->name.ascii,
+               acpi_ut_get_type_name (scope_info->common.value)));
+@@ -225,7 +223,6 @@ acpi_ds_scope_stack_pop (
+       }
+       acpi_ut_delete_generic_state (scope_info);
+-
+       return_ACPI_STATUS (AE_OK);
+ }
+--- linux-2.6.0-test6/drivers/acpi/dispatcher/dswstate.c       2003-06-14 12:18:32.000000000 -0700
++++ 25/drivers/acpi/dispatcher/dswstate.c      2003-10-05 00:33:23.000000000 -0700
+@@ -56,11 +56,12 @@
+  * FUNCTION:    acpi_ds_result_insert
+  *
+  * PARAMETERS:  Object              - Object to push
++ *              Index               - Where to insert the object
+  *              walk_state          - Current Walk state
+  *
+  * RETURN:      Status
+  *
+- * DESCRIPTION: Push an object onto this walk's result stack
++ * DESCRIPTION: Insert an object onto this walk's result stack
+  *
+  ******************************************************************************/
+@@ -114,6 +115,7 @@ acpi_ds_result_insert (
+  * FUNCTION:    acpi_ds_result_remove
+  *
+  * PARAMETERS:  Object              - Where to return the popped object
++ *              Index               - Where to extract the object
+  *              walk_state          - Current Walk state
+  *
+  * RETURN:      Status
+@@ -233,6 +235,7 @@ acpi_ds_result_pop (
+       return (AE_AML_NO_RETURN_VALUE);
+ }
++
+ /*******************************************************************************
+  *
+  * FUNCTION:    acpi_ds_result_pop_from_bottom
+@@ -295,7 +298,6 @@ acpi_ds_result_pop_from_bottom (
+               *object, (*object) ? acpi_ut_get_object_type_name (*object) : "NULL",
+               state, walk_state));
+-
+       return (AE_OK);
+ }
+@@ -358,8 +360,7 @@ acpi_ds_result_push (
+  *
+  * FUNCTION:    acpi_ds_result_stack_push
+  *
+- * PARAMETERS:  Object              - Object to push
+- *              walk_state          - Current Walk state
++ * PARAMETERS:  walk_state          - Current Walk state
+  *
+  * RETURN:      Status
+  *
+@@ -420,7 +421,6 @@ acpi_ds_result_stack_pop (
+               return (AE_AML_NO_OPERAND);
+       }
+-
+       state = acpi_ut_pop_generic_state (&walk_state->results);
+       ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+@@ -572,6 +572,7 @@ acpi_ds_obj_stack_pop_object (
+ }
+ #endif
++
+ /*******************************************************************************
+  *
+  * FUNCTION:    acpi_ds_obj_stack_pop
+@@ -641,6 +642,7 @@ acpi_ds_obj_stack_pop_and_delete (
+       u32                             i;
+       union acpi_operand_object       *obj_desc;
++
+       ACPI_FUNCTION_NAME ("ds_obj_stack_pop_and_delete");
+@@ -883,8 +885,15 @@ acpi_ds_create_walk_state (
+  * FUNCTION:    acpi_ds_init_aml_walk
+  *
+  * PARAMETERS:  walk_state      - New state to be initialized
++ *              Op              - Current parse op
++ *              method_node     - Control method NS node, if any
++ *              aml_start       - Start of AML
++ *              aml_length      - Length of AML
++ *              Params          - Method args, if any
++ *              return_obj_desc - Where to store a return object, if any
++ *              pass_number     - 1, 2, or 3
+  *
+- * RETURN:      None
++ * RETURN:      Status
+  *
+  * DESCRIPTION: Initialize a walk state for a pass 1 or 2 parse tree walk
+  *
+@@ -927,9 +936,9 @@ acpi_ds_init_aml_walk (
+       if (method_node) {
+               walk_state->parser_state.start_node = method_node;
+-              walk_state->walk_type               = ACPI_WALK_METHOD;
+-              walk_state->method_node             = method_node;
+-              walk_state->method_desc             = acpi_ns_get_attached_object (method_node);
++              walk_state->walk_type            = ACPI_WALK_METHOD;
++              walk_state->method_node          = method_node;
++              walk_state->method_desc          = acpi_ns_get_attached_object (method_node);
+               /* Push start scope on scope stack and make it current  */
+@@ -956,6 +965,7 @@ acpi_ds_init_aml_walk (
+               while (extra_op && !extra_op->common.node) {
+                       extra_op = extra_op->common.parent;
+               }
++
+               if (!extra_op) {
+                       parser_state->start_node = NULL;
+               }
+@@ -1014,7 +1024,7 @@ acpi_ds_delete_walk_state (
+               ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p walk still has a scope list\n", walk_state));
+       }
+-   /* Always must free any linked control states */
++      /* Always must free any linked control states */
+       while (walk_state->control_state) {
+               state = walk_state->control_state;
+--- linux-2.6.0-test6/drivers/acpi/ec.c        2003-06-14 12:18:22.000000000 -0700
++++ 25/drivers/acpi/ec.c       2003-10-05 00:33:24.000000000 -0700
+@@ -32,7 +32,7 @@
+ #include <asm/io.h>
+ #include <acpi/acpi_bus.h>
+ #include <acpi/acpi_drivers.h>
+-
++#include <acpi/actypes.h>
+ #define _COMPONENT            ACPI_EC_COMPONENT
+ ACPI_MODULE_NAME              ("acpi_ec")
+@@ -412,7 +412,10 @@ acpi_ec_space_setup (
+        * The EC object is in the handler context and is needed
+        * when calling the acpi_ec_space_handler.
+        */
+-      *return_context = handler_context;
++      if(function == ACPI_REGION_DEACTIVATE) 
++              *return_context = NULL;
++      else 
++              *return_context = handler_context;
+       return AE_OK;
+ }
+--- linux-2.6.0-test6/drivers/acpi/events/evregion.c   2003-06-14 12:18:25.000000000 -0700
++++ 25/drivers/acpi/events/evregion.c  2003-10-05 00:33:24.000000000 -0700
+@@ -382,7 +382,7 @@ acpi_ev_detach_region(
+       union acpi_operand_object       *obj_desc;
+       union acpi_operand_object       **last_obj_ptr;
+       acpi_adr_space_setup            region_setup;
+-      void                            *region_context;
++      void                            **region_context;
+       union acpi_operand_object       *region_obj2;
+       acpi_status                     status;
+@@ -394,7 +394,7 @@ acpi_ev_detach_region(
+       if (!region_obj2) {
+               return_VOID;
+       }
+-      region_context = region_obj2->extra.region_context;
++      region_context = &region_obj2->extra.region_context;
+       /* Get the address handler from the region object */
+@@ -450,7 +450,7 @@ acpi_ev_detach_region(
+                       region_setup = handler_obj->address_space.setup;
+                       status = region_setup (region_obj, ACPI_REGION_DEACTIVATE,
+-                                        handler_obj->address_space.context, &region_context);
++                                        handler_obj->address_space.context, region_context);
+                       /* Init routine may fail, Just ignore errors */
+--- linux-2.6.0-test6/drivers/acpi/executer/excreate.c 2003-06-14 12:18:34.000000000 -0700
++++ 25/drivers/acpi/executer/excreate.c        2003-10-05 00:33:24.000000000 -0700
+@@ -286,7 +286,7 @@ acpi_ex_create_region (
+       ACPI_FUNCTION_TRACE ("ex_create_region");
+-      /* Get the Node from the object stack  */
++      /* Get the Namespace Node */
+       node = walk_state->op->common.node;
+@@ -311,7 +311,6 @@ acpi_ex_create_region (
+       ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "Region Type - %s (%X)\n",
+                         acpi_ut_get_region_name (region_space), region_space));
+-
+       /* Create the region descriptor */
+       obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_REGION);
+@@ -375,6 +374,7 @@ acpi_ex_create_table_region (
+       ACPI_FUNCTION_TRACE ("ex_create_table_region");
++
+       /* Get the Node from the object stack  */
+       node = walk_state->op->common.node;
+@@ -392,7 +392,6 @@ acpi_ex_create_table_region (
+       status = acpi_tb_find_table (operand[1]->string.pointer,
+                          operand[2]->string.pointer,
+                          operand[3]->string.pointer, &table);
+-
+       if (ACPI_FAILURE (status)) {
+               return_ACPI_STATUS (status);
+       }
+@@ -489,7 +488,6 @@ acpi_ex_create_processor (
+       status = acpi_ns_attach_object ((struct acpi_namespace_node *) operand[0],
+                         obj_desc, ACPI_TYPE_PROCESSOR);
+-
+       /* Remove local reference to the object */
+       acpi_ut_remove_reference (obj_desc);
+@@ -540,7 +538,6 @@ acpi_ex_create_power_resource (
+       status = acpi_ns_attach_object ((struct acpi_namespace_node *) operand[0],
+                         obj_desc, ACPI_TYPE_POWER);
+-
+       /* Remove local reference to the object */
+       acpi_ut_remove_reference (obj_desc);
+@@ -609,7 +606,6 @@ acpi_ex_create_method (
+               obj_desc->method.concurrency = (u8)
+                                 (((method_flags & METHOD_FLAGS_SYNCH_LEVEL) >> 4) + 1);
+       }
+-
+       else {
+               obj_desc->method.concurrency = INFINITE_CONCURRENCY;
+       }
+--- linux-2.6.0-test6/drivers/acpi/executer/exfldio.c  2003-06-14 12:18:06.000000000 -0700
++++ 25/drivers/acpi/executer/exfldio.c 2003-10-05 00:33:24.000000000 -0700
+@@ -139,7 +139,41 @@ acpi_ex_setup_region (
+                       field_datum_byte_offset, obj_desc->common_field.access_byte_width,
+                       rgn_desc->region.node->name.ascii, rgn_desc->region.length));
+-              return_ACPI_STATUS (AE_AML_REGION_LIMIT);
++              #ifdef CONFIG_ACPI_RELAXED_AML
++              {
++                      /*
++                       * Allow access to the field if it is within the region size
++                       * rounded up to a multiple of the access byte width.  This
++                       * overcomes "off-by-one" programming errors in the AML often
++                       * found in Toshiba laptops.  These errors were allowed by
++                       * the Microsoft ASL compiler.
++                       */
++                      u32 rounded_length = ACPI_ROUND_UP(rgn_desc->region.length,
++                                                                      obj_desc->common_field.access_byte_width);
++
++                      if (rounded_length < (obj_desc->common_field.base_byte_offset
++                                              + field_datum_byte_offset
++                                              + obj_desc->common_field.access_byte_width)) {
++                              return_ACPI_STATUS (AE_AML_REGION_LIMIT);
++                      } else {
++                              static int      warn_once = 1;
++                              if (warn_once) {
++                                      // Could also associate a flag with each field, and
++                                      // warn once for each field.
++                                      ACPI_REPORT_WARNING((
++                                              "The ACPI AML in your computer contains errors, "
++                                              "please nag the manufacturer to correct it.\n"));
++                                      ACPI_REPORT_WARNING((
++                                              "Allowing relaxed access to fields; "
++                                              "turn on CONFIG_ACPI_DEBUG for details.\n"));
++                                      warn_once = 0;
++                              }
++                              return_ACPI_STATUS (AE_OK);
++                      }
++              }
++              #else
++                      return_ACPI_STATUS (AE_AML_REGION_LIMIT);
++              #endif
+       }
+       return_ACPI_STATUS (AE_OK);
+--- linux-2.6.0-test6/drivers/acpi/Kconfig     2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/acpi/Kconfig    2003-10-05 00:36:23.000000000 -0700
+@@ -3,34 +3,14 @@
+ #
+ menu "ACPI (Advanced Configuration and Power Interface) Support"
+-
+-config ACPI_HT
+-      bool "ACPI Processor Enumeration for HT"
+-      depends on X86
+-      default y
+-      ---help---
+-        ACPI enumerates both logical (a.k.a. Hyper-Threaded -- HT)
+-        and physical processors.  It is designed to obsolete several older
+-        specifications, including the MultiProcessor Specification (MPS),
+-        which supported only physical processors.
+-
+-        CONFIG_ACPI_HT includes the minimal ACPI boot-time code
+-        necessary to enumerate logical processors and enable HT.
+-
+-        CONFIG_ACPI includes CONFIG_ACPI_HT, plus IO APIC enumeration,
+-        and the hooks to run the ACPI AML interpreter for run-time events.
+-
+-        When CONFIG_ACPI is selected, the command-line option "acpi=ht"
+-        is available to run just the ACPI boot-time code -- just as if
+-        only CONFIG_ACPI_HT were selected.
+-
+-        Note that "acpi=off" can be used to disable all ACPI code in the kernel.
+-
+-config ACPI
+-      bool "Full ACPI Support"
+       depends on !X86_VISWS
+       depends on !IA64_HP_SIM
+-      depends on IA64 || (X86 || ACPI_HT)
++      depends on IA64 || X86
++
++config ACPI
++      bool "ACPI Support"
++      depends on IA64 || X86
++
+       default y
+       ---help---
+         Advanced Configuration and Power Interface (ACPI) support for 
+@@ -62,12 +42,19 @@ config ACPI
+ config ACPI_BOOT
+       bool
+-      depends on ACPI || ACPI_HT
++      depends on ACPI || X86_HT
++      default y
++
++config ACPI_INTERPRETER
++      bool
++      depends on ACPI
++      depends on !IA64_SGI_SN
+       default y
+ config ACPI_SLEEP
+       bool "Sleep States (EXPERIMENTAL)"
+       depends on X86 && ACPI
++      depends on ACPI_INTERPRETER
+       depends on EXPERIMENTAL && PM
+       default y
+       ---help---
+@@ -93,7 +80,8 @@ config ACPI_SLEEP_PROC_FS
+ config ACPI_AC
+       tristate "AC Adapter"
+-      depends on X86 && ACPI
++      depends on X86
++      depends on ACPI_INTERPRETER
+       default m
+       help
+         This driver adds support for the AC Adapter object, which indicates
+@@ -102,7 +90,8 @@ config ACPI_AC
+ config ACPI_BATTERY
+       tristate "Battery"
+-      depends on X86 && ACPI
++      depends on X86
++      depends on ACPI_INTERPRETER
+       default m
+       help
+         This driver adds support for battery information through
+@@ -111,7 +100,7 @@ config ACPI_BATTERY
+ config ACPI_BUTTON
+       tristate "Button"
+-      depends on ACPI
++      depends on ACPI_INTERPRETER
+       depends on !IA64_SGI_SN
+       default m
+       help
+@@ -123,7 +112,7 @@ config ACPI_BUTTON
+ config ACPI_FAN
+       tristate "Fan"
+-      depends on ACPI
++      depends on ACPI_INTERPRETER
+       depends on !IA64_SGI_SN
+       default m
+       help
+@@ -132,7 +121,7 @@ config ACPI_FAN
+ config ACPI_PROCESSOR
+       tristate "Processor"
+-      depends on ACPI
++      depends on ACPI_INTERPRETER
+       depends on !IA64_SGI_SN
+       default m
+       help
+@@ -152,14 +141,15 @@ config ACPI_THERMAL
+ config ACPI_NUMA
+       bool "NUMA support"
+-      depends on ACPI
++      depends on ACPI_INTERPRETER
+       depends on NUMA
+       depends on !X86_64
+       default y if IA64_GENERIC || IA64_SGI_SN2
+ config ACPI_ASUS
+         tristate "ASUS/Medion Laptop Extras"
+-        depends on X86 && ACPI
++      depends on X86
++      depends on ACPI_INTERPRETER
+       default m
+         ---help---
+           This driver provides support for extra features of ACPI-compatible
+@@ -170,6 +160,9 @@ config ACPI_ASUS
+           display brightness and output, switching the LCD backlight on and off,
+           and most importantly, allows you to blink those fancy LEDs intended
+           for reporting mail and wireless status.
++
++        Note: display switching code is currently considered EXPERIMENTAL,
++        toying with these values may even lock your machine.
+           
+           All settings are changed via /proc/acpi/asus directory entries. Owner
+           and group for these entries can be set with asus_uid and asus_gid
+@@ -185,7 +178,8 @@ config ACPI_ASUS
+           
+ config ACPI_TOSHIBA
+       tristate "Toshiba Laptop Extras"
+-      depends on X86 && ACPI
++      depends on X86
++      depends on ACPI_INTERPRETER
+       default m
+       ---help---
+         This driver adds support for access to certain system settings
+@@ -212,7 +206,7 @@ config ACPI_TOSHIBA
+ config ACPI_DEBUG
+       bool "Debug Statements"
+-      depends on ACPI
++      depends on ACPI_INTERPRETER
+       depends on !IA64_SGI_SN
+       default n
+       help
+@@ -222,19 +216,14 @@ config ACPI_DEBUG
+ config ACPI_BUS
+       bool
+-      depends on ACPI
+-      depends on !IA64_SGI_SN
+-      default y
+-
+-config ACPI_INTERPRETER
+-      bool
+-      depends on ACPI
++      depends on ACPI_INTERPRETER
+       depends on !IA64_SGI_SN
+       default y
+ config ACPI_EC
+       bool
+-      depends on X86 && ACPI
++      depends on X86
++      depends on ACPI_INTERPRETER
+       default y
+       help
+         This driver is required on some systems for the proper operation of
+@@ -243,19 +232,19 @@ config ACPI_EC
+ config ACPI_POWER
+       bool
+-      depends on ACPI
++      depends on ACPI_INTERPRETER
+       depends on !IA64_SGI_SN
+       default y
+ config ACPI_PCI
+       bool
+-      depends on ACPI
++      depends on ACPI_INTERPRETER
+       depends on !IA64_SGI_SN
+       default PCI
+ config ACPI_SYSTEM
+       bool
+-      depends on ACPI
++      depends on ACPI_INTERPRETER
+       depends on !IA64_SGI_SN
+       default y
+       help
+@@ -263,10 +252,28 @@ config ACPI_SYSTEM
+         dump your ACPI DSDT table using /proc/acpi/dsdt.
+ config ACPI_EFI
+-      bool
+-      depends on ACPI
+-      depends on IA64
+-      default y
++      bool "Obtain RSDP from EFI Configuration Table"
++      depends on ACPI_INTERPRETER
++      depends on IA64 || X86
++      default n
++      help
++         On EFI Systems the RSDP pointer is passed to the kernel via
++         the EFI Configuration Table.  On Itanium systems this is
++         standard and required.  For IA-32, systems that have
++         EFI firmware should leave this enabled.  Platforms with
++         traditional legacy BIOS should disable this option.
++
++config ACPI_RELAXED_AML
++      bool "Relaxed AML"
++      depends on ACPI_INTERPRETER
++      depends on !IA64_SGI_SN
++      default n
++      help
++        If you say `Y' here, the ACPI interpreter will relax its checking
++        for valid AML and will ignore some AML mistakes, such as off-by-one
++        errors in region sizes.  Some laptops may require this option.  In
++        particular, many Toshiba laptops require this for correct operation
++        of the AC module.
+ endmenu
+--- linux-2.6.0-test6/drivers/acpi/Makefile    2003-08-22 19:23:40.000000000 -0700
++++ 25/drivers/acpi/Makefile   2003-10-05 00:33:23.000000000 -0700
+@@ -18,7 +18,7 @@ obj-$(CONFIG_ACPI)           := acpi_ksyms.o 
+ # ACPI Boot-Time Table Parsing
+ #
+ obj-$(CONFIG_ACPI_BOOT)               += tables.o
+-obj-$(CONFIG_ACPI)            += blacklist.o
++obj-$(CONFIG_ACPI_INTERPRETER)        += blacklist.o
+ #
+ # ACPI Core Subsystem (Interpreter)
+--- linux-2.6.0-test6/drivers/acpi/namespace/nsdump.c  2003-06-14 12:18:33.000000000 -0700
++++ 25/drivers/acpi/namespace/nsdump.c 2003-10-05 00:33:24.000000000 -0700
+@@ -234,7 +234,7 @@ acpi_ns_dump_one_object (
+               case ACPI_TYPE_DEVICE:
+-                      acpi_os_printf ("Notify object: %p", obj_desc);
++                      acpi_os_printf ("Notify Object: %p\n", obj_desc);
+                       break;
+@@ -371,7 +371,7 @@ acpi_ns_dump_one_object (
+               case ACPI_TYPE_LOCAL_BANK_FIELD:
+               case ACPI_TYPE_LOCAL_INDEX_FIELD:
+-                      acpi_os_printf (" Off %.2X Len %.2X Acc %.2hd\n",
++                      acpi_os_printf ("Off %.2X Len %.2X Acc %.2hd\n",
+                                       (obj_desc->common_field.base_byte_offset * 8)
+                                               + obj_desc->common_field.start_field_bit_offset,
+                                       obj_desc->common_field.bit_length,
+--- linux-2.6.0-test6/drivers/acpi/namespace/nssearch.c        2003-06-14 12:18:34.000000000 -0700
++++ 25/drivers/acpi/namespace/nssearch.c       2003-10-05 00:33:24.000000000 -0700
+@@ -96,7 +96,7 @@ acpi_ns_search_node (
+               scope_name = acpi_ns_get_external_pathname (node);
+               if (scope_name) {
+-                      ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Searching %s [%p] For %4.4s (%s)\n",
++                      ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Searching %s (%p) For [%4.4s] (%s)\n",
+                               scope_name, node, (char *) &target_name, acpi_ut_get_type_name (type)));
+                       ACPI_MEM_FREE (scope_name);
+@@ -117,9 +117,9 @@ acpi_ns_search_node (
+                        * Found matching entry.
+                        */
+                       ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
+-                              "Name %4.4s Type [%s] found in scope [%4.4s] %p\n",
++                              "Name [%4.4s] (%s) %p found in scope [%4.4s] %p\n",
+                               (char *) &target_name, acpi_ut_get_type_name (next_node->type),
+-                              next_node->name.ascii, next_node));
++                              next_node, node->name.ascii, node));
+                       *return_node = next_node;
+                       return_ACPI_STATUS (AE_OK);
+@@ -143,7 +143,7 @@ acpi_ns_search_node (
+       /* Searched entire namespace level, not found */
+       ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
+-              "Name %4.4s Type [%s] not found in search in scope [%4.4s] %p first child %p\n",
++              "Name [%4.4s] (%s) not found in search in scope [%4.4s] %p first child %p\n",
+               (char *) &target_name, acpi_ut_get_type_name (type),
+               node->name.ascii, node, node->child));
+--- linux-2.6.0-test6/drivers/acpi/namespace/nsutils.c 2003-06-14 12:18:21.000000000 -0700
++++ 25/drivers/acpi/namespace/nsutils.c        2003-10-05 00:33:24.000000000 -0700
+@@ -175,6 +175,11 @@ acpi_ns_print_node_pathname (
+       acpi_status                     status;
++      if (!node) {
++              acpi_os_printf ("[NULL NAME]");
++              return;
++      }
++
+       /* Convert handle to a full pathname and print it (with supplied message) */
+       buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
+@@ -470,11 +475,11 @@ acpi_ns_build_internal_name (
+       *result = 0;
+       if (info->fully_qualified) {
+-              ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "returning [%p] (abs) \"\\%s\"\n",
++              ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Returning [%p] (abs) \"\\%s\"\n",
+                       internal_name, internal_name));
+       }
+       else {
+-              ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "returning [%p] (rel) \"%s\"\n",
++              ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Returning [%p] (rel) \"%s\"\n",
+                       internal_name, internal_name));
+       }
+--- linux-2.6.0-test6/drivers/acpi/osl.c       2003-08-22 19:23:40.000000000 -0700
++++ 25/drivers/acpi/osl.c      2003-10-05 00:36:22.000000000 -0700
+@@ -43,7 +43,6 @@
+ #ifdef CONFIG_ACPI_EFI
+ #include <linux/efi.h>
+-u64 efi_mem_attributes (u64 phys_addr);
+ #endif
+--- linux-2.6.0-test6/drivers/acpi/parser/psparse.c    2003-06-14 12:17:59.000000000 -0700
++++ 25/drivers/acpi/parser/psparse.c   2003-10-05 00:33:24.000000000 -0700
+@@ -437,7 +437,6 @@ acpi_ps_parse_loop (
+               return_ACPI_STATUS (AE_BAD_PARAMETER);
+       }
+-
+       parser_state = &walk_state->parser_state;
+       walk_state->arg_types = 0;
+@@ -705,10 +704,9 @@ acpi_ps_parse_loop (
+                               walk_state->arg_types = 0;
+                               break;
+-
+                       default:
+-                              /* Op is not a constant or string, append each argument */
++                              /* Op is not a constant or string, append each argument to the Op */
+                               while (GET_CURRENT_ARG_TYPE (walk_state->arg_types) &&
+                                               !walk_state->arg_count) {
+@@ -727,23 +725,23 @@ acpi_ps_parse_loop (
+                                       INCREMENT_ARG_LIST (walk_state->arg_types);
+                               }
++                              /* Special processing for certain opcodes */
++
+                               switch (op->common.aml_opcode) {
+                               case AML_METHOD_OP:
+-                                      /* For a method, save the length and address of the body */
+-
+                                       /*
+-                                       * Skip parsing of control method or opregion body,
++                                       * Skip parsing of control method
+                                        * because we don't have enough info in the first pass
+-                                       * to parse them correctly.
++                                       * to parse it correctly.
++                                       *
++                                       * Save the length and address of the body
+                                        */
+                                       op->named.data   = parser_state->aml;
+                                       op->named.length = (u32) (parser_state->pkg_end - parser_state->aml);
+-                                      /*
+-                                       * Skip body of method.  For op_regions, we must continue
+-                                       * parsing because the opregion is not a standalone
+-                                       * package (We don't know where the end is).
+-                                       */
++
++                                      /* Skip body of method */
++
+                                       parser_state->aml   = parser_state->pkg_end;
+                                       walk_state->arg_count = 0;
+                                       break;
+@@ -756,15 +754,15 @@ acpi_ps_parse_loop (
+                                               (op->common.parent->common.aml_opcode == AML_NAME_OP) &&
+                                               (walk_state->descending_callback != acpi_ds_exec_begin_op)) {
+                                               /*
+-                                               * Skip parsing of
++                                               * Skip parsing of Buffers and Packages
+                                                * because we don't have enough info in the first pass
+                                                * to parse them correctly.
+                                                */
+                                               op->named.data   = aml_op_start;
+                                               op->named.length = (u32) (parser_state->pkg_end - aml_op_start);
+-                                              /*
+-                                               * Skip body
+-                                               */
++
++                                              /* Skip body */
++
+                                               parser_state->aml   = parser_state->pkg_end;
+                                               walk_state->arg_count = 0;
+                                       }
+@@ -778,6 +776,7 @@ acpi_ps_parse_loop (
+                                       break;
+                               default:
++
+                                       /* No action for all other opcodes */
+                                       break;
+                               }
+--- linux-2.6.0-test6/drivers/acpi/pci_irq.c   2003-08-22 19:23:40.000000000 -0700
++++ 25/drivers/acpi/pci_irq.c  2003-10-05 00:36:20.000000000 -0700
+@@ -71,6 +71,9 @@ acpi_pci_irq_find_prt_entry (
+       ACPI_FUNCTION_TRACE("acpi_pci_irq_find_prt_entry");
++      if (!acpi_prt.count)
++              return_PTR(NULL);
++
+       /*
+        * Parse through all PRT entries looking for a match on the specified
+        * PCI device's segment, bus, device, and pin (don't care about func).
+@@ -234,7 +237,7 @@ acpi_pci_irq_add_prt (
+                           PCI Interrupt Routing Support
+    -------------------------------------------------------------------------- */
+-static int
++int
+ acpi_pci_irq_lookup (struct pci_bus *bus, int device, int pin)
+ {
+       struct acpi_prt_entry   *entry = NULL;
+--- linux-2.6.0-test6/drivers/acpi/pci_link.c  2003-09-08 13:58:56.000000000 -0700
++++ 25/drivers/acpi/pci_link.c 2003-10-05 00:33:24.000000000 -0700
+@@ -220,7 +220,6 @@ acpi_pci_link_check_current (
+       return AE_CTRL_TERMINATE;
+ }
+-
+ static int
+ acpi_pci_link_get_current (
+       struct acpi_pci_link    *link)
+@@ -279,6 +278,28 @@ end:
+       return_VALUE(result);
+ }
++static int
++acpi_pci_link_try_get_current (
++      struct acpi_pci_link *link,
++      int irq)
++{
++      int result;
++
++      ACPI_FUNCTION_TRACE("acpi_pci_link_try_get_current");
++
++      result = acpi_pci_link_get_current(link);
++      if (result && link->irq.active) {
++              return_VALUE(result);
++      }
++
++      if (!link->irq.active) {
++              ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "No active IRQ resource found\n"));
++              printk(KERN_WARNING "_CRS returns NULL! Using IRQ %d for device (%s [%s]).\n", irq, acpi_device_name(link->device), acpi_device_bid(link->device));
++              link->irq.active = irq;
++      }
++      
++      return 0;
++}
+ static int
+ acpi_pci_link_set (
+@@ -294,6 +315,7 @@ acpi_pci_link_set (
+       struct acpi_buffer      buffer = {sizeof(resource)+1, &resource};
+       int                     i = 0;
+       int                     valid = 0;
++      int                     resource_type = 0;
+       ACPI_FUNCTION_TRACE("acpi_pci_link_set");
+@@ -317,20 +339,32 @@ acpi_pci_link_set (
+               }
+       }
++      /* If IRQ<=15, first try with a "normal" IRQ descriptor. If that fails, try with
++       * an extended one */
++      if (irq <= 15) {
++              resource_type = ACPI_RSTYPE_IRQ;
++      } else {
++              resource_type = ACPI_RSTYPE_EXT_IRQ;
++      }
++
++retry_programming:
++   
+       memset(&resource, 0, sizeof(resource));
+       /* NOTE: PCI interrupts are always level / active_low / shared. But not all
+          interrupts > 15 are PCI interrupts. Rely on the ACPI IRQ definition for 
+          parameters */
+-      if (irq <= 15) {
++      switch(resource_type) {
++      case ACPI_RSTYPE_IRQ:
+               resource.res.id = ACPI_RSTYPE_IRQ;
+               resource.res.length = sizeof(struct acpi_resource);
+               resource.res.data.irq.edge_level = link->irq.edge_level;
+               resource.res.data.irq.active_high_low = link->irq.active_high_low;
+               resource.res.data.irq.number_of_interrupts = 1;
+               resource.res.data.irq.interrupts[0] = irq;
+-      }
+-      else {
++              break;
++         
++      case ACPI_RSTYPE_EXT_IRQ:
+               resource.res.id = ACPI_RSTYPE_EXT_IRQ;
+               resource.res.length = sizeof(struct acpi_resource);
+               resource.res.data.extended_irq.producer_consumer = ACPI_CONSUMER;
+@@ -339,11 +373,21 @@ acpi_pci_link_set (
+               resource.res.data.extended_irq.number_of_interrupts = 1;
+               resource.res.data.extended_irq.interrupts[0] = irq;
+               /* ignore resource_source, it's optional */
++              break;
+       }
+       resource.end.id = ACPI_RSTYPE_END_TAG;
+       /* Attempt to set the resource */
+       status = acpi_set_current_resources(link->handle, &buffer);
++
++      /* if we failed and IRQ <= 15, try again with an extended descriptor */
++      if (ACPI_FAILURE(status) && (resource_type == ACPI_RSTYPE_IRQ)) {
++                resource_type = ACPI_RSTYPE_EXT_IRQ;
++                printk(PREFIX "Retrying with extended IRQ descriptor\n");
++                goto retry_programming;
++      }
++  
++      /* check for total failure */
+       if (ACPI_FAILURE(status)) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _SRS\n"));
+               return_VALUE(-ENODEV);
+@@ -361,7 +405,7 @@ acpi_pci_link_set (
+       }
+       /* Make sure the active IRQ is the one we requested. */
+-      result = acpi_pci_link_get_current(link);
++      result = acpi_pci_link_try_get_current(link, irq);
+       if (result) {
+               return_VALUE(result);
+       }
+@@ -456,16 +500,16 @@ static int acpi_pci_link_allocate(struct
+               irq = link->irq.active;
+       } else {
+               irq = link->irq.possible[0];
+-      }
+-              /* 
+-               * Select the best IRQ.  This is done in reverse to promote 
++              /*
++               * Select the best IRQ.  This is done in reverse to promote
+                * the use of IRQs 9, 10, 11, and >15.
+                */
+               for (i=(link->irq.possible_count-1); i>0; i--) {
+                       if (acpi_irq_penalty[irq] > acpi_irq_penalty[link->irq.possible[i]])
+                               irq = link->irq.possible[i];
+               }
++      }
+       /* Attempt to enable the link device at this IRQ. */
+       if (acpi_pci_link_set(link, irq)) {
+@@ -574,10 +618,6 @@ acpi_pci_link_add (
+               else
+                       printk(" %d", link->irq.possible[i]);
+       }
+-      if (!link->irq.active)
+-              printk(", disabled");
+-      else if (!found)
+-              printk(", enabled at IRQ %d", link->irq.active);
+       printk(")\n");
+       /* TBD: Acquire/release lock */
+--- linux-2.6.0-test6/drivers/acpi/tables.c    2003-08-22 19:23:40.000000000 -0700
++++ 25/drivers/acpi/tables.c   2003-10-05 00:33:24.000000000 -0700
+@@ -69,7 +69,8 @@ struct acpi_table_sdt {
+ static unsigned long          sdt_pa;         /* Physical Address */
+ static unsigned long          sdt_count;      /* Table count */
+-static struct acpi_table_sdt  *sdt_entry;
++
++static struct acpi_table_sdt  sdt_entry[ACPI_MAX_TABLES];
+ void
+ acpi_table_print (
+@@ -418,12 +419,6 @@ acpi_table_get_sdt (
+                       sdt_count = ACPI_MAX_TABLES;
+               }
+-              sdt_entry = alloc_bootmem(sdt_count * sizeof(struct acpi_table_sdt));
+-              if (!sdt_entry) {
+-                      printk(KERN_ERR "ACPI: Could not allocate mem for SDT entries!\n");
+-                      return -ENOMEM;
+-              }
+-
+               for (i = 0; i < sdt_count; i++)
+                       sdt_entry[i].pa = (unsigned long) mapped_xsdt->entry[i];
+       }
+@@ -470,12 +465,6 @@ acpi_table_get_sdt (
+                       sdt_count = ACPI_MAX_TABLES;
+               }
+-              sdt_entry = alloc_bootmem(sdt_count * sizeof(struct acpi_table_sdt));
+-              if (!sdt_entry) {
+-                      printk(KERN_ERR "ACPI: Could not allocate mem for SDT entries!\n");
+-                      return -ENOMEM;
+-              }
+-
+               for (i = 0; i < sdt_count; i++)
+                       sdt_entry[i].pa = (unsigned long) mapped_rsdt->entry[i];
+       }
+--- linux-2.6.0-test6/drivers/acpi/toshiba_acpi.c      2003-08-22 19:23:40.000000000 -0700
++++ 25/drivers/acpi/toshiba_acpi.c     2003-10-05 00:33:24.000000000 -0700
+@@ -41,7 +41,6 @@
+ #include <linux/init.h>
+ #include <linux/types.h>
+ #include <linux/proc_fs.h>
+-#include <linux/version.h>
+ #include <acpi/acpi_drivers.h>
+--- linux-2.6.0-test6/drivers/acpi/utilities/utdelete.c        2003-06-14 12:18:20.000000000 -0700
++++ 25/drivers/acpi/utilities/utdelete.c       2003-10-05 00:34:43.000000000 -0700
+@@ -417,6 +417,8 @@ acpi_ut_update_object_reference (
+       union acpi_generic_state         *state_list = NULL;
+       union acpi_generic_state         *state;
++      union acpi_operand_object        *tmp;
++
+       ACPI_FUNCTION_TRACE_PTR ("ut_update_object_reference", object);
+@@ -448,8 +450,15 @@ acpi_ut_update_object_reference (
+               switch (ACPI_GET_OBJECT_TYPE (object)) {
+               case ACPI_TYPE_DEVICE:
+-                      acpi_ut_update_ref_count (object->device.system_notify, action);
+-                      acpi_ut_update_ref_count (object->device.device_notify, action);
++                      tmp = object->device.system_notify;
++                      if(tmp && tmp->common.reference_count<=1 && action == REF_DECREMENT)
++                              object->device.system_notify = NULL;
++                      acpi_ut_update_ref_count (tmp, action);
++
++                      tmp = object->device.device_notify;
++                      if(tmp && tmp->common.reference_count <=1 && action == REF_DECREMENT)
++                              object->device.device_notify = NULL;
++                      acpi_ut_update_ref_count (tmp, action);
+                       break;
+@@ -467,6 +476,9 @@ acpi_ut_update_object_reference (
+                                */
+                               status = acpi_ut_create_update_state_and_push (
+                                                object->package.elements[i], action, &state_list);
++                              tmp = object->package.elements[i];
++                              if(tmp && tmp->common.reference_count<=1  && action == REF_DECREMENT) /*reference count didn't refresh now*/
++                                      object->package.elements[i] = NULL;
+                               if (ACPI_FAILURE (status)) {
+                                       goto error_exit;
+                               }
+@@ -478,6 +490,9 @@ acpi_ut_update_object_reference (
+                       status = acpi_ut_create_update_state_and_push (
+                                        object->buffer_field.buffer_obj, action, &state_list);
++                      tmp = object->buffer_field.buffer_obj;
++                      if( tmp && tmp->common.reference_count <=1  && action == REF_DECREMENT)/*reference count didn't refresh now*/
++                              object->buffer_field.buffer_obj = NULL;
+                       if (ACPI_FAILURE (status)) {
+                               goto error_exit;
+                       }
+@@ -491,6 +506,9 @@ acpi_ut_update_object_reference (
+                       if (ACPI_FAILURE (status)) {
+                               goto error_exit;
+                       }
++                      tmp = object->field.region_obj;
++                      if( tmp && tmp->common.reference_count <=1  && action == REF_DECREMENT)/*reference count didn't refresh now*/
++                              object->field.region_obj = NULL;
+                  break;
+@@ -501,12 +519,18 @@ acpi_ut_update_object_reference (
+                       if (ACPI_FAILURE (status)) {
+                               goto error_exit;
+                       }
++                      tmp = object->bank_field.bank_obj;
++                      if( tmp && tmp->common.reference_count <=1  && action == REF_DECREMENT)/*reference count didn't refresh now*/
++                              object->bank_field.bank_obj = NULL;
+                       status = acpi_ut_create_update_state_and_push (
+                                        object->bank_field.region_obj, action, &state_list);
+                       if (ACPI_FAILURE (status)) {
+                               goto error_exit;
+                       }
++                      tmp = object->bank_field.region_obj;
++                      if( tmp && tmp->common.reference_count <=1  && action == REF_DECREMENT)/*reference count didn't refresh now*/
++                              object->bank_field.region_obj = NULL;
+                       break;
+@@ -517,12 +541,18 @@ acpi_ut_update_object_reference (
+                       if (ACPI_FAILURE (status)) {
+                               goto error_exit;
+                       }
++                      tmp = object->index_field.index_obj;
++                      if( tmp && tmp->common.reference_count <=1  && action == REF_DECREMENT)/*reference count didn't refresh now*/
++                              object->index_field.index_obj = NULL;
+                       status = acpi_ut_create_update_state_and_push (
+                                        object->index_field.data_obj, action, &state_list);
+                       if (ACPI_FAILURE (status)) {
+                               goto error_exit;
+                       }
++                      tmp = object->index_field.data_obj;
++                      if( tmp && tmp->common.reference_count <=1  && action == REF_DECREMENT)/*reference count didn't refresh now*/
++                              object->index_field.data_obj = NULL;
+                       break;
+--- linux-2.6.0-test6/drivers/block/acsi.c     2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/block/acsi.c    2003-10-05 00:34:00.000000000 -0700
+@@ -63,6 +63,7 @@ typedef void Scsi_Device; /* hack to avo
+ #include <linux/hdreg.h> /* for HDIO_GETGEO */
+ #include <linux/blkpg.h>
+ #include <linux/buffer_head.h>
++#include <linux/blkdev.h>
+ #include <asm/setup.h>
+ #include <asm/pgtable.h>
+@@ -346,7 +347,7 @@ struct acsi_error {
+ static int acsicmd_dma( const char *cmd, char *buffer, int blocks, int
+                         rwflag, int enable);
+ static int acsi_reqsense( char *buffer, int targ, int lun);
+-static void acsi_print_error(const unsigned char *errblk, int struct acsi_info_struct *aip);
++static void acsi_print_error(const unsigned char *errblk, struct acsi_info_struct *aip);
+ static irqreturn_t acsi_interrupt (int irq, void *data, struct pt_regs *fp);
+ static void unexpected_acsi_interrupt( void );
+ static void bad_rw_intr( void );
+@@ -358,10 +359,9 @@ static void copy_from_acsibuffer( void )
+ static void do_end_requests( void );
+ static void do_acsi_request( request_queue_t * );
+ static void redo_acsi_request( void );
+-static int acsi_ioctl( struct inode *inode, struct file *file, unsigned int
++static int acsi_ioctl(struct block_device *bdev, struct file *file, unsigned int
+                        cmd, unsigned long arg );
+-static int acsi_open( struct inode * inode, struct file * filp );
+-static int acsi_release( struct inode * inode, struct file * file );
++static int acsi_open(struct block_device *bdev, struct file *filp);
+ static void acsi_prevent_removal(struct acsi_info_struct *aip, int flag );
+ static int acsi_change_blk_size( int target, int lun);
+ static int acsi_mode_sense( int target, int lun, SENSE_DATA *sd );
+@@ -1080,10 +1080,10 @@ static void redo_acsi_request( void )
+  ***********************************************************************/
+-static int acsi_ioctl( struct inode *inode, struct file *file,
+-                                         unsigned int cmd, unsigned long arg )
++static int acsi_ioctl(struct block_device *bdev, struct file *file,
++                    unsigned int cmd, unsigned long arg )
+ {
+-      struct gendisk *disk = inode->i_bdev->bd_disk;
++      struct gendisk *disk = bdev->bd_disk;
+       struct acsi_info_struct *aip = disk->private_data;
+       switch (cmd) {
+         case HDIO_GETGEO:
+@@ -1095,7 +1095,7 @@ static int acsi_ioctl( struct inode *ino
+           put_user( 64, &geo->heads );
+           put_user( 32, &geo->sectors );
+           put_user( aip->size >> 11, &geo->cylinders );
+-              put_user(get_start_sect(inode->i_bdev), &geo->start);
++              put_user(get_start_sect(bdev), &geo->start);
+               return 0;
+         }
+         case SCSI_IOCTL_GET_IDLUN:
+@@ -1125,16 +1125,16 @@ static int acsi_ioctl( struct inode *ino
+  *
+  */
+-static int acsi_open( struct inode * inode, struct file * filp )
++static int acsi_open(struct block_device *bdev, struct file *filp)
+ {
+-      struct gendisk *disk = inode->i_bdev->bd_disk;
++      struct gendisk *disk = bdev->bd_disk;
+       struct acsi_info_struct *aip = disk->private_data;
+       if (aip->access_count == 0 && aip->removable) {
+ #if 0
+               aip->changed = 1;       /* safety first */
+ #endif
+-              check_disk_change( inode->i_bdev );
++              check_disk_change(bdev);
+               if (aip->changed)       /* revalidate was not successful (no medium) */
+                       return -ENXIO;
+               acsi_prevent_removal(aip, 1);
+@@ -1142,10 +1142,11 @@ static int acsi_open( struct inode * ino
+       aip->access_count++;
+       if (filp && filp->f_mode) {
+-              check_disk_change( inode->i_bdev );
++              check_disk_change(bdev);
+               if (filp->f_mode & 2) {
+                       if (aip->read_only) {
+-                              acsi_release( inode, filp );
++                              if (--aip->access_count == 0 && aip->removable)
++                                      acsi_prevent_removal(aip, 0);
+                               return -EROFS;
+                       }
+               }
+@@ -1159,9 +1160,8 @@ static int acsi_open( struct inode * ino
+  * be forgotten about...
+  */
+-static int acsi_release( struct inode * inode, struct file * file )
++static int acsi_release(struct gendisk *disk)
+ {
+-      struct gendisk *disk = inode->i_bdev->bd_disk;
+       struct acsi_info_struct *aip = disk->private_data;
+       if (--aip->access_count == 0 && aip->removable)
+               acsi_prevent_removal(aip, 0);
+@@ -1327,8 +1327,6 @@ static int acsi_mode_sense( int target, 
+  ********************************************************************/
+-extern struct block_device_operations acsi_fops;
+-
+ static struct gendisk *acsi_gendisk[MAX_DEV];
+ #define MAX_SCSI_DEVICE_CODE 10
+--- linux-2.6.0-test6/drivers/block/amiflop.c  2003-09-08 13:58:56.000000000 -0700
++++ 25/drivers/block/amiflop.c 2003-10-05 00:34:00.000000000 -0700
+@@ -1434,10 +1434,11 @@ static void do_fd_request(request_queue_
+       redo_fd_request();
+ }
+-static int fd_ioctl(struct inode *inode, struct file *filp,
++static int fd_ioctl(struct block_device *bdev, struct file *filp,
+                   unsigned int cmd, unsigned long param)
+ {
+-      int drive = iminor(inode) & 3;
++      struct amiga_floppy_struct *floppy = bdev->bd_disk->private_data;
++      int drive = floppy - unit;
+       static struct floppy_struct getprm;
+       switch(cmd){
+@@ -1459,7 +1460,7 @@ static int fd_ioctl(struct inode *inode,
+                       rel_fdc();
+                       return -EBUSY;
+               }
+-              fsync_bdev(inode->i_bdev);
++              fsync_bdev(bdev);
+               if (fd_motor_on(drive) == 0) {
+                       rel_fdc();
+                       return -ENODEV;
+@@ -1488,7 +1489,7 @@ static int fd_ioctl(struct inode *inode,
+               break;
+       case FDFMTEND:
+               floppy_off(drive);
+-              invalidate_bdev(inode->i_bdev, 0);
++              invalidate_bdev(bdev, 0);
+               break;
+       case FDGETPRM:
+               memset((void *)&getprm, 0, sizeof (getprm));
+@@ -1559,10 +1560,11 @@ static void fd_probe(int dev)
+  * /dev/PS0 etc), and disallows simultaneous access to the same
+  * drive with different device numbers.
+  */
+-static int floppy_open(struct inode *inode, struct file *filp)
++static int floppy_open(struct block_device *bdev, struct file *filp)
+ {
+-      int drive = iminor(inode) & 3;
+-      int system =  (iminor(inode) & 4) >> 2;
++      struct amiga_floppy_struct *p = bdev->bd_disk->private_data;
++      int drive = p - unit;
++      int system =  (MINOR(bdev->bd_dev) & 4) >> 2;
+       int old_dev;
+       unsigned long flags;
+@@ -1572,7 +1574,7 @@ static int floppy_open(struct inode *ino
+               return -EBUSY;
+       if (filp && filp->f_mode & 3) {
+-              check_disk_change(inode->i_bdev);
++              check_disk_change(bdev);
+               if (filp->f_mode & 2 ) {
+                       int wrprot;
+@@ -1607,9 +1609,10 @@ static int floppy_open(struct inode *ino
+       return 0;
+ }
+-static int floppy_release(struct inode * inode, struct file * filp)
++static int floppy_release(struct gendisk *disk)
+ {
+-      int drive = iminor(inode) & 3;
++      struct amiga_floppy_struct *p = disk->private_data;
++      int drive = p - unit;
+       if (unit[drive].dirty == 1) {
+               del_timer (flush_track_timer + drive);
+--- linux-2.6.0-test6/drivers/block/as-iosched.c       2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/block/as-iosched.c      2003-10-05 00:36:08.000000000 -0700
+@@ -174,12 +174,14 @@ static kmem_cache_t *arq_pool;
+  * IO Context helper functions
+  */
+ /* Debug */
+-static atomic_t nr_as_io_requests = ATOMIC_INIT(0);
++extern atomic_t global_nr_requests;
++static atomic_t nr_as_io_contexts = ATOMIC_INIT(0);
+ /* Called to deallocate the as_io_context */
+ static void free_as_io_context(struct as_io_context *aic)
+ {
+-      atomic_dec(&nr_as_io_requests);
++      WARN_ON(atomic_read(&nr_as_io_contexts) == 0);
++      atomic_dec(&nr_as_io_contexts);
+       kfree(aic);
+ }
+@@ -195,7 +197,9 @@ static struct as_io_context *alloc_as_io
+       ret = kmalloc(sizeof(*ret), GFP_ATOMIC);
+       if (ret) {
+-              atomic_inc(&nr_as_io_requests);
++              atomic_inc(&nr_as_io_contexts);
++              WARN_ON(atomic_read(&nr_as_io_contexts) ==
++                      1 + nr_threads + atomic_read(&global_nr_requests));
+               ret->dtor = free_as_io_context;
+               ret->exit = exit_as_io_context;
+               ret->state = 1 << AS_TASK_RUNNING;
+@@ -914,6 +918,8 @@ static void as_completed_request(request
+       struct as_rq *arq = RQ_DATA(rq);
+       struct as_io_context *aic;
++      WARN_ON(!list_empty(&rq->queuelist));
++
+       if (unlikely(arq->state != AS_RQ_DISPATCHED))
+               return;
+@@ -926,6 +932,7 @@ static void as_completed_request(request
+               if (ad->batch_data_dir == REQ_SYNC)
+                       ad->new_batch = 1;
+       }
++      WARN_ON(ad->nr_dispatched == 0);
+       ad->nr_dispatched--;
+       /*
+@@ -1140,8 +1147,6 @@ static void as_move_to_dispatch(struct a
+       /*
+        * take it off the sort and fifo list, add to dispatch queue
+        */
+-      as_remove_queued_request(ad->q, rq);
+-
+       insert = ad->dispatch->prev;
+       while (!list_empty(&rq->queuelist)) {
+@@ -1159,6 +1164,7 @@ static void as_move_to_dispatch(struct a
+               ad->nr_dispatched++;
+       }
++      as_remove_queued_request(ad->q, rq);
+       list_add(&rq->queuelist, insert);
+       if (arq->io_context && arq->io_context->aic)
+               atomic_inc(&arq->io_context->aic->nr_dispatched);
+@@ -1325,12 +1331,27 @@ static struct request *as_next_request(r
+ static inline void
+ as_add_aliased_request(struct as_data *ad, struct as_rq *arq, struct as_rq *alias)
+ {
++      struct request  *req = arq->request;
++      struct list_head *insert = alias->request->queuelist.prev;
++
++      /*
++       * Transfer list of aliases
++       */
++      while (!list_empty(&req->queuelist)) {
++              struct request *__rq = list_entry_rq(req->queuelist.next);
++              struct as_rq *__arq = RQ_DATA(__rq);
++
++              list_move_tail(&__rq->queuelist, &alias->request->queuelist);
++
++              WARN_ON(__arq->state != AS_RQ_QUEUED);
++      }
++
+       /*
+        * Another request with the same start sector on the rbtree.
+        * Link this request to that sector. They are untangled in
+        * as_move_to_dispatch
+        */
+-      list_add_tail(&arq->request->queuelist, &alias->request->queuelist);
++      list_add(&arq->request->queuelist, insert);
+       /*
+        * Don't want to have to handle merges.
+@@ -1390,9 +1411,6 @@ static void as_add_request(struct as_dat
+               }
+       }
+-
+-
+-
+       arq->state = AS_RQ_QUEUED;
+ }
+@@ -1596,7 +1614,8 @@ static void as_merged_request(request_qu
+                */
+       }
+-      q->last_merge = req;
++      if (arq->on_hash)
++              q->last_merge = req;
+ }
+ static void
+--- linux-2.6.0-test6/drivers/block/ataflop.c  2003-09-08 13:58:56.000000000 -0700
++++ 25/drivers/block/ataflop.c 2003-10-05 00:34:00.000000000 -0700
+@@ -364,13 +364,12 @@ static void finish_fdc_done( int dummy )
+ static __inline__ void copy_buffer( void *from, void *to);
+ static void setup_req_params( int drive );
+ static void redo_fd_request( void);
+-static int fd_ioctl( struct inode *inode, struct file *filp, unsigned int
++static int fd_ioctl(struct block_device *bdev, struct file *filp, unsigned int
+                      cmd, unsigned long param);
+ static void fd_probe( int drive );
+ static int fd_test_drive_present( int drive );
+ static void config_types( void );
+-static int floppy_open( struct inode *inode, struct file *filp );
+-static int floppy_release( struct inode * inode, struct file * filp );
++static int floppy_open(struct block_device *bdev, struct file *filp );
+ /************************* End of Prototypes **************************/
+@@ -1496,10 +1495,10 @@ void do_fd_request(request_queue_t * q)
+       atari_enable_irq( IRQ_MFP_FDC );
+ }
+-static int fd_ioctl(struct inode *inode, struct file *filp,
++static int fd_ioctl(struct block_device *bdev, struct file *filp,
+                   unsigned int cmd, unsigned long param)
+ {
+-      struct gendisk *disk = inode->i_bdev->bd_disk;
++      struct gendisk *disk = bdev->bd_disk;
+       struct atari_floppy_struct *floppy = disk->private_data;
+       int drive = floppy - unit;
+       int type = floppy->type;
+@@ -1673,7 +1672,7 @@ static int fd_ioctl(struct inode *inode,
+               /* invalidate the buffer track to force a reread */
+               BufferDrive = -1;
+               set_bit(drive, &fake_change);
+-              check_disk_change(inode->i_bdev);
++              check_disk_change(bdev);
+               return 0;
+       default:
+               return -EINVAL;
+@@ -1816,10 +1815,10 @@ static void __init config_types( void )
+  * drive with different device numbers.
+  */
+-static int floppy_open( struct inode *inode, struct file *filp )
++static int floppy_open(struct block_device *bdev, struct file *filp )
+ {
+-      struct atari_floppy_struct *p = inode->i_bdev->bd_disk->private_data;
+-      int type  = iminor(inode) >> 2;
++      struct atari_floppy_struct *p = bdev->bd_disk->private_data;
++      int type  = MINOR(bdev->bd_dev) >> 2;
+       DPRINT(("fd_open: type=%d\n",type));
+       if (p->ref && p->type != type)
+@@ -1839,14 +1838,13 @@ static int floppy_open( struct inode *in
+               return 0;
+       if (filp->f_mode & 3) {
+-              check_disk_change(inode->i_bdev);
++              check_disk_change(bdev);
+               if (filp->f_mode & 2) {
+                       if (p->wpstat) {
+                               if (p->ref < 0)
+                                       p->ref = 0;
+                               else
+                                       p->ref--;
+-                              floppy_release(inode, filp);
+                               return -EROFS;
+                       }
+               }
+@@ -1855,9 +1853,9 @@ static int floppy_open( struct inode *in
+ }
+-static int floppy_release( struct inode * inode, struct file * filp )
++static int floppy_release(struct gendisk *disk)
+ {
+-      struct atari_floppy_struct *p = inode->i_bdev->bd_disk->private_data;
++      struct atari_floppy_struct *p = disk->private_data;
+       if (p->ref < 0)
+               p->ref = 0;
+       else if (!p->ref--) {
+--- linux-2.6.0-test6/drivers/block/cciss.c    2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/block/cciss.c   2003-10-05 00:34:00.000000000 -0700
+@@ -111,12 +111,10 @@ static struct board_type products[] = {
+ static ctlr_info_t *hba[MAX_CTLR];
+-static struct proc_dir_entry *proc_cciss;
+-
+ static void do_cciss_request(request_queue_t *q);
+-static int cciss_open(struct inode *inode, struct file *filep);
+-static int cciss_release(struct inode *inode, struct file *filep);
+-static int cciss_ioctl(struct inode *inode, struct file *filep, 
++static int cciss_open(struct block_device *bdev, struct file *filep);
++static int cciss_release(struct gendisk *disk);
++static int cciss_ioctl(struct block_device *bdev, struct file *filep, 
+               unsigned int cmd, unsigned long arg);
+ static int revalidate_allvol(ctlr_info_t *host);
+@@ -137,8 +135,6 @@ static int cciss_proc_get_info(char *buf
+               int length, int *eof, void *data);
+ static void cciss_procinit(int i);
+ #else
+-static int cciss_proc_get_info(char *buffer, char **start, off_t offset, 
+-              int length, int *eof, void *data) { return 0;}
+ static void cciss_procinit(int i) {}
+ #endif /* CONFIG_PROC_FS */
+@@ -156,6 +152,9 @@ static struct block_device_operations cc
+  * Report information about this controller.
+  */
+ #ifdef CONFIG_PROC_FS
++
++static struct proc_dir_entry *proc_cciss;
++
+ static int cciss_proc_get_info(char *buffer, char **start, off_t offset, 
+               int length, int *eof, void *data)
+ {
+@@ -363,13 +362,13 @@ static inline drive_info_struct *get_drv
+ /*
+  * Open.  Make sure the device is really there.
+  */
+-static int cciss_open(struct inode *inode, struct file *filep)
++static int cciss_open(struct block_device *bdev, struct file *filep)
+ {
+-      ctlr_info_t *host = get_host(inode->i_bdev->bd_disk);
+-      drive_info_struct *drv = get_drv(inode->i_bdev->bd_disk);
++      ctlr_info_t *host = get_host(bdev->bd_disk);
++      drive_info_struct *drv = get_drv(bdev->bd_disk);
+ #ifdef CCISS_DEBUG
+-      printk(KERN_DEBUG "cciss_open %s\n", inode->i_bdev->bd_disk->disk_name);
++      printk(KERN_DEBUG "cciss_open %s\n", bdev->bd_disk->disk_name);
+ #endif /* CCISS_DEBUG */ 
+       /*
+@@ -379,7 +378,7 @@ static int cciss_open(struct inode *inod
+        * for "raw controller".
+        */
+       if (drv->nr_blocks == 0) {
+-              if (iminor(inode) != 0)
++              if (bdev != bdev->bd_contains || drv != host->drv)
+                       return -ENXIO;
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+@@ -391,13 +390,13 @@ static int cciss_open(struct inode *inod
+ /*
+  * Close.  Sync first.
+  */
+-static int cciss_release(struct inode *inode, struct file *filep)
++static int cciss_release(struct gendisk *disk)
+ {
+-      ctlr_info_t *host = get_host(inode->i_bdev->bd_disk);
+-      drive_info_struct *drv = get_drv(inode->i_bdev->bd_disk);
++      ctlr_info_t *host = get_host(disk);
++      drive_info_struct *drv = get_drv(disk);
+ #ifdef CCISS_DEBUG
+-      printk(KERN_DEBUG "cciss_release %s\n", inode->i_bdev->bd_disk->disk_name);
++      printk(KERN_DEBUG "cciss_release %s\n", disk->disk_name);
+ #endif /* CCISS_DEBUG */
+       drv->usage_count--;
+@@ -408,10 +407,9 @@ static int cciss_release(struct inode *i
+ /*
+  * ioctl 
+  */
+-static int cciss_ioctl(struct inode *inode, struct file *filep, 
++static int cciss_ioctl(struct block_device *bdev, struct file *filep, 
+               unsigned int cmd, unsigned long arg)
+ {
+-      struct block_device *bdev = inode->i_bdev;
+       struct gendisk *disk = bdev->bd_disk;
+       ctlr_info_t *host = get_host(disk);
+       drive_info_struct *drv = get_drv(disk);
+@@ -434,7 +432,7 @@ static int cciss_ioctl(struct inode *ino
+                         driver_geo.sectors = 0x3f;
+                         driver_geo.cylinders = (int)drv->nr_blocks / (0xff*0x3f);
+                 }
+-                driver_geo.start= get_start_sect(inode->i_bdev);
++                driver_geo.start= get_start_sect(bdev);
+                 if (copy_to_user((void *) arg, &driver_geo,
+                                 sizeof( struct hd_geometry)))
+                         return  -EFAULT;
+@@ -636,9 +634,11 @@ static int cciss_ioctl(struct inode *ino
+               {       
+                       return -EINVAL;
+               } 
++#if 0 /* 'buf_size' member is 16-bits, and always smaller than kmalloc limit */
+               /* Check kmalloc limits */
+               if(iocommand.buf_size > 128000)
+                       return -EINVAL;
++#endif
+               if(iocommand.buf_size > 0)
+               {
+                       buff =  kmalloc(iocommand.buf_size, GFP_KERNEL);
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/drivers/block/cfq-iosched.c     2003-10-05 00:34:17.000000000 -0700
+@@ -0,0 +1,707 @@
++/*
++ *  linux/drivers/block/cfq-iosched.c
++ *
++ *  CFQ, or complete fairness queueing, disk scheduler.
++ *
++ *  Based on ideas from a previously unfinished io
++ *  scheduler (round robin per-process disk scheduling) and Andrea Arcangeli.
++ *
++ *  Copyright (C) 2003 Jens Axboe <axboe@suse.de>
++ */
++#include <linux/kernel.h>
++#include <linux/fs.h>
++#include <linux/blkdev.h>
++#include <linux/elevator.h>
++#include <linux/bio.h>
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/compiler.h>
++#include <linux/hash.h>
++#include <linux/rbtree.h>
++#include <linux/mempool.h>
++
++/*
++ * tunables
++ */
++static int cfq_quantum = 4;
++static int cfq_queued = 8;
++
++#define CFQ_QHASH_SHIFT               6
++#define CFQ_QHASH_ENTRIES     (1 << CFQ_QHASH_SHIFT)
++#define list_entry_qhash(entry)       list_entry((entry), struct cfq_queue, cfq_hash)
++
++#define CFQ_MHASH_SHIFT               8
++#define CFQ_MHASH_BLOCK(sec)  ((sec) >> 3)
++#define CFQ_MHASH_ENTRIES     (1 << CFQ_MHASH_SHIFT)
++#define CFQ_MHASH_FN(sec)     (hash_long(CFQ_MHASH_BLOCK((sec)),CFQ_MHASH_SHIFT))
++#define ON_MHASH(crq)         !list_empty(&(crq)->hash)
++#define rq_hash_key(rq)               ((rq)->sector + (rq)->nr_sectors)
++#define list_entry_hash(ptr)  list_entry((ptr), struct cfq_rq, hash)
++
++#define list_entry_cfqq(ptr)  list_entry((ptr), struct cfq_queue, cfq_list)
++
++#define RQ_DATA(rq)           ((struct cfq_rq *) (rq)->elevator_private)
++
++static kmem_cache_t *crq_pool;
++static kmem_cache_t *cfq_pool;
++static mempool_t *cfq_mpool;
++
++struct cfq_data {
++      struct list_head rr_list;
++      struct list_head *dispatch;
++      struct list_head *cfq_hash;
++
++      struct list_head *crq_hash;
++
++      unsigned int busy_queues;
++      unsigned int max_queued;
++
++      mempool_t *crq_pool;
++};
++
++struct cfq_queue {
++      struct list_head cfq_hash;
++      struct list_head cfq_list;
++      struct rb_root sort_list;
++      int pid;
++      int queued[2];
++#if 0
++      /*
++       * with a simple addition like this, we can do io priorities. almost.
++       * does need a split request free list, too.
++       */
++      int io_prio
++#endif
++};
++
++struct cfq_rq {
++      struct rb_node rb_node;
++      sector_t rb_key;
++
++      struct request *request;
++
++      struct cfq_queue *cfq_queue;
++
++      struct list_head hash;
++};
++
++static void cfq_put_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq);
++static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *cfqd, int pid);
++static void cfq_dispatch_sort(struct list_head *head, struct cfq_rq *crq);
++
++/*
++ * lots of deadline iosched dupes, can be abstracted later...
++ */
++static inline void __cfq_del_crq_hash(struct cfq_rq *crq)
++{
++      list_del_init(&crq->hash);
++}
++
++static inline void cfq_del_crq_hash(struct cfq_rq *crq)
++{
++      if (ON_MHASH(crq))
++              __cfq_del_crq_hash(crq);
++}
++
++static void cfq_remove_merge_hints(request_queue_t *q, struct cfq_rq *crq)
++{
++      cfq_del_crq_hash(crq);
++
++      if (q->last_merge == crq->request)
++              q->last_merge = NULL;
++}
++
++static inline void cfq_add_crq_hash(struct cfq_data *cfqd, struct cfq_rq *crq)
++{
++      struct request *rq = crq->request;
++
++      BUG_ON(ON_MHASH(crq));
++
++      list_add(&crq->hash, &cfqd->crq_hash[CFQ_MHASH_FN(rq_hash_key(rq))]);
++}
++
++static struct request *cfq_find_rq_hash(struct cfq_data *cfqd, sector_t offset)
++{
++      struct list_head *hash_list = &cfqd->crq_hash[CFQ_MHASH_FN(offset)];
++      struct list_head *entry, *next = hash_list->next;
++
++      while ((entry = next) != hash_list) {
++              struct cfq_rq *crq = list_entry_hash(entry);
++              struct request *__rq = crq->request;
++
++              next = entry->next;
++
++              BUG_ON(!ON_MHASH(crq));
++
++              if (!rq_mergeable(__rq)) {
++                      __cfq_del_crq_hash(crq);
++                      continue;
++              }
++
++              if (rq_hash_key(__rq) == offset)
++                      return __rq;
++      }
++
++      return NULL;
++}
++
++/*
++ * rb tree support functions
++ */
++#define RB_NONE               (2)
++#define RB_EMPTY(node)        ((node)->rb_node == NULL)
++#define RB_CLEAR(node)        ((node)->rb_color = RB_NONE)
++#define RB_CLEAR_ROOT(root)   ((root)->rb_node = NULL)
++#define ON_RB(node)   ((node)->rb_color != RB_NONE)
++#define rb_entry_crq(node)    rb_entry((node), struct cfq_rq, rb_node)
++#define rq_rb_key(rq)         (rq)->sector
++
++static inline void cfq_del_crq_rb(struct cfq_queue *cfqq, struct cfq_rq *crq)
++{
++      if (ON_RB(&crq->rb_node)) {
++              cfqq->queued[rq_data_dir(crq->request)]--;
++              rb_erase(&crq->rb_node, &cfqq->sort_list);
++              crq->cfq_queue = NULL;
++      }
++}
++
++static struct cfq_rq *
++__cfq_add_crq_rb(struct cfq_queue *cfqq, struct cfq_rq *crq)
++{
++      struct rb_node **p = &cfqq->sort_list.rb_node;
++      struct rb_node *parent = NULL;
++      struct cfq_rq *__crq;
++
++      while (*p) {
++              parent = *p;
++              __crq = rb_entry_crq(parent);
++
++              if (crq->rb_key < __crq->rb_key)
++                      p = &(*p)->rb_left;
++              else if (crq->rb_key > __crq->rb_key)
++                      p = &(*p)->rb_right;
++              else
++                      return __crq;
++      }
++
++      rb_link_node(&crq->rb_node, parent, p);
++      return 0;
++}
++
++static void
++cfq_add_crq_rb(struct cfq_data *cfqd, struct cfq_queue *cfqq,struct cfq_rq *crq)
++{
++      struct request *rq = crq->request;
++      struct cfq_rq *__alias;
++
++      crq->rb_key = rq_rb_key(rq);
++      cfqq->queued[rq_data_dir(rq)]++;
++retry:
++      __alias = __cfq_add_crq_rb(cfqq, crq);
++      if (!__alias) {
++              rb_insert_color(&crq->rb_node, &cfqq->sort_list);
++              crq->cfq_queue = cfqq;
++              return;
++      }
++
++      cfq_del_crq_rb(cfqq, __alias);
++      cfq_dispatch_sort(cfqd->dispatch, __alias);
++      goto retry;
++}
++
++static struct request *
++cfq_find_rq_rb(struct cfq_data *cfqd, sector_t sector)
++{
++      struct cfq_queue *cfqq = cfq_find_cfq_hash(cfqd, current->tgid);
++      struct rb_node *n;
++
++      if (!cfqq)
++              goto out;
++
++      n = cfqq->sort_list.rb_node;
++      while (n) {
++              struct cfq_rq *crq = rb_entry_crq(n);
++
++              if (sector < crq->rb_key)
++                      n = n->rb_left;
++              else if (sector > crq->rb_key)
++                      n = n->rb_right;
++              else
++                      return crq->request;
++      }
++
++out:
++      return NULL;
++}
++
++static void cfq_remove_request(request_queue_t *q, struct request *rq)
++{
++      struct cfq_data *cfqd = q->elevator.elevator_data;
++      struct cfq_rq *crq = RQ_DATA(rq);
++
++      if (crq) {
++              struct cfq_queue *cfqq = crq->cfq_queue;
++
++              cfq_remove_merge_hints(q, crq);
++              list_del_init(&rq->queuelist);
++
++              if (cfqq) {
++                      cfq_del_crq_rb(cfqq, crq);
++
++                      if (RB_EMPTY(&cfqq->sort_list))
++                              cfq_put_queue(cfqd, cfqq);
++              }
++      }
++}
++
++static int
++cfq_merge(request_queue_t *q, struct request **req, struct bio *bio)
++{
++      struct cfq_data *cfqd = q->elevator.elevator_data;
++      struct request *__rq;
++      int ret;
++
++      ret = elv_try_last_merge(q, bio);
++      if (ret != ELEVATOR_NO_MERGE) {
++              __rq = q->last_merge;
++              goto out_insert;
++      }
++
++      __rq = cfq_find_rq_hash(cfqd, bio->bi_sector);
++      if (__rq) {
++              BUG_ON(__rq->sector + __rq->nr_sectors != bio->bi_sector);
++
++              if (elv_rq_merge_ok(__rq, bio)) {
++                      ret = ELEVATOR_BACK_MERGE;
++                      goto out;
++              }
++      }
++
++      __rq = cfq_find_rq_rb(cfqd, bio->bi_sector + bio_sectors(bio));
++      if (__rq) {
++              if (elv_rq_merge_ok(__rq, bio)) {
++                      ret = ELEVATOR_FRONT_MERGE;
++                      goto out;
++              }
++      }
++
++      return ELEVATOR_NO_MERGE;
++out:
++      q->last_merge = __rq;
++out_insert:
++      *req = __rq;
++      return ret;
++}
++
++static void cfq_merged_request(request_queue_t *q, struct request *req)
++{
++      struct cfq_data *cfqd = q->elevator.elevator_data;
++      struct cfq_rq *crq = RQ_DATA(req);
++
++      cfq_del_crq_hash(crq);
++      cfq_add_crq_hash(cfqd, crq);
++
++      if (ON_RB(&crq->rb_node) && (rq_rb_key(req) != crq->rb_key)) {
++              struct cfq_queue *cfqq = crq->cfq_queue;
++
++              cfq_del_crq_rb(cfqq, crq);
++              cfq_add_crq_rb(cfqd, cfqq, crq);
++      }
++
++      q->last_merge = req;
++}
++
++static void
++cfq_merged_requests(request_queue_t *q, struct request *req,
++                  struct request *next)
++{
++      cfq_merged_request(q, req);
++      cfq_remove_request(q, next);
++}
++
++static void cfq_dispatch_sort(struct list_head *head, struct cfq_rq *crq)
++{
++      struct list_head *entry = head;
++      struct request *__rq;
++
++      if (!list_empty(head)) {
++              __rq = list_entry_rq(head->next);
++
++              if (crq->request->sector < __rq->sector) {
++                      entry = head->prev;
++                      goto link;
++              }
++      }
++
++      while ((entry = entry->prev) != head) {
++              __rq = list_entry_rq(entry);
++
++              if (crq->request->sector <= __rq->sector)
++                      break;
++      }
++
++link:
++      list_add_tail(&crq->request->queuelist, entry);
++}
++
++static inline void
++__cfq_dispatch_requests(request_queue_t *q, struct cfq_data *cfqd,
++                      struct cfq_queue *cfqq)
++{
++      struct cfq_rq *crq = rb_entry_crq(rb_first(&cfqq->sort_list));
++
++      cfq_del_crq_rb(cfqq, crq);
++      cfq_remove_merge_hints(q, crq);
++      cfq_dispatch_sort(cfqd->dispatch, crq);
++}
++
++static int cfq_dispatch_requests(request_queue_t *q, struct cfq_data *cfqd)
++{
++      struct cfq_queue *cfqq;
++      struct list_head *entry, *tmp;
++      int ret, queued, good_queues;
++
++      if (list_empty(&cfqd->rr_list))
++              return 0;
++
++      queued = ret = 0;
++restart:
++      good_queues = 0;
++      list_for_each_safe(entry, tmp, &cfqd->rr_list) {
++              cfqq = list_entry_cfqq(cfqd->rr_list.next);
++
++              BUG_ON(RB_EMPTY(&cfqq->sort_list));
++
++              __cfq_dispatch_requests(q, cfqd, cfqq);
++
++              if (RB_EMPTY(&cfqq->sort_list))
++                      cfq_put_queue(cfqd, cfqq);
++              else
++                      good_queues++;
++
++              queued++;
++              ret = 1;
++      }
++
++      if ((queued < cfq_quantum) && good_queues)
++              goto restart;
++
++      return ret;
++}
++
++static struct request *cfq_next_request(request_queue_t *q)
++{
++      struct cfq_data *cfqd = q->elevator.elevator_data;
++      struct request *rq;
++
++      if (!list_empty(cfqd->dispatch)) {
++              struct cfq_rq *crq;
++dispatch:
++              rq = list_entry_rq(cfqd->dispatch->next);
++
++              BUG_ON(q->last_merge == rq);
++              crq = RQ_DATA(rq);
++              if (crq)
++                      BUG_ON(ON_MHASH(crq));
++
++              return rq;
++      }
++
++      if (cfq_dispatch_requests(q, cfqd))
++              goto dispatch;
++
++      return NULL;
++}
++
++static inline struct cfq_queue *
++__cfq_find_cfq_hash(struct cfq_data *cfqd, int pid, const int hashval)
++{
++      struct list_head *hash_list = &cfqd->cfq_hash[hashval];
++      struct list_head *entry;
++
++      list_for_each(entry, hash_list) {
++              struct cfq_queue *__cfqq = list_entry_qhash(entry);
++
++              if (__cfqq->pid == pid)
++                      return __cfqq;
++      }
++
++      return NULL;
++}
++
++static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *cfqd, int pid)
++{
++      const int hashval = hash_long(current->tgid, CFQ_QHASH_SHIFT);
++
++      return __cfq_find_cfq_hash(cfqd, pid, hashval);
++}
++
++static void cfq_put_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
++{
++      cfqd->busy_queues--;
++      list_del(&cfqq->cfq_list);
++      list_del(&cfqq->cfq_hash);
++      mempool_free(cfqq, cfq_mpool);
++}
++
++static struct cfq_queue *cfq_get_queue(struct cfq_data *cfqd, int pid)
++{
++      const int hashval = hash_long(current->tgid, CFQ_QHASH_SHIFT);
++      struct cfq_queue *cfqq = __cfq_find_cfq_hash(cfqd, pid, hashval);
++
++      if (!cfqq) {
++              cfqq = mempool_alloc(cfq_mpool, GFP_NOIO);
++
++              INIT_LIST_HEAD(&cfqq->cfq_hash);
++              INIT_LIST_HEAD(&cfqq->cfq_list);
++              RB_CLEAR_ROOT(&cfqq->sort_list);
++
++              cfqq->pid = pid;
++              cfqq->queued[0] = cfqq->queued[1] = 0;
++              list_add(&cfqq->cfq_hash, &cfqd->cfq_hash[hashval]);
++      }
++
++      return cfqq;
++}
++
++static void cfq_enqueue(struct cfq_data *cfqd, struct cfq_rq *crq)
++{
++      struct cfq_queue *cfqq;
++
++      cfqq = cfq_get_queue(cfqd, current->tgid);
++
++      cfq_add_crq_rb(cfqd, cfqq, crq);
++
++      if (list_empty(&cfqq->cfq_list)) {
++              list_add(&cfqq->cfq_list, &cfqd->rr_list);
++              cfqd->busy_queues++;
++      }
++}
++
++static void
++cfq_insert_request(request_queue_t *q, struct request *rq, int where)
++{
++      struct cfq_data *cfqd = q->elevator.elevator_data;
++      struct cfq_rq *crq = RQ_DATA(rq);
++
++      switch (where) {
++              case ELEVATOR_INSERT_BACK:
++                      while (cfq_dispatch_requests(q, cfqd))
++                              ;
++                      list_add_tail(&rq->queuelist, cfqd->dispatch);
++                      break;
++              case ELEVATOR_INSERT_FRONT:
++                      list_add(&rq->queuelist, cfqd->dispatch);
++                      break;
++              case ELEVATOR_INSERT_SORT:
++                      BUG_ON(!blk_fs_request(rq));
++                      cfq_enqueue(cfqd, crq);
++                      break;
++              default:
++                      printk("%s: bad insert point %d\n", __FUNCTION__,where);
++                      return;
++      }
++
++      if (rq_mergeable(rq)) {
++              cfq_add_crq_hash(cfqd, crq);
++
++              if (!q->last_merge)
++                      q->last_merge = rq;
++      }
++}
++
++static int cfq_queue_empty(request_queue_t *q)
++{
++      struct cfq_data *cfqd = q->elevator.elevator_data;
++
++      if (list_empty(cfqd->dispatch) && list_empty(&cfqd->rr_list))
++              return 1;
++
++      return 0;
++}
++
++static struct request *
++cfq_former_request(request_queue_t *q, struct request *rq)
++{
++      struct cfq_rq *crq = RQ_DATA(rq);
++      struct rb_node *rbprev = rb_prev(&crq->rb_node);
++
++      if (rbprev)
++              return rb_entry_crq(rbprev)->request;
++
++      return NULL;
++}
++
++static struct request *
++cfq_latter_request(request_queue_t *q, struct request *rq)
++{
++      struct cfq_rq *crq = RQ_DATA(rq);
++      struct rb_node *rbnext = rb_next(&crq->rb_node);
++
++      if (rbnext)
++              return rb_entry_crq(rbnext)->request;
++
++      return NULL;
++}
++
++static int cfq_may_queue(request_queue_t *q, int rw)
++{
++      struct cfq_data *cfqd = q->elevator.elevator_data;
++      struct cfq_queue *cfqq;
++      int ret = 1;
++
++      if (!cfqd->busy_queues)
++              goto out;
++
++      cfqq = cfq_find_cfq_hash(cfqd, current->tgid);
++      if (cfqq) {
++              int limit = (q->nr_requests - cfq_queued) / cfqd->busy_queues;
++
++              if (limit < 3)
++                      limit = 3;
++              else if (limit > cfqd->max_queued)
++                      limit = cfqd->max_queued;
++
++              if (cfqq->queued[rw] > limit)
++                      ret = 0;
++      }
++out:
++      return ret;
++}
++
++static void cfq_put_request(request_queue_t *q, struct request *rq)
++{
++      struct cfq_data *cfqd = q->elevator.elevator_data;
++      struct cfq_rq *crq = RQ_DATA(rq);
++
++      if (crq) {
++              BUG_ON(q->last_merge == rq);
++              BUG_ON(ON_MHASH(crq));
++
++              mempool_free(crq, cfqd->crq_pool);
++              rq->elevator_private = NULL;
++      }
++}
++
++static int cfq_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
++{
++      struct cfq_data *cfqd = q->elevator.elevator_data;
++      struct cfq_rq *crq = mempool_alloc(cfqd->crq_pool, gfp_mask);
++
++      if (crq) {
++              RB_CLEAR(&crq->rb_node);
++              crq->request = rq;
++              crq->cfq_queue = NULL;
++              INIT_LIST_HEAD(&crq->hash);
++              rq->elevator_private = crq;
++              return 0;
++      }
++
++      return 1;
++}
++
++static void cfq_exit(request_queue_t *q, elevator_t *e)
++{
++      struct cfq_data *cfqd = e->elevator_data;
++
++      e->elevator_data = NULL;
++      mempool_destroy(cfqd->crq_pool);
++      kfree(cfqd->crq_hash);
++      kfree(cfqd->cfq_hash);
++      kfree(cfqd);
++}
++
++static int cfq_init(request_queue_t *q, elevator_t *e)
++{
++      struct cfq_data *cfqd;
++      int i;
++
++      cfqd = kmalloc(sizeof(*cfqd), GFP_KERNEL);
++      if (!cfqd)
++              return -ENOMEM;
++
++      memset(cfqd, 0, sizeof(*cfqd));
++      INIT_LIST_HEAD(&cfqd->rr_list);
++
++      cfqd->crq_hash = kmalloc(sizeof(struct list_head) * CFQ_MHASH_ENTRIES, GFP_KERNEL);
++      if (!cfqd->crq_hash)
++              goto out_crqhash;
++
++      cfqd->cfq_hash = kmalloc(sizeof(struct list_head) * CFQ_QHASH_ENTRIES, GFP_KERNEL);
++      if (!cfqd->cfq_hash)
++              goto out_cfqhash;
++
++      cfqd->crq_pool = mempool_create(BLKDEV_MIN_RQ, mempool_alloc_slab, mempool_free_slab, crq_pool);
++      if (!cfqd->crq_pool)
++              goto out_crqpool;
++
++      for (i = 0; i < CFQ_MHASH_ENTRIES; i++)
++              INIT_LIST_HEAD(&cfqd->crq_hash[i]);
++      for (i = 0; i < CFQ_QHASH_ENTRIES; i++)
++              INIT_LIST_HEAD(&cfqd->cfq_hash[i]);
++
++      cfqd->dispatch = &q->queue_head;
++      e->elevator_data = cfqd;
++
++      /*
++       * just set it to some high value, we want anyone to be able to queue
++       * some requests. fairness is handled differently
++       */
++      cfqd->max_queued = q->nr_requests;
++      q->nr_requests = 8192;
++
++      return 0;
++out_crqpool:
++      kfree(cfqd->cfq_hash);
++out_cfqhash:
++      kfree(cfqd->crq_hash);
++out_crqhash:
++      kfree(cfqd);
++      return -ENOMEM;
++}
++
++static int __init cfq_slab_setup(void)
++{
++      crq_pool = kmem_cache_create("crq_pool", sizeof(struct cfq_rq), 0, 0,
++                                      NULL, NULL);
++
++      if (!crq_pool)
++              panic("cfq_iosched: can't init crq pool\n");
++
++      cfq_pool = kmem_cache_create("cfq_pool", sizeof(struct cfq_queue), 0, 0,
++                                      NULL, NULL);
++
++      if (!cfq_pool)
++              panic("cfq_iosched: can't init cfq pool\n");
++
++      cfq_mpool = mempool_create(64, mempool_alloc_slab, mempool_free_slab, cfq_pool);
++
++      if (!cfq_mpool)
++              panic("cfq_iosched: can't init cfq mpool\n");
++
++      return 0;
++}
++
++subsys_initcall(cfq_slab_setup);
++
++elevator_t iosched_cfq = {
++      .elevator_name =                "cfq",
++      .elevator_merge_fn =            cfq_merge,
++      .elevator_merged_fn =           cfq_merged_request,
++      .elevator_merge_req_fn =        cfq_merged_requests,
++      .elevator_next_req_fn =         cfq_next_request,
++      .elevator_add_req_fn =          cfq_insert_request,
++      .elevator_remove_req_fn =       cfq_remove_request,
++      .elevator_queue_empty_fn =      cfq_queue_empty,
++      .elevator_former_req_fn =       cfq_former_request,
++      .elevator_latter_req_fn =       cfq_latter_request,
++      .elevator_set_req_fn =          cfq_set_request,
++      .elevator_put_req_fn =          cfq_put_request,
++      .elevator_may_queue_fn =        cfq_may_queue,
++      .elevator_init_fn =             cfq_init,
++      .elevator_exit_fn =             cfq_exit,
++};
++
++EXPORT_SYMBOL(iosched_cfq);
+--- linux-2.6.0-test6/drivers/block/cpqarray.c 2003-09-08 13:58:56.000000000 -0700
++++ 25/drivers/block/cpqarray.c        2003-10-05 00:34:00.000000000 -0700
+@@ -99,8 +99,6 @@ static struct board_type products[] = {
+ static struct gendisk *ida_gendisk[MAX_CTLR][NWD];
+-static struct proc_dir_entry *proc_array;
+-
+ /* Debug... */
+ #define DBG(s)        do { s } while(0)
+ /* Debug (general info)... */
+@@ -130,9 +128,9 @@ static int sendcmd(
+       unsigned int blkcnt,
+       unsigned int log_unit );
+-static int ida_open(struct inode *inode, struct file *filep);
+-static int ida_release(struct inode *inode, struct file *filep);
+-static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg);
++static int ida_open(struct block_device *bdev, struct file *filep);
++static int ida_release(struct gendisk *disk);
++static int ida_ioctl(struct block_device *bdev, struct file *filep, unsigned int cmd, unsigned long arg);
+ static int ida_ctlr_ioctl(ctlr_info_t *h, int dsk, ida_ioctl_t *io);
+ static void do_ida_request(request_queue_t *q);
+@@ -153,8 +151,6 @@ static void ida_procinit(int i);
+ static int ida_proc_get_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
+ #else
+ static void ida_procinit(int i) {}
+-static int ida_proc_get_info(char *buffer, char **start, off_t offset,
+-                           int length, int *eof, void *data) { return 0;}
+ #endif
+ static inline drv_info_t *get_drv(struct gendisk *disk)
+@@ -179,6 +175,8 @@ static struct block_device_operations id
+ #ifdef CONFIG_PROC_FS
++static struct proc_dir_entry *proc_array;
++
+ /*
+  * Get us a file in /proc/array that says something about each controller.
+  * Create /proc/array if it doesn't exist yet.
+@@ -717,12 +715,12 @@ DBGINFO(
+ /*
+  * Open.  Make sure the device is really there.
+  */
+-static int ida_open(struct inode *inode, struct file *filep)
++static int ida_open(struct block_device *bdev, struct file *filep)
+ {
+-      drv_info_t *drv = get_drv(inode->i_bdev->bd_disk);
+-      ctlr_info_t *host = get_host(inode->i_bdev->bd_disk);
++      drv_info_t *drv = get_drv(bdev->bd_disk);
++      ctlr_info_t *host = get_host(bdev->bd_disk);
+-      DBGINFO(printk("ida_open %s\n", inode->i_bdev->bd_disk->disk_name));
++      DBGINFO(printk("ida_open %s\n", bdev->bd_disk->disk_name));
+       /*
+        * Root is allowed to open raw volume zero even if it's not configured
+        * so array config can still work.  I don't think I really like this,
+@@ -742,9 +740,9 @@ static int ida_open(struct inode *inode,
+ /*
+  * Close.  Sync first.
+  */
+-static int ida_release(struct inode *inode, struct file *filep)
++static int ida_release(struct gendisk *disk)
+ {
+-      ctlr_info_t *host = get_host(inode->i_bdev->bd_disk);
++      ctlr_info_t *host = get_host(disk);
+       host->usage_count--;
+       return 0;
+ }
+@@ -1024,10 +1022,10 @@ static void ida_timer(unsigned long tdat
+  *  ida_ioctl does some miscellaneous stuff like reporting drive geometry,
+  *  setting readahead and submitting commands from userspace to the controller.
+  */
+-static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg)
++static int ida_ioctl(struct block_device *bdev, struct file *filep, unsigned int cmd, unsigned long arg)
+ {
+-      drv_info_t *drv = get_drv(inode->i_bdev->bd_disk);
+-      ctlr_info_t *host = get_host(inode->i_bdev->bd_disk);
++      drv_info_t *drv = get_drv(bdev->bd_disk);
++      ctlr_info_t *host = get_host(bdev->bd_disk);
+       int error;
+       int diskinfo[4];
+       struct hd_geometry *geo = (struct hd_geometry *)arg;
+@@ -1048,7 +1046,7 @@ static int ida_ioctl(struct inode *inode
+               put_user(diskinfo[0], &geo->heads);
+               put_user(diskinfo[1], &geo->sectors);
+               put_user(diskinfo[2], &geo->cylinders);
+-              put_user(get_start_sect(inode->i_bdev), &geo->start);
++              put_user(get_start_sect(bdev), &geo->start);
+               return 0;
+       case IDAGETDRVINFO:
+               if (copy_to_user(&io->c.drv, drv, sizeof(drv_info_t)))
+@@ -1078,7 +1076,7 @@ out_passthru:
+               put_user(host->ctlr_sig, (int*)arg);
+               return 0;
+       case IDAREVALIDATEVOLS:
+-              if (iminor(inode) != 0)
++              if (bdev != bdev->bd_contains || drv != host->drv)
+                       return -ENXIO;
+               return revalidate_allvol(host);
+       case IDADRIVERVERSION:
+--- linux-2.6.0-test6/drivers/block/DAC960.c   2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/block/DAC960.c  2003-10-05 00:33:58.000000000 -0700
+@@ -67,9 +67,9 @@ static long disk_size(DAC960_Controller_
+       }
+ }
+-static int DAC960_open(struct inode *inode, struct file *file)
++static int DAC960_open(struct block_device *bdev, struct file *file)
+ {
+-      struct gendisk *disk = inode->i_bdev->bd_disk;
++      struct gendisk *disk = bdev->bd_disk;
+       DAC960_Controller_T *p = disk->queue->queuedata;
+       int drive_nr = (long)disk->private_data;
+@@ -84,17 +84,17 @@ static int DAC960_open(struct inode *ino
+                       return -ENXIO;
+       }
+-      check_disk_change(inode->i_bdev);
++      check_disk_change(bdev);
+       if (!get_capacity(p->disks[drive_nr]))
+               return -ENXIO;
+       return 0;
+ }
+-static int DAC960_ioctl(struct inode *inode, struct file *file,
++static int DAC960_ioctl(struct block_device *bdev, struct file *file,
+                       unsigned int cmd, unsigned long arg)
+ {
+-      struct gendisk *disk = inode->i_bdev->bd_disk;
++      struct gendisk *disk = bdev->bd_disk;
+       DAC960_Controller_T *p = disk->queue->queuedata;
+       int drive_nr = (long)disk->private_data;
+       struct hd_geometry g, *loc = (struct hd_geometry *)arg;
+@@ -128,7 +128,7 @@ static int DAC960_ioctl(struct inode *in
+               g.cylinders = i->ConfigurableDeviceSize / (g.heads * g.sectors);
+       }
+       
+-      g.start = get_start_sect(inode->i_bdev);
++      g.start = get_start_sect(bdev);
+       return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0; 
+ }
+--- linux-2.6.0-test6/drivers/block/floppy98.c 2003-09-08 13:58:56.000000000 -0700
++++ 25/drivers/block/floppy98.c        2003-10-05 00:34:01.000000000 -0700
+@@ -3484,14 +3484,14 @@ static int get_floppy_geometry(int drive
+       return 0;
+ }
+-static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
++static int fd_ioctl(struct block_device *bdev, struct file *filp, unsigned int cmd,
+                   unsigned long param)
+ {
+ #define FD_IOCTL_ALLOWED ((filp) && (filp)->private_data)
+ #define OUT(c,x) case c: outparam = (const char *) (x); break
+ #define IN(c,x,tag) case c: *(x) = inparam. tag ; return 0
+-      int drive = (long)inode->i_bdev->bd_disk->private_data;
++      int drive = (long)bdev->bd_disk->private_data;
+       int i, type = ITYPE(UDRS->fd_device);
+       int ret;
+       int size;
+@@ -3566,11 +3566,11 @@ static int fd_ioctl(struct inode *inode,
+                       current_type[drive] = NULL;
+                       floppy_sizes[drive] = MAX_DISK_SIZE << 1;
+                       UDRS->keep_data = 0;
+-                      return invalidate_drive(inode->i_bdev);
++                      return invalidate_drive(bdev);
+               case FDSETPRM:
+               case FDDEFPRM:
+                       return set_geometry(cmd, & inparam.g,
+-                                          drive, type, inode->i_bdev);
++                                          drive, type, bdev);
+               case FDGETPRM:
+                       ECALL(get_floppy_geometry(drive, type, 
+                                                 (struct floppy_struct**)
+@@ -3625,7 +3625,7 @@ static int fd_ioctl(struct inode *inode,
+               case FDFMTEND:
+               case FDFLUSH:
+                       LOCK_FDC(drive,1);
+-                      return invalidate_drive(inode->i_bdev);
++                      return invalidate_drive(bdev);
+               case FDSETEMSGTRESH:
+                       UDP->max_errors.reporting =
+@@ -3735,9 +3735,9 @@ static void __init config_types(void)
+               printk("\n");
+ }
+-static int floppy_release(struct inode * inode, struct file * filp)
++static int floppy_release(struct gendisk *disk)
+ {
+-      int drive = (long)inode->i_bdev->bd_disk->private_data;
++      int drive = (long)disk->private_data;
+       down(&open_lock);
+       if (UDRS->fd_ref < 0)
+@@ -3758,11 +3758,10 @@ static int floppy_release(struct inode *
+  * /dev/PS0 etc), and disallows simultaneous access to the same
+  * drive with different device numbers.
+  */
+-#define RETERR(x) do{floppy_release(inode,filp); return -(x);}while(0)
+-static int floppy_open(struct inode * inode, struct file * filp)
++static int floppy_open(struct block_device *bdev, struct file *filp)
+ {
+-      int drive = (long)inode->i_bdev->bd_disk->private_data;
++      int drive = (long)bdev->bd_disk->private_data;
+       int old_dev;
+       int try;
+       int res = -EBUSY;
+@@ -3789,7 +3788,7 @@ static int floppy_open(struct inode * in
+       down(&open_lock);
+       old_dev = UDRS->fd_device;
+-      if (opened_bdev[drive] && opened_bdev[drive] != inode->i_bdev)
++      if (opened_bdev[drive] && opened_bdev[drive] != bdev)
+               goto out2;
+       if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)){
+@@ -3809,7 +3808,7 @@ static int floppy_open(struct inode * in
+       else
+               UDRS->fd_ref++;
+-      opened_bdev[drive] = inode->i_bdev;
++      opened_bdev[drive] = bdev;
+       res = -ENXIO;
+@@ -3844,9 +3843,9 @@ static int floppy_open(struct inode * in
+               }
+       }
+-      UDRS->fd_device = iminor(inode);
+-      set_capacity(disks[drive], floppy_sizes[iminor(inode)]);
+-      if (old_dev != -1 && old_dev != iminor(inode)) {
++      UDRS->fd_device = MINOR(bdev->bd_dev);
++      set_capacity(disks[drive], floppy_sizes[MINOR(bdev->bd_dev)]);
++      if (old_dev != -1 && old_dev != MINOR(bdev->bd_dev)) {
+               if (buffer_drive == drive)
+                       buffer_track = -1;
+       }
+@@ -3859,8 +3858,7 @@ static int floppy_open(struct inode * in
+       /* Allow ioctls if we have write-permissions even if read-only open.
+        * Needed so that programs such as fdrawcmd still can work on write
+        * protected disks */
+-      if ((filp->f_mode & 2) || 
+-          (inode->i_sb && (permission(inode,2) == 0)))
++      if ((filp->f_mode & 2) || permission(filp->f_dentry->d_inode,2) == 0)
+           filp->private_data = (void*) 8;
+       if (UFDCS->rawcmd == 1)
+@@ -3873,7 +3871,7 @@ static int floppy_open(struct inode * in
+       if (!(filp->f_flags & O_NDELAY)) {
+               if (filp->f_mode & 3) {
+                       UDRS->last_checked = 0;
+-                      check_disk_change(inode->i_bdev);
++                      check_disk_change(bdev);
+                       if (UTESTF(FD_DISK_CHANGED))
+                               goto out;
+               }
+--- linux-2.6.0-test6/drivers/block/floppy.c   2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/block/floppy.c  2003-10-05 00:34:01.000000000 -0700
+@@ -3456,14 +3456,14 @@ static int get_floppy_geometry(int drive
+       return 0;
+ }
+-static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
++static int fd_ioctl(struct block_device *bdev, struct file *filp, unsigned int cmd,
+                   unsigned long param)
+ {
+ #define FD_IOCTL_ALLOWED ((filp) && (filp)->private_data)
+ #define OUT(c,x) case c: outparam = (const char *) (x); break
+ #define IN(c,x,tag) case c: *(x) = inparam. tag ; return 0
+-      int drive = (long)inode->i_bdev->bd_disk->private_data;
++      int drive = (long)bdev->bd_disk->private_data;
+       int i, type = ITYPE(UDRS->fd_device);
+       int ret;
+       int size;
+@@ -3539,11 +3539,11 @@ static int fd_ioctl(struct inode *inode,
+                       current_type[drive] = NULL;
+                       floppy_sizes[drive] = MAX_DISK_SIZE << 1;
+                       UDRS->keep_data = 0;
+-                      return invalidate_drive(inode->i_bdev);
++                      return invalidate_drive(bdev);
+               case FDSETPRM:
+               case FDDEFPRM:
+                       return set_geometry(cmd, & inparam.g,
+-                                          drive, type, inode->i_bdev);
++                                          drive, type, bdev);
+               case FDGETPRM:
+                       ECALL(get_floppy_geometry(drive, type, 
+                                                 (struct floppy_struct**)
+@@ -3574,7 +3574,7 @@ static int fd_ioctl(struct inode *inode,
+               case FDFMTEND:
+               case FDFLUSH:
+                       LOCK_FDC(drive,1);
+-                      return invalidate_drive(inode->i_bdev);
++                      return invalidate_drive(bdev);
+               case FDSETEMSGTRESH:
+                       UDP->max_errors.reporting =
+@@ -3685,9 +3685,9 @@ static void __init config_types(void)
+               printk("\n");
+ }
+-static int floppy_release(struct inode * inode, struct file * filp)
++static int floppy_release(struct gendisk *disk)
+ {
+-      int drive = (long)inode->i_bdev->bd_disk->private_data;
++      int drive = (long)disk->private_data;
+       down(&open_lock);
+       if (UDRS->fd_ref < 0)
+@@ -3708,9 +3708,9 @@ static int floppy_release(struct inode *
+  * /dev/PS0 etc), and disallows simultaneous access to the same
+  * drive with different device numbers.
+  */
+-static int floppy_open(struct inode * inode, struct file * filp)
++static int floppy_open(struct block_device *bdev, struct file * filp)
+ {
+-      int drive = (long)inode->i_bdev->bd_disk->private_data;
++      int drive = (long)bdev->bd_disk->private_data;
+       int old_dev;
+       int try;
+       int res = -EBUSY;
+@@ -3719,7 +3719,7 @@ static int floppy_open(struct inode * in
+       filp->private_data = (void*) 0;
+       down(&open_lock);
+       old_dev = UDRS->fd_device;
+-      if (opened_bdev[drive] && opened_bdev[drive] != inode->i_bdev)
++      if (opened_bdev[drive] && opened_bdev[drive] != bdev)
+               goto out2;
+       if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)){
+@@ -3739,7 +3739,7 @@ static int floppy_open(struct inode * in
+       else
+               UDRS->fd_ref++;
+-      opened_bdev[drive] = inode->i_bdev;
++      opened_bdev[drive] = bdev;
+       res = -ENXIO;
+@@ -3774,9 +3774,9 @@ static int floppy_open(struct inode * in
+               }
+       }
+-      UDRS->fd_device = iminor(inode);
+-      set_capacity(disks[drive], floppy_sizes[iminor(inode)]);
+-      if (old_dev != -1 && old_dev != iminor(inode)) {
++      UDRS->fd_device = MINOR(bdev->bd_dev);
++      set_capacity(disks[drive], floppy_sizes[MINOR(bdev->bd_dev)]);
++      if (old_dev != -1 && old_dev != MINOR(bdev->bd_dev)) {
+               if (buffer_drive == drive)
+                       buffer_track = -1;
+       }
+@@ -3784,8 +3784,7 @@ static int floppy_open(struct inode * in
+       /* Allow ioctls if we have write-permissions even if read-only open.
+        * Needed so that programs such as fdrawcmd still can work on write
+        * protected disks */
+-      if ((filp->f_mode & 2) || 
+-          (inode->i_sb && (permission(inode,2, NULL) == 0)))
++      if ((filp->f_mode & 2) || permission(filp->f_dentry->d_inode,2,NULL) == 0)
+           filp->private_data = (void*) 8;
+       if (UFDCS->rawcmd == 1)
+@@ -3794,7 +3793,7 @@ static int floppy_open(struct inode * in
+       if (!(filp->f_flags & O_NDELAY)) {
+               if (filp->f_mode & 3) {
+                       UDRS->last_checked = 0;
+-                      check_disk_change(inode->i_bdev);
++                      check_disk_change(bdev);
+                       if (UTESTF(FD_DISK_CHANGED))
+                               goto out;
+               }
+--- linux-2.6.0-test6/drivers/block/initrd.c   2003-06-14 12:18:51.000000000 -0700
++++ /dev/null  2002-08-30 16:31:37.000000000 -0700
+@@ -1,100 +0,0 @@
+-
+-#include <linux/blkdev.h>
+-#include <linux/genhd.h>
+-#include <linux/initrd.h>
+-#include <linux/init.h>
+-#include <linux/major.h>
+-#include <linux/module.h>
+-#include <linux/spinlock.h>
+-#include <asm/uaccess.h>
+-
+-
+-unsigned long initrd_start, initrd_end;
+-int initrd_below_start_ok;
+-
+-static int initrd_users;
+-static spinlock_t initrd_users_lock = SPIN_LOCK_UNLOCKED;
+-
+-static struct gendisk *initrd_disk;
+-
+-static ssize_t initrd_read(struct file *file, char *buf,
+-                         size_t count, loff_t *ppos)
+-{
+-      int left = initrd_end - initrd_start - *ppos;
+-
+-      if (count > left)
+-              count = left;
+-      if (count == 0)
+-              return 0;
+-      if (copy_to_user(buf, (char *)initrd_start + *ppos, count))
+-              return -EFAULT;
+-
+-      *ppos += count;
+-      return count;
+-}
+-
+-static int initrd_release(struct inode *inode,struct file *file)
+-{
+-
+-      blkdev_put(inode->i_bdev, BDEV_FILE);
+-
+-      spin_lock(&initrd_users_lock);
+-      if (!--initrd_users) {
+-              spin_unlock(&initrd_users_lock);
+-              del_gendisk(initrd_disk);
+-              free_initrd_mem(initrd_start, initrd_end);
+-              initrd_start = 0;
+-      } else
+-              spin_unlock(&initrd_users_lock);
+-
+-      return 0;
+-}
+-
+-static struct file_operations initrd_fops = {
+-      .read =         initrd_read,
+-      .release =      initrd_release,
+-};
+-
+-static int initrd_open(struct inode *inode, struct file *filp)
+-{
+-      if (!initrd_start) 
+-              return -ENODEV;
+-
+-      spin_lock(&initrd_users_lock);
+-      initrd_users++;
+-      spin_unlock(&initrd_users_lock);
+-
+-      filp->f_op = &initrd_fops;
+-      return 0;
+-}
+-
+-static struct block_device_operations initrd_bdops = {
+-      .owner =        THIS_MODULE,
+-      .open =         initrd_open,
+-};
+-
+-static int __init initrd_init(void)
+-{
+-      initrd_disk = alloc_disk(1);
+-      if (!initrd_disk)
+-              return -ENOMEM;
+-
+-      initrd_disk->major = RAMDISK_MAJOR;
+-      initrd_disk->first_minor = INITRD_MINOR;
+-      initrd_disk->fops = &initrd_bdops;      
+-
+-      sprintf(initrd_disk->disk_name, "initrd");
+-      sprintf(initrd_disk->devfs_name, "rd/initrd");
+-
+-      set_capacity(initrd_disk, (initrd_end-initrd_start+511) >> 9);
+-      add_disk(initrd_disk);
+-      return 0;
+-}
+-
+-static void __exit initrd_exit(void)
+-{
+-      put_disk(initrd_disk);
+-}
+-
+-module_init(initrd_init);
+-module_exit(initrd_exit);
+--- linux-2.6.0-test6/drivers/block/ioctl.c    2003-09-08 13:58:56.000000000 -0700
++++ 25/drivers/block/ioctl.c   2003-10-05 00:34:11.000000000 -0700
+@@ -132,10 +132,9 @@ static int put_u64(unsigned long arg, u6
+       return put_user(val, (u64 *)arg);
+ }
+-int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd,
++int blkdev_ioctl(struct block_device *bdev, struct file *file, unsigned cmd,
+                       unsigned long arg)
+ {
+-      struct block_device *bdev = inode->i_bdev;
+       struct gendisk *disk = bdev->bd_disk;
+       struct backing_dev_info *bdi;
+       int holder;
+@@ -194,7 +193,7 @@ int blkdev_ioctl(struct inode *inode, st
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EACCES;
+               if (disk->fops->ioctl) {
+-                      ret = disk->fops->ioctl(inode, file, cmd, arg);
++                      ret = disk->fops->ioctl(bdev, file, cmd, arg);
+                       if (ret != -EINVAL)
+                               return ret;
+               }
+@@ -203,7 +202,7 @@ int blkdev_ioctl(struct inode *inode, st
+               return 0;
+       case BLKROSET:
+               if (disk->fops->ioctl) {
+-                      ret = disk->fops->ioctl(inode, file, cmd, arg);
++                      ret = disk->fops->ioctl(bdev, file, cmd, arg);
+                       if (ret != -EINVAL)
+                               return ret;
+               }
+@@ -215,7 +214,7 @@ int blkdev_ioctl(struct inode *inode, st
+               return 0;
+       default:
+               if (disk->fops->ioctl)
+-                      return disk->fops->ioctl(inode, file, cmd, arg);
++                      return disk->fops->ioctl(bdev, file, cmd, arg);
+       }
+       return -ENOTTY;
+ }
+--- linux-2.6.0-test6/drivers/block/Kconfig    2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/block/Kconfig   2003-10-05 00:33:24.000000000 -0700
+@@ -6,7 +6,7 @@ menu "Block devices"
+ config BLK_DEV_FD
+       tristate "Normal floppy disk support"
+-      depends on !X86_PC9800 && !ARCH_S390
++      depends on ISA || M68 || SPARC64
+       ---help---
+         If you want to use the floppy disk drive(s) of your PC under Linux,
+         say Y. Information about this driver, especially important for IBM
+@@ -35,7 +35,7 @@ config BLK_DEV_FD98
+ config BLK_DEV_SWIM_IOP
+       bool "Macintosh IIfx/Quadra 900/Quadra 950 floppy support (EXPERIMENTAL)"
+-      depends on MAC && EXPERIMENTAL
++      depends on MAC && EXPERIMENTAL && BROKEN
+       help
+         Say Y here to support the SWIM (Super Woz Integrated Machine) IOP
+         floppy controller on the Macintosh IIfx and Quadra 900/950.
+@@ -63,7 +63,7 @@ config AMIGA_Z2RAM
+ config ATARI_ACSI
+       tristate "Atari ACSI support"
+-      depends on ATARI
++      depends on ATARI && BROKEN
+       ---help---
+         This enables support for the Atari ACSI interface. The driver
+         supports hard disks and CD-ROMs, which have 512-byte sectors, or can
+--- linux-2.6.0-test6/drivers/block/Kconfig.iosched    2003-08-22 19:23:40.000000000 -0700
++++ 25/drivers/block/Kconfig.iosched   2003-10-05 00:34:17.000000000 -0700
+@@ -27,3 +27,10 @@ config IOSCHED_DEADLINE
+         a disk at any one time, its behaviour is almost identical to the
+         anticipatory I/O scheduler and so is a good choice.
++config IOSCHED_CFQ
++      bool "CFQ I/O scheduler" if EMBEDDED
++      default y
++      ---help---
++        The CFQ I/O scheduler tries to distribute bandwidth equally
++        among all processes in the system. It should provide a fair
++        working environment, suitable for desktop systems.
+--- linux-2.6.0-test6/drivers/block/ll_rw_blk.c        2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/block/ll_rw_blk.c       2003-10-05 00:36:58.000000000 -0700
+@@ -119,7 +119,7 @@ static void set_queue_congested(request_
+ /**
+  * blk_get_backing_dev_info - get the address of a queue's backing_dev_info
+- * @dev:      device
++ * @bdev:     device
+  *
+  * Locates the passed device's request queue and returns the address of its
+  * backing_dev_info
+@@ -414,8 +414,8 @@ void blk_queue_segment_boundary(request_
+ /**
+  * blk_queue_dma_alignment - set dma length and memory alignment
+- * @q:  the request queue for the device
+- * @dma_mask:  alignment mask
++ * @q:     the request queue for the device
++ * @mask:  alignment mask
+  *
+  * description:
+  *    set required memory and length aligment for direct dma transactions.
+@@ -1152,7 +1152,7 @@ void blk_stop_queue(request_queue_t *q)
+ /**
+  * blk_run_queue - run a single device queue
+- * @q The queue to run
++ * @q:        The queue to run
+  */
+ void blk_run_queue(struct request_queue *q)
+ {
+@@ -1257,6 +1257,8 @@ static elevator_t *chosen_elevator =
+       &iosched_as;
+ #elif defined(CONFIG_IOSCHED_DEADLINE)
+       &iosched_deadline;
++#elif defined(CONFIG_IOSCHED_CFQ)
++      &iosched_cfq;
+ #elif defined(CONFIG_IOSCHED_NOOP)
+       &elevator_noop;
+ #else
+@@ -1275,6 +1277,10 @@ static int __init elevator_setup(char *s
+       if (!strcmp(str, "as"))
+               chosen_elevator = &iosched_as;
+ #endif
++#ifdef CONFIG_IOSCHED_CFQ
++      if (!strcmp(str, "cfq"))
++              chosen_elevator = &iosched_cfq;
++#endif
+ #ifdef CONFIG_IOSCHED_NOOP
+       if (!strcmp(str, "noop"))
+               chosen_elevator = &elevator_noop;
+@@ -1459,6 +1465,8 @@ static void freed_request(request_queue_
+       }
+ }
++atomic_t global_nr_requests = ATOMIC_INIT(0);
++
+ #define blkdev_free_rq(list) list_entry((list)->next, struct request, queuelist)
+ /*
+  * Get a free request, queue_lock must not be held
+@@ -1536,6 +1544,8 @@ static struct request *get_request(reque
+       rq->data = NULL;
+       rq->sense = NULL;
++      atomic_inc(&global_nr_requests);
++
+ out:
+       put_io_context(ioc);
+       return rq;
+@@ -1766,6 +1776,9 @@ void __blk_put_request(request_queue_t *
+               blk_free_request(q, req);
+               freed_request(q, rw);
++
++              WARN_ON(atomic_read(&global_nr_requests) == 0);
++              atomic_dec(&global_nr_requests);
+       }
+ }
+@@ -1787,25 +1800,50 @@ void blk_put_request(struct request *req
+ }
+ /**
+- * blk_congestion_wait - wait for a queue to become uncongested
++ * blk_congestion_wait_wq - wait for a queue to become uncongested,
+  * @rw: READ or WRITE
+  * @timeout: timeout in jiffies
++ * @wait : wait queue entry to use for waiting or async notification
++ * (NULL defaults to synchronous behaviour)
+  *
+  * Waits for up to @timeout jiffies for a queue (any queue) to exit congestion.
+  * If no queues are congested then just wait for the next request to be
+  * returned.
++ *
++ * If the wait queue parameter specifies an async i/o callback,
++ * then instead of blocking, just register the callback on the wait
++ * queue for async notification when the queue gets uncongested.
+  */
+-void blk_congestion_wait(int rw, long timeout)
++int blk_congestion_wait_wq(int rw, long timeout, wait_queue_t *wait)
+ {
+-      DEFINE_WAIT(wait);
+       wait_queue_head_t *wqh = &congestion_wqh[rw];
++      DEFINE_WAIT(local_wait);
++
++      if (!wait)
++              wait = &local_wait;
+       blk_run_queues();
+-      prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE);
++      prepare_to_wait(wqh, wait, TASK_UNINTERRUPTIBLE);
++      if (!is_sync_wait(wait)) {
++              /*
++               * if we've queued an async wait queue
++               * callback do not block; just tell the
++               * caller to return and retry later when
++               * the callback is notified
++               */
++              return -EIOCBRETRY;
++      }
+       io_schedule_timeout(timeout);
+-      finish_wait(wqh, &wait);
++      finish_wait(wqh, wait);
++      return 0;
+ }
++void blk_congestion_wait(int rw, long timeout)
++{
++      blk_congestion_wait_wq(rw, timeout, NULL);
++}
++
++
+ /*
+  * Has to be called with the request spinlock acquired
+  */
+@@ -2592,6 +2630,7 @@ void put_io_context(struct io_context *i
+               if (ioc->aic && ioc->aic->dtor)
+                       ioc->aic->dtor(ioc->aic);
+               kfree(ioc);
++              WARN_ON(atomic_read(&nr_io_contexts) == 0);
+               atomic_dec(&nr_io_contexts);
+       }
+ }
+@@ -2634,6 +2673,9 @@ struct io_context *get_io_context(int gf
+               ret = kmalloc(sizeof(*ret), GFP_ATOMIC);
+               if (ret) {
+                       atomic_inc(&nr_io_contexts);
++                      WARN_ON(atomic_read(&nr_io_contexts) ==
++                              1 + nr_threads + atomic_read(&global_nr_requests));
++
+                       atomic_set(&ret->refcount, 1);
+                       ret->pid = tsk->pid;
+                       ret->last_waited = jiffies; /* doesn't matter... */
+--- linux-2.6.0-test6/drivers/block/loop.c     2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/block/loop.c    2003-10-05 00:34:11.000000000 -0700
+@@ -140,8 +140,7 @@ figure_loop_size(struct loop_device *lo)
+       sector_t x;
+       /* Compute loopsize in bytes */
+-      size = i_size_read(lo->lo_backing_file->f_dentry->
+-                              d_inode->i_mapping->host);
++      size = i_size_read(lo->lo_backing_file->f_mapping->host);
+       offset = lo->lo_offset;
+       loopsize = size - offset;
+       if (lo->lo_sizelimit > 0 && lo->lo_sizelimit < loopsize)
+@@ -175,7 +174,7 @@ static int
+ do_lo_send(struct loop_device *lo, struct bio_vec *bvec, int bsize, loff_t pos)
+ {
+       struct file *file = lo->lo_backing_file; /* kudos to NFsckingS */
+-      struct address_space *mapping = file->f_dentry->d_inode->i_mapping;
++      struct address_space *mapping = file->f_mapping;
+       struct address_space_operations *aops = mapping->a_ops;
+       struct page *page;
+       char *kaddr, *data;
+@@ -660,6 +659,7 @@ static int loop_set_fd(struct loop_devic
+       struct file     *file;
+       struct inode    *inode;
+       struct block_device *lo_device = NULL;
++      struct address_space *mapping;
+       unsigned lo_blocksize;
+       int             lo_flags = 0;
+       int             error;
+@@ -676,14 +676,16 @@ static int loop_set_fd(struct loop_devic
+       if (!file)
+               goto out;
+-      error = -EINVAL;
+-      inode = file->f_dentry->d_inode;
++      mapping = file->f_mapping;
++      inode = mapping->host;
+       if (!(file->f_mode & FMODE_WRITE))
+               lo_flags |= LO_FLAGS_READ_ONLY;
++      error = -EINVAL;
++
+       if (S_ISBLK(inode->i_mode)) {
+-              lo_device = inode->i_bdev;
++              lo_device = I_BDEV(inode);
+               if (lo_device == bdev) {
+                       error = -EBUSY;
+                       goto out;
+@@ -692,7 +694,7 @@ static int loop_set_fd(struct loop_devic
+               if (bdev_read_only(lo_device))
+                       lo_flags |= LO_FLAGS_READ_ONLY;
+       } else if (S_ISREG(inode->i_mode)) {
+-              struct address_space_operations *aops = inode->i_mapping->a_ops;
++              struct address_space_operations *aops = mapping->a_ops;
+               /*
+                * If we can't read - sorry. If we only can't write - well,
+                * it's going to be read-only.
+@@ -728,9 +730,8 @@ static int loop_set_fd(struct loop_devic
+               fput(file);
+               goto out_putf;
+       }
+-      lo->old_gfp_mask = mapping_gfp_mask(inode->i_mapping);
+-      mapping_set_gfp_mask(inode->i_mapping,
+-                           lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS));
++      lo->old_gfp_mask = mapping_gfp_mask(mapping);
++      mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS));
+       set_blocksize(bdev, lo_blocksize);
+@@ -846,7 +847,7 @@ static int loop_clr_fd(struct loop_devic
+       memset(lo->lo_file_name, 0, LO_NAME_SIZE);
+       invalidate_bdev(bdev, 0);
+       set_capacity(disks[lo->lo_number], 0);
+-      mapping_set_gfp_mask(filp->f_dentry->d_inode->i_mapping, gfp);
++      mapping_set_gfp_mask(filp->f_mapping, gfp);
+       lo->lo_state = Lo_unbound;
+       fput(filp);
+       /* This is safe: open() is still holding a reference. */
+@@ -1056,19 +1057,19 @@ loop_get_status64(struct loop_device *lo
+       return err;
+ }
+-static int lo_ioctl(struct inode * inode, struct file * file,
++static int lo_ioctl(struct block_device *bdev, struct file *file,
+       unsigned int cmd, unsigned long arg)
+ {
+-      struct loop_device *lo = inode->i_bdev->bd_disk->private_data;
++      struct loop_device *lo = bdev->bd_disk->private_data;
+       int err;
+       down(&lo->lo_ctl_mutex);
+       switch (cmd) {
+       case LOOP_SET_FD:
+-              err = loop_set_fd(lo, file, inode->i_bdev, arg);
++              err = loop_set_fd(lo, file, bdev, arg);
+               break;
+       case LOOP_CLR_FD:
+-              err = loop_clr_fd(lo, inode->i_bdev);
++              err = loop_clr_fd(lo, bdev);
+               break;
+       case LOOP_SET_STATUS:
+               err = loop_set_status_old(lo, (struct loop_info *) arg);
+@@ -1089,9 +1090,9 @@ static int lo_ioctl(struct inode * inode
+       return err;
+ }
+-static int lo_open(struct inode *inode, struct file *file)
++static int lo_open(struct block_device *bdev, struct file *file)
+ {
+-      struct loop_device *lo = inode->i_bdev->bd_disk->private_data;
++      struct loop_device *lo = bdev->bd_disk->private_data;
+       down(&lo->lo_ctl_mutex);
+       lo->lo_refcnt++;
+@@ -1100,9 +1101,9 @@ static int lo_open(struct inode *inode, 
+       return 0;
+ }
+-static int lo_release(struct inode *inode, struct file *file)
++static int lo_release(struct gendisk *disk)
+ {
+-      struct loop_device *lo = inode->i_bdev->bd_disk->private_data;
++      struct loop_device *lo = disk->private_data;
+       down(&lo->lo_ctl_mutex);
+       --lo->lo_refcnt;
+--- linux-2.6.0-test6/drivers/block/Makefile   2003-08-22 19:23:40.000000000 -0700
++++ 25/drivers/block/Makefile  2003-10-05 00:34:17.000000000 -0700
+@@ -18,6 +18,7 @@ obj-y        := elevator.o ll_rw_blk.o ioctl.o 
+ obj-$(CONFIG_IOSCHED_NOOP)    += noop-iosched.o
+ obj-$(CONFIG_IOSCHED_AS)      += as-iosched.o
+ obj-$(CONFIG_IOSCHED_DEADLINE)        += deadline-iosched.o
++obj-$(CONFIG_IOSCHED_CFQ)     += cfq-iosched.o
+ obj-$(CONFIG_MAC_FLOPPY)      += swim3.o
+ obj-$(CONFIG_BLK_DEV_FD)      += floppy.o
+ obj-$(CONFIG_BLK_DEV_FD98)    += floppy98.o
+@@ -28,7 +29,6 @@ obj-$(CONFIG_ATARI_ACSI)     += acsi.o
+ obj-$(CONFIG_ATARI_SLM)               += acsi_slm.o
+ obj-$(CONFIG_AMIGA_Z2RAM)     += z2ram.o
+ obj-$(CONFIG_BLK_DEV_RAM)     += rd.o
+-obj-$(CONFIG_BLK_DEV_INITRD)  += initrd.o
+ obj-$(CONFIG_BLK_DEV_LOOP)    += loop.o
+ obj-$(CONFIG_BLK_DEV_PS2)     += ps2esdi.o
+ obj-$(CONFIG_BLK_DEV_XD)      += xd.o
+--- linux-2.6.0-test6/drivers/block/nbd.c      2003-08-22 19:23:40.000000000 -0700
++++ 25/drivers/block/nbd.c     2003-10-05 00:33:54.000000000 -0700
+@@ -535,10 +535,10 @@ static void do_nbd_request(request_queue
+       return;
+ }
+-static int nbd_ioctl(struct inode *inode, struct file *file,
++static int nbd_ioctl(struct block_device *bdev, struct file *file,
+                    unsigned int cmd, unsigned long arg)
+ {
+-      struct nbd_device *lo = inode->i_bdev->bd_disk->private_data;
++      struct nbd_device *lo = bdev->bd_disk->private_data;
+       int error;
+       struct request sreq ;
+@@ -593,7 +593,7 @@ static int nbd_ioctl(struct inode *inode
+               error = -EINVAL;
+               file = fget(arg);
+               if (file) {
+-                      inode = file->f_dentry->d_inode;
++                      struct inode *inode = file->f_dentry->d_inode;
+                       if (inode->i_sock) {
+                               lo->file = file;
+                               lo->sock = SOCKET_I(inode);
+@@ -606,20 +606,20 @@ static int nbd_ioctl(struct inode *inode
+       case NBD_SET_BLKSIZE:
+               lo->blksize = arg;
+               lo->bytesize &= ~(lo->blksize-1);
+-              inode->i_bdev->bd_inode->i_size = lo->bytesize;
+-              set_blocksize(inode->i_bdev, lo->blksize);
++              bdev->bd_inode->i_size = lo->bytesize;
++              set_blocksize(bdev, lo->blksize);
+               set_capacity(lo->disk, lo->bytesize >> 9);
+               return 0;
+       case NBD_SET_SIZE:
+               lo->bytesize = arg & ~(lo->blksize-1);
+-              inode->i_bdev->bd_inode->i_size = lo->bytesize;
+-              set_blocksize(inode->i_bdev, lo->blksize);
++              bdev->bd_inode->i_size = lo->bytesize;
++              set_blocksize(bdev, lo->blksize);
+               set_capacity(lo->disk, lo->bytesize >> 9);
+               return 0;
+       case NBD_SET_SIZE_BLOCKS:
+               lo->bytesize = ((u64) arg) * lo->blksize;
+-              inode->i_bdev->bd_inode->i_size = lo->bytesize;
+-              set_blocksize(inode->i_bdev, lo->blksize);
++              bdev->bd_inode->i_size = lo->bytesize;
++              set_blocksize(bdev, lo->blksize);
+               set_capacity(lo->disk, lo->bytesize >> 9);
+               return 0;
+       case NBD_DO_IT:
+@@ -664,11 +664,11 @@ static int nbd_ioctl(struct inode *inode
+       case NBD_PRINT_DEBUG:
+ #ifdef PARANOIA
+               printk(KERN_INFO "%s: next = %p, prev = %p. Global: in %d, out %d\n",
+-                      inode->i_bdev->bd_disk->disk_name, lo->queue_head.next,
++                      bdev->bd_disk->disk_name, lo->queue_head.next,
+                       lo->queue_head.prev, requests_in, requests_out);
+ #else
+               printk(KERN_INFO "%s: next = %p, prev = %p\n",
+-                      inode->i_bdev->bd_disk->disk_name,
++                      bdev->bd_disk->disk_name,
+                       lo->queue_head.next, lo->queue_head.prev);
+ #endif
+               return 0;
+--- linux-2.6.0-test6/drivers/block/paride/pcd.c       2003-08-08 22:55:11.000000000 -0700
++++ 25/drivers/block/paride/pcd.c      2003-10-05 00:34:01.000000000 -0700
+@@ -243,23 +243,23 @@ static int pcd_warned;           /* Have we logge
+ /* kernel glue structures */
+-static int pcd_block_open(struct inode *inode, struct file *file)
++static int pcd_block_open(struct block_device *bdev, struct file *file)
+ {
+-      struct pcd_unit *cd = inode->i_bdev->bd_disk->private_data;
+-      return cdrom_open(&cd->info, inode, file);
++      struct pcd_unit *cd = bdev->bd_disk->private_data;
++      return cdrom_open(&cd->info, bdev, file);
+ }
+-static int pcd_block_release(struct inode *inode, struct file *file)
++static int pcd_block_release(struct gendisk *disk)
+ {
+-      struct pcd_unit *cd = inode->i_bdev->bd_disk->private_data;
+-      return cdrom_release(&cd->info, file);
++      struct pcd_unit *cd = disk->private_data;
++      return cdrom_release(&cd->info);
+ }
+-static int pcd_block_ioctl(struct inode *inode, struct file *file,
++static int pcd_block_ioctl(struct block_device *bdev, struct file *file,
+                               unsigned cmd, unsigned long arg)
+ {
+-      struct pcd_unit *cd = inode->i_bdev->bd_disk->private_data;
+-      return cdrom_ioctl(&cd->info, inode, cmd, arg);
++      struct pcd_unit *cd = bdev->bd_disk->private_data;
++      return cdrom_ioctl(&cd->info, bdev, cmd, arg);
+ }
+ static int pcd_block_media_changed(struct gendisk *disk)
+--- linux-2.6.0-test6/drivers/block/paride/pd.c        2003-09-08 13:58:56.000000000 -0700
++++ 25/drivers/block/paride/pd.c       2003-10-05 00:34:01.000000000 -0700
+@@ -236,11 +236,11 @@ MODULE_PARM(drive3, "1-8i");
+ #define IDE_EJECT             0xed
+ void pd_setup(char *str, int *ints);
+-static int pd_open(struct inode *inode, struct file *file);
++static int pd_open(struct block_device *bdev, struct file *file);
+ static void do_pd_request(request_queue_t * q);
+-static int pd_ioctl(struct inode *inode, struct file *file,
++static int pd_ioctl(struct block_device *bdev, struct file *file,
+                   unsigned int cmd, unsigned long arg);
+-static int pd_release(struct inode *inode, struct file *file);
++static int pd_release(struct gendisk *disk);
+ static int pd_revalidate(struct gendisk *p);
+ static int pd_detect(void);
+ static void do_pd_read(void);
+@@ -304,8 +304,6 @@ static char *pd_errs[17] = { "ERR", "IND
+ /* kernel glue structures */
+-extern struct block_device_operations pd_fops;
+-
+ static struct block_device_operations pd_fops = {
+       .owner          = THIS_MODULE,
+       .open           = pd_open,
+@@ -337,9 +335,9 @@ static void pd_init_units(void)
+       }
+ }
+-static int pd_open(struct inode *inode, struct file *file)
++static int pd_open(struct block_device *bdev, struct file *file)
+ {
+-      struct pd_unit *disk = inode->i_bdev->bd_disk->private_data;
++      struct pd_unit *disk = bdev->bd_disk->private_data;
+       disk->access++;
+@@ -350,10 +348,10 @@ static int pd_open(struct inode *inode, 
+       return 0;
+ }
+-static int pd_ioctl(struct inode *inode, struct file *file,
++static int pd_ioctl(struct block_device *bdev, struct file *file,
+        unsigned int cmd, unsigned long arg)
+ {
+-      struct pd_unit *disk = inode->i_bdev->bd_disk->private_data;
++      struct pd_unit *disk = bdev->bd_disk->private_data;
+       struct hd_geometry *geo = (struct hd_geometry *) arg;
+       struct hd_geometry g;
+@@ -372,7 +370,7 @@ static int pd_ioctl(struct inode *inode,
+                       g.sectors = disk->sectors;
+                       g.cylinders = disk->cylinders;
+               }
+-              g.start = get_start_sect(inode->i_bdev);
++              g.start = get_start_sect(bdev);
+               if (copy_to_user(geo, &g, sizeof(struct hd_geometry)))
+                       return -EFAULT;
+               return 0;
+@@ -381,9 +379,9 @@ static int pd_ioctl(struct inode *inode,
+       }
+ }
+-static int pd_release(struct inode *inode, struct file *file)
++static int pd_release(struct gendisk *p)
+ {
+-      struct pd_unit *disk = inode->i_bdev->bd_disk->private_data;
++      struct pd_unit *disk = p->private_data;
+       if (!--disk->access && disk->removable)
+               pd_doorlock(disk, IDE_DOORUNLOCK);
+--- linux-2.6.0-test6/drivers/block/paride/pf.c        2003-08-08 22:55:11.000000000 -0700
++++ 25/drivers/block/paride/pf.c       2003-10-05 00:34:01.000000000 -0700
+@@ -222,12 +222,12 @@ MODULE_PARM(drive3, "1-7i");
+ #define ATAPI_READ_10         0x28
+ #define ATAPI_WRITE_10                0x2a
+-static int pf_open(struct inode *inode, struct file *file);
++static int pf_open(struct block_device *bdev, struct file *file);
+ static void do_pf_request(request_queue_t * q);
+-static int pf_ioctl(struct inode *inode, struct file *file,
++static int pf_ioctl(struct block_device *bdev, struct file *file,
+                   unsigned int cmd, unsigned long arg);
+-static int pf_release(struct inode *inode, struct file *file);
++static int pf_release(struct gendisk *disk);
+ static int pf_detect(void);
+ static void do_pf_read(void);
+@@ -315,9 +315,9 @@ void pf_init_units(void)
+       }
+ }
+-static int pf_open(struct inode *inode, struct file *file)
++static int pf_open(struct block_device *bdev, struct file *file)
+ {
+-      struct pf_unit *pf = inode->i_bdev->bd_disk->private_data;
++      struct pf_unit *pf = bdev->bd_disk->private_data;
+       pf_identify(pf);
+@@ -334,9 +334,9 @@ static int pf_open(struct inode *inode, 
+       return 0;
+ }
+-static int pf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
++static int pf_ioctl(struct block_device *bdev, struct file *file, unsigned int cmd, unsigned long arg)
+ {
+-      struct pf_unit *pf = inode->i_bdev->bd_disk->private_data;
++      struct pf_unit *pf = bdev->bd_disk->private_data;
+       struct hd_geometry *geo = (struct hd_geometry *) arg;
+       struct hd_geometry g;
+       sector_t capacity;
+@@ -365,9 +365,9 @@ static int pf_ioctl(struct inode *inode,
+       return 0;
+ }
+-static int pf_release(struct inode *inode, struct file *file)
++static int pf_release(struct gendisk *disk)
+ {
+-      struct pf_unit *pf = inode->i_bdev->bd_disk->private_data;
++      struct pf_unit *pf = disk->private_data;
+       if (pf->access <= 0)
+               return -EINVAL;
+--- linux-2.6.0-test6/drivers/block/ps2esdi.c  2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/block/ps2esdi.c 2003-10-05 00:33:54.000000000 -0700
+@@ -39,7 +39,7 @@
+ #include <linux/genhd.h>
+ #include <linux/ps2esdi.h>
+ #include <linux/blkdev.h>
+-#include <linux/mca.h>
++#include <linux/mca-legacy.h>
+ #include <linux/init.h>
+ #include <linux/ioport.h>
+ #include <linux/module.h>
+@@ -81,7 +81,7 @@ static void (*current_int_handler) (u_in
+ static void ps2esdi_normal_interrupt_handler(u_int);
+ static void ps2esdi_initial_reset_int_handler(u_int);
+ static void ps2esdi_geometry_int_handler(u_int);
+-static int ps2esdi_ioctl(struct inode *inode, struct file *file,
++static int ps2esdi_ioctl(struct block_device *bdev, struct file *file,
+                        u_int cmd, u_long arg);
+ static int ps2esdi_read_status_words(int num_words, int max_words, u_short * buffer);
+@@ -1059,10 +1059,10 @@ static void dump_cmd_complete_status(u_i
+ }
+-static int ps2esdi_ioctl(struct inode *inode,
++static int ps2esdi_ioctl(struct block_device *bdev,
+                        struct file *file, u_int cmd, u_long arg)
+ {
+-      struct ps2esdi_i_struct *p = inode->i_bdev->bd_disk->private_data;
++      struct ps2esdi_i_struct *p = bdev->bd_disk->private_data;
+       struct ps2esdi_geometry *geometry = (struct ps2esdi_geometry *) arg;
+       int err;
+@@ -1073,7 +1073,7 @@ static int ps2esdi_ioctl(struct inode *i
+       put_user(p->head, (char *) &geometry->heads);
+       put_user(p->sect, (char *) &geometry->sectors);
+       put_user(p->cyl, (short *) &geometry->cylinders);
+-      put_user(get_start_sect(inode->i_bdev), (long *) &geometry->start);
++      put_user(get_start_sect(bdev), (long *) &geometry->start);
+       return 0;
+ }
+--- linux-2.6.0-test6/drivers/block/rd.c       2003-09-08 13:58:56.000000000 -0700
++++ 25/drivers/block/rd.c      2003-10-05 00:34:30.000000000 -0700
+@@ -1,15 +1,15 @@
+ /*
+  * ramdisk.c - Multiple RAM disk driver - gzip-loading version - v. 0.8 beta.
+- * 
+- * (C) Chad Page, Theodore Ts'o, et. al, 1995. 
++ *
++ * (C) Chad Page, Theodore Ts'o, et. al, 1995.
+  *
+  * This RAM disk is designed to have filesystems created on it and mounted
+- * just like a regular floppy disk.  
+- *  
++ * just like a regular floppy disk.
++ *
+  * It also does something suggested by Linus: use the buffer cache as the
+  * RAM disk data.  This makes it possible to dynamically allocate the RAM disk
+- * buffer - with some consequences I have to deal with as I write this. 
+- * 
++ * buffer - with some consequences I have to deal with as I write this.
++ *
+  * This code is based on the original ramdisk.c, written mostly by
+  * Theodore Ts'o (TYT) in 1991.  The code was largely rewritten by
+  * Chad Page to use the buffer cache to store the RAM disk data in
+@@ -33,7 +33,7 @@
+  *
+  *  Added initrd: Werner Almesberger & Hans Lermen, Feb '96
+  *
+- * 4/25/96 : Made RAM disk size a parameter (default is now 4 MB) 
++ * 4/25/96 : Made RAM disk size a parameter (default is now 4 MB)
+  *            - Chad Page
+  *
+  * Add support for fs images split across >1 disk, Paul Gortmaker, Mar '98
+@@ -60,7 +60,7 @@
+ #include <asm/uaccess.h>
+ /* The RAM disk size is now a parameter */
+-#define NUM_RAMDISKS 16               /* This cannot be overridden (yet) */ 
++#define NUM_RAMDISKS 16               /* This cannot be overridden (yet) */
+ /* Various static variables go here.  Most are used only in the RAM disk code.
+  */
+@@ -73,7 +73,7 @@ static struct request_queue *rd_queue[NU
+  * Parameters for the boot-loading of the RAM disk.  These are set by
+  * init/main.c (from arguments to the kernel command line) or from the
+  * architecture-specific setup routine (from the stored boot sector
+- * information). 
++ * information).
+  */
+ int rd_size = CONFIG_BLK_DEV_RAM_SIZE;                /* Size of the RAM disks */
+ /*
+@@ -94,7 +94,7 @@ int rd_blocksize = BLOCK_SIZE;                       /* bloc
+  *               2000 Transmeta Corp.
+  * aops copied from ramfs.
+  */
+-static int ramdisk_readpage(struct file *file, struct page * page)
++static int ramdisk_readpage(struct file *file, struct page *page)
+ {
+       if (!PageUptodate(page)) {
+               void *kaddr = kmap_atomic(page, KM_USER0);
+@@ -108,7 +108,8 @@ static int ramdisk_readpage(struct file 
+       return 0;
+ }
+-static int ramdisk_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to)
++static int ramdisk_prepare_write(struct file *file, struct page *page,
++                              unsigned offset, unsigned to)
+ {
+       if (!PageUptodate(page)) {
+               void *kaddr = kmap_atomic(page, KM_USER0);
+@@ -122,7 +123,8 @@ static int ramdisk_prepare_write(struct 
+       return 0;
+ }
+-static int ramdisk_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to)
++static int ramdisk_commit_write(struct file *file, struct page *page,
++                              unsigned offset, unsigned to)
+ {
+       return 0;
+ }
+@@ -212,7 +214,7 @@ static int rd_blkdev_pagecache_IO(int rw
+  * 19-JAN-1998  Richard Gooch <rgooch@atnf.csiro.au>  Added devfs support
+  *
+  */
+-static int rd_make_request(request_queue_t * q, struct bio *bio)
++static int rd_make_request(request_queue_t *q, struct bio *bio)
+ {
+       struct block_device *bdev = bio->bi_bdev;
+       struct address_space * mapping = bdev->bd_inode->i_mapping;
+@@ -242,17 +244,19 @@ fail:
+       return 0;
+ } 
+-static int rd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
++static int rd_ioctl(struct block_device *bdev, struct file *file,
++                      unsigned int cmd, unsigned long arg)
+ {
+       int error;
+-      struct block_device *bdev = inode->i_bdev;
+       if (cmd != BLKFLSBUF)
+               return -EINVAL;
+-      /* special: we want to release the ramdisk memory,
+-         it's not like with the other blockdevices where
+-         this ioctl only flushes away the buffer cache. */
++      /*
++       * special: we want to release the ramdisk memory, it's not like with
++       * the other blockdevices where this ioctl only flushes away the buffer
++       * cache
++       */
+       error = -EBUSY;
+       down(&bdev->bd_sem);
+       if (bdev->bd_openers <= 2) {
+@@ -268,16 +272,15 @@ static struct backing_dev_info rd_backin
+       .memory_backed  = 1,    /* Does not contribute to dirty memory */
+ };
+-static int rd_open(struct inode * inode, struct file * filp)
++static int rd_open(struct block_device *bdev, struct file *filp)
+ {
+-      unsigned unit = iminor(inode);
++      unsigned unit = MINOR(bdev->bd_dev);
+       /*
+        * Immunize device against invalidate_buffers() and prune_icache().
+        */
+       if (rd_bdev[unit] == NULL) {
+-              struct block_device *bdev = inode->i_bdev;
+-              inode = igrab(bdev->bd_inode);
++              struct inode *inode = igrab(bdev->bd_inode);
+               rd_bdev[unit] = bdev;
+               bdev->bd_openers++;
+               bdev->bd_block_size = rd_blocksize;
+@@ -295,12 +298,14 @@ static struct block_device_operations rd
+       .ioctl =        rd_ioctl,
+ };
+-/* Before freeing the module, invalidate all of the protected buffers! */
+-static void __exit rd_cleanup (void)
++/*
++ * Before freeing the module, invalidate all of the protected buffers!
++ */
++static void __exit rd_cleanup(void)
+ {
+       int i;
+-      for (i = 0 ; i < NUM_RAMDISKS; i++) {
++      for (i = 0; i < NUM_RAMDISKS; i++) {
+               struct block_device *bdev = rd_bdev[i];
+               rd_bdev[i] = NULL;
+               if (bdev) {
+@@ -311,17 +316,19 @@ static void __exit rd_cleanup (void)
+               put_disk(rd_disks[i]);
+       }
+       devfs_remove("rd");
+-      unregister_blkdev(RAMDISK_MAJOR, "ramdisk" );
++      unregister_blkdev(RAMDISK_MAJOR, "ramdisk");
+ }
+-/* This is the registration and initialization section of the RAM disk driver */
+-static int __init rd_init (void)
++/*
++ * This is the registration and initialization section of the RAM disk driver
++ */
++static int __init rd_init(void)
+ {
+       int i;
+       int err = -ENOMEM;
+       if (rd_blocksize > PAGE_SIZE || rd_blocksize < 512 ||
+-          (rd_blocksize & (rd_blocksize-1))) {
++                      (rd_blocksize & (rd_blocksize-1))) {
+               printk("RAMDISK: wrong blocksize %d, reverting to defaults\n",
+                      rd_blocksize);
+               rd_blocksize = BLOCK_SIZE;
+@@ -362,8 +369,8 @@ static int __init rd_init (void)
+       /* rd_size is given in kB */
+       printk("RAMDISK driver initialized: "
+-             "%d RAM disks of %dK size %d blocksize\n",
+-             NUM_RAMDISKS, rd_size, rd_blocksize);
++              "%d RAM disks of %dK size %d blocksize\n",
++              NUM_RAMDISKS, rd_size, rd_blocksize);
+       return 0;
+ out_queue:
+--- linux-2.6.0-test6/drivers/block/scsi_ioctl.c       2003-09-08 13:58:56.000000000 -0700
++++ 25/drivers/block/scsi_ioctl.c      2003-10-05 00:36:48.000000000 -0700
+@@ -25,6 +25,7 @@
+ #include <linux/cdrom.h>
+ #include <linux/slab.h>
+ #include <linux/bio.h>
++#include <linux/times.h>
+ #include <asm/uaccess.h>
+ #include <scsi/scsi.h>
+@@ -140,40 +141,36 @@ static int sg_emulated_host(request_queu
+ }
+ static int sg_io(request_queue_t *q, struct block_device *bdev,
+-               struct sg_io_hdr *uptr)
++               struct sg_io_hdr *hdr)
+ {
+       unsigned long start_time;
+       int reading, writing;
+-      struct sg_io_hdr hdr;
+       struct request *rq;
+       struct bio *bio;
+       char sense[SCSI_SENSE_BUFFERSIZE];
+       void *buffer;
+-      if (copy_from_user(&hdr, uptr, sizeof(*uptr)))
+-              return -EFAULT;
+-
+-      if (hdr.interface_id != 'S')
++      if (hdr->interface_id != 'S')
+               return -EINVAL;
+-      if (hdr.cmd_len > sizeof(rq->cmd))
++      if (hdr->cmd_len > sizeof(rq->cmd))
+               return -EINVAL;
+       /*
+        * we'll do that later
+        */
+-      if (hdr.iovec_count)
++      if (hdr->iovec_count)
+               return -EOPNOTSUPP;
+-      if (hdr.dxfer_len > (q->max_sectors << 9))
++      if (hdr->dxfer_len > (q->max_sectors << 9))
+               return -EIO;
+       reading = writing = 0;
+       buffer = NULL;
+       bio = NULL;
+-      if (hdr.dxfer_len) {
+-              unsigned int bytes = (hdr.dxfer_len + 511) & ~511;
++      if (hdr->dxfer_len) {
++              unsigned int bytes = (hdr->dxfer_len + 511) & ~511;
+-              switch (hdr.dxfer_direction) {
++              switch (hdr->dxfer_direction) {
+               default:
+                       return -EINVAL;
+               case SG_DXFER_TO_FROM_DEV:
+@@ -191,8 +188,8 @@ static int sg_io(request_queue_t *q, str
+                * first try to map it into a bio. reading from device will
+                * be a write to vm.
+                */
+-              bio = bio_map_user(bdev, (unsigned long) hdr.dxferp,
+-                                 hdr.dxfer_len, reading);
++              bio = bio_map_user(bdev, (unsigned long) hdr->dxferp,
++                                 hdr->dxfer_len, reading);
+               /*
+                * if bio setup failed, fall back to slow approach
+@@ -203,11 +200,11 @@ static int sg_io(request_queue_t *q, str
+                               return -ENOMEM;
+                       if (writing) {
+-                              if (copy_from_user(buffer, hdr.dxferp,
+-                                                 hdr.dxfer_len))
++                              if (copy_from_user(buffer, hdr->dxferp,
++                                                 hdr->dxfer_len))
+                                       goto out_buffer;
+                       } else
+-                              memset(buffer, 0, hdr.dxfer_len);
++                              memset(buffer, 0, hdr->dxfer_len);
+               }
+       }
+@@ -216,11 +213,10 @@ static int sg_io(request_queue_t *q, str
+       /*
+        * fill in request structure
+        */
+-      rq->cmd_len = hdr.cmd_len;
+-      if (copy_from_user(rq->cmd, hdr.cmdp, hdr.cmd_len))
+-              goto out_request;
+-      if (sizeof(rq->cmd) != hdr.cmd_len)
+-              memset(rq->cmd + hdr.cmd_len, 0, sizeof(rq->cmd) - hdr.cmd_len);
++      rq->cmd_len = hdr->cmd_len;
++      memcpy(rq->cmd, hdr->cmdp, hdr->cmd_len);
++      if (sizeof(rq->cmd) != hdr->cmd_len)
++              memset(rq->cmd + hdr->cmd_len, 0, sizeof(rq->cmd) - hdr->cmd_len);
+       memset(sense, 0, sizeof(sense));
+       rq->sense = sense;
+@@ -234,9 +230,9 @@ static int sg_io(request_queue_t *q, str
+               blk_rq_bio_prep(q, rq, bio);
+       rq->data = buffer;
+-      rq->data_len = hdr.dxfer_len;
++      rq->data_len = hdr->dxfer_len;
+-      rq->timeout = (hdr.timeout * HZ) / 1000;
++      rq->timeout = (hdr->timeout * HZ) / 1000;
+       if (!rq->timeout)
+               rq->timeout = q->sg_timeout;
+       if (!rq->timeout)
+@@ -254,33 +250,30 @@ static int sg_io(request_queue_t *q, str
+               bio_unmap_user(bio, reading);
+       /* write to all output members */
+-      hdr.status = rq->errors;        
+-      hdr.masked_status = (hdr.status >> 1) & 0x1f;
+-      hdr.msg_status = 0;
+-      hdr.host_status = 0;
+-      hdr.driver_status = 0;
+-      hdr.info = 0;
+-      if (hdr.masked_status || hdr.host_status || hdr.driver_status)
+-              hdr.info |= SG_INFO_CHECK;
+-      hdr.resid = rq->data_len;
+-      hdr.duration = ((jiffies - start_time) * 1000) / HZ;
+-      hdr.sb_len_wr = 0;
++      hdr->status = rq->errors;       
++      hdr->masked_status = (hdr->status >> 1) & 0x1f;
++      hdr->msg_status = 0;
++      hdr->host_status = 0;
++      hdr->driver_status = 0;
++      hdr->info = 0;
++      if (hdr->masked_status || hdr->host_status || hdr->driver_status)
++              hdr->info |= SG_INFO_CHECK;
++      hdr->resid = rq->data_len;
++      hdr->duration = ((jiffies - start_time) * 1000) / HZ;
++      hdr->sb_len_wr = 0;
+-      if (rq->sense_len && hdr.sbp) {
+-              int len = min((unsigned int) hdr.mx_sb_len, rq->sense_len);
++      if (rq->sense_len && hdr->sbp) {
++              int len = min((unsigned int) hdr->mx_sb_len, rq->sense_len);
+-              if (!copy_to_user(hdr.sbp, rq->sense, len))
+-                      hdr.sb_len_wr = len;
++              if (!copy_to_user(hdr->sbp, rq->sense, len))
++                      hdr->sb_len_wr = len;
+       }
+       blk_put_request(rq);
+-      if (copy_to_user(uptr, &hdr, sizeof(*uptr)))
+-              goto out_buffer;
+-
+       if (buffer) {
+               if (reading)
+-                      if (copy_to_user(hdr.dxferp, buffer, hdr.dxfer_len))
++                      if (copy_to_user(hdr->dxferp, buffer, hdr->dxfer_len))
+                               goto out_buffer;
+               kfree(buffer);
+@@ -289,8 +282,6 @@ static int sg_io(request_queue_t *q, str
+       /* may not have succeeded, but output values written to control
+        * structure (struct sg_io_hdr).  */
+       return 0;
+-out_request:
+-      blk_put_request(rq);
+ out_buffer:
+       kfree(buffer);
+       return -EFAULT;
+@@ -319,7 +310,7 @@ static int sg_scsi_ioctl(request_queue_t
+               return -EFAULT;
+       if (in_len > PAGE_SIZE || out_len > PAGE_SIZE)
+               return -EINVAL;
+-      if (get_user(opcode, sic->data))
++      if (get_user(opcode, (int *)sic->data))
+               return -EFAULT;
+       bytes = max(in_len, out_len);
+@@ -437,9 +428,71 @@ int scsi_cmd_ioctl(struct block_device *
+               case SG_EMULATED_HOST:
+                       err = sg_emulated_host(q, (int *) arg);
+                       break;
+-              case SG_IO:
+-                      err = sg_io(q, bdev, (struct sg_io_hdr *) arg);
++              case SG_IO: {
++                      struct sg_io_hdr hdr;
++
++                      if (copy_from_user(&hdr, (struct sg_io_hdr *) arg, sizeof(hdr))) {
++                              err = -EFAULT;
++                              break;
++                      }
++                      err = sg_io(q, bdev, &hdr);
++                      if (copy_to_user((struct sg_io_hdr *) arg, &hdr, sizeof(hdr)))
++                              err = -EFAULT;
+                       break;
++              }
++              case CDROM_SEND_PACKET: {
++                      struct cdrom_generic_command cgc;
++                      struct sg_io_hdr hdr;
++
++                      if (copy_from_user(&cgc, (struct cdrom_generic_command *) arg, sizeof(cgc))) {
++                              err = -EFAULT;
++                              break;
++                      }
++                      cgc.timeout = clock_t_to_jiffies(cgc.timeout);
++                      memset(&hdr, 0, sizeof(hdr));
++                      hdr.interface_id = 'S';
++                      hdr.cmd_len = sizeof(cgc.cmd);
++                      hdr.dxfer_len = cgc.buflen;
++                      err = 0;
++                      switch (cgc.data_direction) {
++                              case CGC_DATA_UNKNOWN:
++                                      hdr.dxfer_direction = SG_DXFER_UNKNOWN;
++                                      break;
++                              case CGC_DATA_WRITE:
++                                      hdr.dxfer_direction = SG_DXFER_TO_DEV;
++                                      break;
++                              case CGC_DATA_READ:
++                                      hdr.dxfer_direction = SG_DXFER_FROM_DEV;
++                                      break;
++                              case CGC_DATA_NONE:
++                                      hdr.dxfer_direction = SG_DXFER_NONE;
++                                      break;
++                              default:
++                                      err = -EINVAL;
++                      }
++                      if (err)
++                              break;
++
++                      hdr.dxferp = cgc.buffer;
++                      hdr.sbp = (char *) cgc.sense;
++                      if (hdr.sbp)
++                              hdr.mx_sb_len = sizeof(struct request_sense);
++                      hdr.timeout = cgc.timeout;
++                      hdr.cmdp = cgc.cmd;
++                      hdr.cmd_len = sizeof(cgc.cmd);
++                      err = sg_io(q, bdev, &hdr);
++
++                      if (hdr.status)
++                              err = -EIO;
++
++                      cgc.stat = err;
++                      cgc.buflen = hdr.resid;
++                      if (copy_to_user((struct cdrom_generic_command *) arg, &cgc, sizeof(cgc)))
++                              err = -EFAULT;
++
++                      break;
++              }
++
+               /*
+                * old junk scsi send command ioctl
+                */
+--- linux-2.6.0-test6/drivers/block/swim3.c    2003-08-08 22:55:11.000000000 -0700
++++ 25/drivers/block/swim3.c   2003-10-05 00:34:01.000000000 -0700
+@@ -239,10 +239,9 @@ static int grab_drive(struct floppy_stat
+                     int interruptible);
+ static void release_drive(struct floppy_state *fs);
+ static int fd_eject(struct floppy_state *fs);
+-static int floppy_ioctl(struct inode *inode, struct file *filp,
++static int floppy_ioctl(struct block_device *bdev, struct file *filp,
+                       unsigned int cmd, unsigned long param);
+-static int floppy_open(struct inode *inode, struct file *filp);
+-static int floppy_release(struct inode *inode, struct file *filp);
++static int floppy_open(struct block_device *bdev, struct file *filp);
+ static int floppy_check_change(struct gendisk *disk);
+ static int floppy_revalidate(struct gendisk *disk);
+ static int swim3_add_device(struct device_node *swims);
+@@ -811,10 +810,10 @@ static int fd_eject(struct floppy_state 
+ static struct floppy_struct floppy_type =
+       { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL };    /*  7 1.44MB 3.5"   */
+-static int floppy_ioctl(struct inode *inode, struct file *filp,
++static int floppy_ioctl(struct block_device *bdev, struct file *filp,
+                       unsigned int cmd, unsigned long param)
+ {
+-      struct floppy_state *fs = inode->i_bdev->bd_disk->private_data;
++      struct floppy_state *fs = bdev->bd_disk->private_data;
+       int err;
+               
+       if ((cmd & 0x80) && !capable(CAP_SYS_ADMIN))
+@@ -838,9 +837,9 @@ static int floppy_ioctl(struct inode *in
+       return -ENOTTY;
+ }
+-static int floppy_open(struct inode *inode, struct file *filp)
++static int floppy_open(struct block_device *bdev, struct file *filp)
+ {
+-      struct floppy_state *fs = inode->i_bdev->bd_disk->private_data;
++      struct floppy_state *fs = bdev->bd_disk->private_data;
+       volatile struct swim3 *sw = fs->swim3;
+       int n, err = 0;
+@@ -876,7 +875,7 @@ static int floppy_open(struct inode *ino
+       if (err == 0 && (filp->f_flags & O_NDELAY) == 0
+           && (filp->f_mode & 3)) {
+-              check_disk_change(inode->i_bdev);
++              check_disk_change(bdev);
+               if (fs->ejected)
+                       err = -ENXIO;
+       }
+@@ -904,9 +903,9 @@ static int floppy_open(struct inode *ino
+       return 0;
+ }
+-static int floppy_release(struct inode *inode, struct file *filp)
++static int floppy_release(struct gendisk *disk)
+ {
+-      struct floppy_state *fs = inode->i_bdev->bd_disk->private_data;
++      struct floppy_state *fs = disk->private_data;
+       volatile struct swim3 *sw = fs->swim3;
+       if (fs->ref_count > 0 && --fs->ref_count == 0) {
+               swim3_action(fs, MOTOR_OFF);
+--- linux-2.6.0-test6/drivers/block/swim_iop.c 2003-08-08 22:55:11.000000000 -0700
++++ 25/drivers/block/swim_iop.c        2003-10-05 00:34:01.000000000 -0700
+@@ -31,6 +31,7 @@
+ #include <linux/delay.h>
+ #include <linux/fd.h>
+ #include <linux/ioctl.h>
++#include <linux/blkdev.h>
+ #include <asm/io.h>
+ #include <asm/uaccess.h>
+ #include <asm/mac_iop.h>
+@@ -97,10 +98,10 @@ static void swimiop_receive(struct iop_m
+ static void swimiop_status_update(int, struct swim_drvstatus *);
+ static int swimiop_eject(struct floppy_state *fs);
+-static int floppy_ioctl(struct inode *inode, struct file *filp,
++static int floppy_ioctl(struct block_device *bdev, struct file *filp,
+                       unsigned int cmd, unsigned long param);
+-static int floppy_open(struct inode *inode, struct file *filp);
+-static int floppy_release(struct inode *inode, struct file *filp);
++static int floppy_open(struct block_device *bdev, struct file *filp);
++static int floppy_release(struct gendisk *disk);
+ static int floppy_check_change(struct gendisk *disk);
+ static int floppy_revalidate(struct gendisk *disk);
+ static int grab_drive(struct floppy_state *fs, enum swim_state state,
+@@ -347,10 +348,10 @@ static int swimiop_eject(struct floppy_s
+ static struct floppy_struct floppy_type =
+       { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL };    /*  7 1.44MB 3.5"   */
+-static int floppy_ioctl(struct inode *inode, struct file *filp,
++static int floppy_ioctl(struct block_device *bdev, struct file *filp,
+                       unsigned int cmd, unsigned long param)
+ {
+-      struct floppy_state *fs = inode->i_bdev->bd_disk->private_data;
++      struct floppy_state *fs = bdev->bd_disk->private_data;
+       int err;
+       if ((cmd & 0x80) && !capable(CAP_SYS_ADMIN))
+@@ -371,15 +372,15 @@ static int floppy_ioctl(struct inode *in
+       return -ENOTTY;
+ }
+-static int floppy_open(struct inode *inode, struct file *filp)
++static int floppy_open(struct block_device *bdev, struct file *filp)
+ {
+-      struct floppy_state *fs = inode->i_bdev->bd_disk->private_data;
++      struct floppy_state *fs = bdev->bd_disk->private_data;
+       if (fs->ref_count == -1 || filp->f_flags & O_EXCL)
+               return -EBUSY;
+       if ((filp->f_flags & O_NDELAY) == 0 && (filp->f_mode & 3)) {
+-              check_disk_change(inode->i_bdev);
++              check_disk_change(bdev);
+               if (fs->ejected)
+                       return -ENXIO;
+       }
+@@ -395,9 +396,9 @@ static int floppy_open(struct inode *ino
+       return 0;
+ }
+-static int floppy_release(struct inode *inode, struct file *filp)
++static int floppy_release(struct gendisk *disk)
+ {
+-      struct floppy_state *fs = inode->i_bdev->bd_disk->private_data;
++      struct floppy_state *fs = disk->private_data;
+       if (fs->ref_count > 0)
+               fs->ref_count--;
+       return 0;
+--- linux-2.6.0-test6/drivers/block/umem.c     2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/block/umem.c    2003-10-05 00:33:58.000000000 -0700
+@@ -153,7 +153,6 @@ struct cardinfo {
+ };
+ static struct cardinfo cards[MM_MAXCARDS];
+-static struct block_device_operations mm_fops;
+ static struct timer_list battery_timer;
+ static int num_cards = 0;
+@@ -818,10 +817,10 @@ static int mm_revalidate(struct gendisk 
+ --                            mm_ioctl
+ -----------------------------------------------------------------------------------
+ */
+-static int mm_ioctl(struct inode *i, struct file *f, unsigned int cmd, unsigned long arg)
++static int mm_ioctl(struct block_device *bdev, struct file *f, unsigned int cmd, unsigned long arg)
+ {
+       if (cmd == HDIO_GETGEO) {
+-              struct cardinfo *card = i->i_bdev->bd_disk->private_data;
++              struct cardinfo *card = bdev->bd_disk->private_data;
+               int size = card->mm_size * (1024 / MM_HARDSECT);
+               struct hd_geometry geo;
+               /*
+@@ -831,7 +830,7 @@ static int mm_ioctl(struct inode *i, str
+                */
+               geo.heads     = 64;
+               geo.sectors   = 32;
+-              geo.start     = get_start_sect(i->i_bdev);
++              geo.start     = get_start_sect(bdev);
+               geo.cylinders = size / (geo.heads * geo.sectors);
+               if (copy_to_user((void *) arg, &geo, sizeof(geo)))
+--- linux-2.6.0-test6/drivers/block/xd.c       2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/block/xd.c      2003-10-05 00:33:54.000000000 -0700
+@@ -322,9 +322,9 @@ static void do_xd_request (request_queue
+ }
+ /* xd_ioctl: handle device ioctl's */
+-static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg)
++static int xd_ioctl (struct block_device *bdev,struct file *file,u_int cmd,u_long arg)
+ {
+-      XD_INFO *p = inode->i_bdev->bd_disk->private_data;
++      XD_INFO *p = bdev->bd_disk->private_data;
+       switch (cmd) {
+               case HDIO_GETGEO:
+@@ -334,7 +334,7 @@ static int xd_ioctl (struct inode *inode
+                       g.heads = p->heads;
+                       g.sectors = p->sectors;
+                       g.cylinders = p->cylinders;
+-                      g.start = get_start_sect(inode->i_bdev);
++                      g.start = get_start_sect(bdev);
+                       return copy_to_user(geometry, &g, sizeof g) ? -EFAULT : 0;
+               }
+               case HDIO_SET_DMA:
+--- linux-2.6.0-test6/drivers/block/xd.h       2003-06-14 12:18:30.000000000 -0700
++++ 25/drivers/block/xd.h      2003-10-05 00:33:54.000000000 -0700
+@@ -105,7 +105,7 @@ static u_char xd_detect (u_char *control
+ static u_char xd_initdrives (void (*init_drive)(u_char drive));
+ static void do_xd_request (request_queue_t * q);
+-static int xd_ioctl (struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg);
++static int xd_ioctl (struct block_device *bdev,struct file *file,unsigned int cmd,unsigned long arg);
+ static int xd_readwrite (u_char operation,XD_INFO *disk,char *buffer,u_int block,u_int count);
+ static void xd_recalibrate (u_char drive);
+--- linux-2.6.0-test6/drivers/block/z2ram.c    2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/block/z2ram.c   2003-10-05 00:34:01.000000000 -0700
+@@ -67,7 +67,6 @@ static int current_device   = -1;
+ static spinlock_t z2ram_lock = SPIN_LOCK_UNLOCKED;
+-static struct block_device_operations z2_fops;
+ static struct gendisk *z2ram_gendisk;
+ static void do_z2_request(request_queue_t *q)
+@@ -141,7 +140,7 @@ get_chipram( void )
+ }
+ static int
+-z2_open( struct inode *inode, struct file *filp )
++z2_open( struct block_device *bdev, struct file *filp )
+ {
+     int device;
+     int max_z2_map = ( Z2RAM_SIZE / Z2RAM_CHUNKSIZE ) *
+@@ -150,7 +149,7 @@ z2_open( struct inode *inode, struct fil
+       sizeof( z2ram_map[0] );
+     int rc = -ENOMEM;
+-    device = iminor(inode);
++    device = MINOR(bdev->bd_dev);
+     if ( current_device != -1 && current_device != device )
+     {
+@@ -301,8 +300,7 @@ err_out:
+     return rc;
+ }
+-static int
+-z2_release( struct inode *inode, struct file *filp )
++static int z2_release(struct gendisk *disk)
+ {
+     if ( current_device == -1 )
+       return 0;     
+--- linux-2.6.0-test6/drivers/cdrom/aztcd.c    2003-09-08 13:58:56.000000000 -0700
++++ 25/drivers/cdrom/aztcd.c   2003-10-05 00:34:01.000000000 -0700
+@@ -330,10 +330,10 @@ static int aztGetToc(int multi);
+ /* Kernel Interface Functions */
+ static int check_aztcd_media_change(struct gendisk *disk);
+-static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
++static int aztcd_ioctl(struct block_device *bdev, struct file *fp, unsigned int cmd,
+                      unsigned long arg);
+-static int aztcd_open(struct inode *ip, struct file *fp);
+-static int aztcd_release(struct inode *inode, struct file *file);
++static int aztcd_open(struct block_device *bdev, struct file *fp);
++static int aztcd_release(struct gendisk *disk);
+ static struct block_device_operations azt_fops = {
+       .owner          = THIS_MODULE,
+@@ -1153,7 +1153,7 @@ static int check_aztcd_media_change(stru
+ /*
+  * Kernel IO-controls
+ */
+-static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
++static int aztcd_ioctl(struct block_device *bdev, struct file *fp, unsigned int cmd,
+                      unsigned long arg)
+ {
+       int i;
+@@ -1171,8 +1171,6 @@ static int aztcd_ioctl(struct inode *ip,
+              cmd, jiffies);
+       printk("aztcd Status %x\n", getAztStatus());
+ #endif
+-      if (!ip)
+-              RETURNM("aztcd_ioctl 1", -EINVAL);
+       if (getAztStatus() < 0)
+               RETURNM("aztcd_ioctl 2", -EIO);
+       if ((!aztTocUpToDate) || (aztDiskChanged)) {
+@@ -1624,7 +1622,7 @@ static void azt_invalidate_buffers(void)
+ /*
+  * Open the device special file.  Check that a disk is in.
+  */
+-static int aztcd_open(struct inode *ip, struct file *fp)
++static int aztcd_open(struct block_device *bdev, struct file *fp)
+ {
+       int st;
+@@ -1673,12 +1671,11 @@ static int aztcd_open(struct inode *ip, 
+ /*
+  * On close, we flush all azt blocks from the buffer cache.
+  */
+-static int aztcd_release(struct inode *inode, struct file *file)
++static int aztcd_release(struct gendisk *disk)
+ {
+ #ifdef AZT_DEBUG
+       printk("aztcd: executing aztcd_release\n");
+-      printk("inode: %p, device: %s    file: %p\n", inode,
+-             inode->i_bdev->bd_disk->disk_name, file);
++      printk("disk: %p, device: %s\n", disk, disk->disk_name);
+ #endif
+       if (!--azt_open_count) {
+               azt_invalidate_buffers();
+--- linux-2.6.0-test6/drivers/cdrom/cdrom.c    2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/cdrom/cdrom.c   2003-10-05 00:33:59.000000000 -0700
+@@ -367,6 +367,7 @@ int register_cdrom(struct cdrom_device_i
+       ENSURE(generic_packet, CDC_GENERIC_PACKET);
+       cdi->mc_flags = 0;
+       cdo->n_minors = 0;
++      cdi->for_data = 0;
+         cdi->options = CDO_USE_FFLAGS;
+       
+       if (autoclose==1 && CDROM_CAN(CDC_CLOSE_TRAY))
+@@ -416,7 +417,7 @@ int unregister_cdrom(struct cdrom_device
+  * is in their own interest: device control becomes a lot easier
+  * this way.
+  */
+-int cdrom_open(struct cdrom_device_info *cdi, struct inode *ip, struct file *fp)
++int cdrom_open(struct cdrom_device_info *cdi, struct block_device *bdev, struct file *fp)
+ {
+       int ret;
+@@ -437,7 +438,7 @@ int cdrom_open(struct cdrom_device_info 
+       cdinfo(CD_OPEN, "Use count for \"/dev/%s\" now %d\n", cdi->name, cdi->use_count);
+       /* Do this on open.  Don't wait for mount, because they might
+           not be mounting, but opening with O_NONBLOCK */
+-      check_disk_change(ip->i_bdev);
++      check_disk_change(bdev);
+       return ret;
+ }
+@@ -530,6 +531,7 @@ int open_for_data(struct cdrom_device_in
+                       cdinfo(CD_OPEN, "door locked.\n");
+       }
+       cdinfo(CD_OPEN, "device opened successfully.\n"); 
++      cdi->for_data = 1;
+       return ret;
+       /* Something failed.  Try to unlock the drive, because some drivers
+@@ -605,30 +607,29 @@ int check_for_audio_disc(struct cdrom_de
+ /* Admittedly, the logic below could be performed in a nicer way. */
+-int cdrom_release(struct cdrom_device_info *cdi, struct file *fp)
++int cdrom_release(struct cdrom_device_info *cdi)
+ {
+       struct cdrom_device_ops *cdo = cdi->ops;
+-      int opened_for_data;
+       cdinfo(CD_CLOSE, "entering cdrom_release\n"); 
+       if (cdi->use_count > 0)
+               cdi->use_count--;
+-      if (cdi->use_count == 0)
+-              cdinfo(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n", cdi->name);
+-      if (cdi->use_count == 0 &&
+-          cdo->capability & CDC_LOCK && !keeplocked) {
++      if (cdi->use_count) {
++              cdo->release(cdi);
++              return 0;
++      }
++              
++      cdinfo(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n", cdi->name);
++      if (cdo->capability & CDC_LOCK && !keeplocked) {
+               cdinfo(CD_CLOSE, "Unlocking door!\n");
+               cdo->lock_door(cdi, 0);
+       }
+-      opened_for_data = !(cdi->options & CDO_USE_FFLAGS) ||
+-              !(fp && fp->f_flags & O_NONBLOCK);
+       cdo->release(cdi);
+-      if (cdi->use_count == 0) {      /* last process that closes dev*/
+-              if (opened_for_data &&
+-                  cdi->options & CDO_AUTO_EJECT && CDROM_CAN(CDC_OPEN_TRAY))
+-                      cdo->tray_move(cdi, 1);
+-      }
++      if (cdi->for_data &&
++          cdi->options & CDO_AUTO_EJECT && CDROM_CAN(CDC_OPEN_TRAY))
++              cdo->tray_move(cdi, 1);
++      cdi->for_data = 0;
+       return 0;
+ }
+@@ -1433,14 +1434,14 @@ static int cdrom_read_block(struct cdrom
+  * these days. ATAPI / SCSI specific code now mainly resides in
+  * mmc_ioct().
+  */
+-int cdrom_ioctl(struct cdrom_device_info *cdi, struct inode *ip,
++int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev,
+               unsigned int cmd, unsigned long arg)
+ {
+       struct cdrom_device_ops *cdo = cdi->ops;
+       int ret;
+       /* Try the generic SCSI command ioctl's first.. */
+-      ret = scsi_cmd_ioctl(ip->i_bdev, cmd, arg);
++      ret = scsi_cmd_ioctl(bdev, cmd, arg);
+       if (ret != -ENOTTY)
+               return ret;
+@@ -1593,7 +1594,7 @@ int cdrom_ioctl(struct cdrom_device_info
+               cdinfo(CD_DO_IOCTL, "entering CDROM_RESET\n");
+               if (!CDROM_CAN(CDC_RESET))
+                       return -ENOSYS;
+-              invalidate_bdev(ip->i_bdev, 0);
++              invalidate_bdev(bdev, 0);
+               return cdo->reset(cdi);
+               }
+@@ -1856,57 +1857,6 @@ static int cdrom_switch_blocksize(struct
+       return cdo->generic_packet(cdi, &cgc);
+ }
+-static int cdrom_do_cmd(struct cdrom_device_info *cdi,
+-                      struct cdrom_generic_command *cgc)
+-{
+-      struct request_sense *usense, sense;
+-      unsigned char *ubuf;
+-      int ret;
+-
+-      if (cgc->data_direction == CGC_DATA_UNKNOWN)
+-              return -EINVAL;
+-
+-      if (cgc->buflen < 0 || cgc->buflen >= 131072)
+-              return -EINVAL;
+-
+-      usense = cgc->sense;
+-      cgc->sense = &sense;
+-      if (usense && !access_ok(VERIFY_WRITE, usense, sizeof(*usense))) {
+-              return -EFAULT;
+-      }
+-
+-      ubuf = cgc->buffer;
+-      if (cgc->data_direction == CGC_DATA_READ ||
+-          cgc->data_direction == CGC_DATA_WRITE) {
+-              cgc->buffer = kmalloc(cgc->buflen, GFP_KERNEL);
+-              if (cgc->buffer == NULL)
+-                      return -ENOMEM;
+-      }
+-
+-
+-      if (cgc->data_direction == CGC_DATA_READ) {
+-              if (!access_ok(VERIFY_READ, ubuf, cgc->buflen)) {
+-                      kfree(cgc->buffer);
+-                      return -EFAULT;
+-              }
+-      } else if (cgc->data_direction == CGC_DATA_WRITE) {
+-              if (copy_from_user(cgc->buffer, ubuf, cgc->buflen)) {
+-                      kfree(cgc->buffer);
+-                      return -EFAULT;
+-              }
+-      }
+-
+-      ret = cdi->ops->generic_packet(cdi, cgc);
+-      __copy_to_user(usense, cgc->sense, sizeof(*usense));
+-      if (!ret && cgc->data_direction == CGC_DATA_READ)
+-              __copy_to_user(ubuf, cgc->buffer, cgc->buflen);
+-      if (cgc->data_direction == CGC_DATA_READ ||
+-          cgc->data_direction == CGC_DATA_WRITE) {
+-              kfree(cgc->buffer);
+-      }
+-      return ret;
+-}
+-
+ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
+                    unsigned long arg)
+ {             
+@@ -2176,14 +2126,6 @@ static int mmc_ioctl(struct cdrom_device
+               return 0;
+               }
+-      case CDROM_SEND_PACKET: {
+-              if (!CDROM_CAN(CDC_GENERIC_PACKET))
+-                      return -ENOSYS;
+-              cdinfo(CD_DO_IOCTL, "entering CDROM_SEND_PACKET\n"); 
+-              IOCTL_IN(arg, struct cdrom_generic_command, cgc);
+-              cgc.timeout = clock_t_to_jiffies(cgc.timeout);
+-              return cdrom_do_cmd(cdi, &cgc);
+-              }
+       case CDROM_NEXT_WRITABLE: {
+               long next = 0;
+               cdinfo(CD_DO_IOCTL, "entering CDROM_NEXT_WRITABLE\n"); 
+--- linux-2.6.0-test6/drivers/cdrom/cdu31a.c   2003-09-08 13:58:56.000000000 -0700
++++ 25/drivers/cdrom/cdu31a.c  2003-10-05 00:34:01.000000000 -0700
+@@ -3167,20 +3167,20 @@ static struct cdrom_device_info scd_info
+       .name           = "cdu31a"
+ };
+-static int scd_block_open(struct inode *inode, struct file *file)
++static int scd_block_open(struct block_device *bdev, struct file *file)
+ {
+-      return cdrom_open(&scd_info, inode, file);
++      return cdrom_open(&scd_info, bdev, file);
+ }
+-static int scd_block_release(struct inode *inode, struct file *file)
++static int scd_block_release(struct gendisk *disk)
+ {
+-      return cdrom_release(&scd_info, file);
++      return cdrom_release(&scd_info);
+ }
+-static int scd_block_ioctl(struct inode *inode, struct file *file,
++static int scd_block_ioctl(struct block_device *bdev, struct file *file,
+                               unsigned cmd, unsigned long arg)
+ {
+-      return cdrom_ioctl(&scd_info, inode, cmd, arg);
++      return cdrom_ioctl(&scd_info, bdev, cmd, arg);
+ }
+ static int scd_block_media_changed(struct gendisk *disk)
+--- linux-2.6.0-test6/drivers/cdrom/cm206.c    2003-09-08 13:58:56.000000000 -0700
++++ 25/drivers/cdrom/cm206.c   2003-10-05 00:34:01.000000000 -0700
+@@ -1350,20 +1350,20 @@ static struct cdrom_device_info cm206_in
+       .name           = "cm206",
+ };
+-static int cm206_block_open(struct inode *inode, struct file *file)
++static int cm206_block_open(struct block_device *bdev, struct file *file)
+ {
+-      return cdrom_open(&cm206_info, inode, file);
++      return cdrom_open(&cm206_info, bdev, file);
+ }
+-static int cm206_block_release(struct inode *inode, struct file *file)
++static int cm206_block_release(struct gendisk *disk)
+ {
+-      return cdrom_release(&cm206_info, file);
++      return cdrom_release(&cm206_info);
+ }
+-static int cm206_block_ioctl(struct inode *inode, struct file *file,
++static int cm206_block_ioctl(struct block_device *bdev, struct file *file,
+                               unsigned cmd, unsigned long arg)
+ {
+-      return cdrom_ioctl(&cm206_info, inode, cmd, arg);
++      return cdrom_ioctl(&cm206_info, bdev, cmd, arg);
+ }
+ static int cm206_block_media_changed(struct gendisk *disk)
+--- linux-2.6.0-test6/drivers/cdrom/gscd.c     2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/cdrom/gscd.c    2003-10-05 00:34:01.000000000 -0700
+@@ -91,10 +91,10 @@ static void gscd_bin2bcd(unsigned char *
+ /* Schnittstellen zum Kern/FS */
+ static void __do_gscd_request(unsigned long dummy);
+-static int gscd_ioctl(struct inode *, struct file *, unsigned int,
++static int gscd_ioctl(struct block_device *, struct file *, unsigned int,
+                     unsigned long);
+-static int gscd_open(struct inode *, struct file *);
+-static int gscd_release(struct inode *, struct file *);
++static int gscd_open(struct block_device *, struct file *);
++static int gscd_release(struct gendisk *disk);
+ static int check_gscd_med_chg(struct gendisk *disk);
+ /*      GoldStar Funktionen    */
+@@ -190,8 +190,8 @@ __setup("gscd=", gscd_setup);
+ #endif
+-static int gscd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
+-                    unsigned long arg)
++static int gscd_ioctl(struct block_device *bdev, struct file *fp,
++                      unsigned int cmd, unsigned long arg)
+ {
+       unsigned char to_do[10];
+       unsigned char dummy;
+@@ -338,7 +338,7 @@ static void gscd_read_cmd(struct request
+  * Open the device special file.  Check that a disk is in.
+  */
+-static int gscd_open(struct inode *ip, struct file *fp)
++static int gscd_open(struct block_device *bdev, struct file *fp)
+ {
+       int st;
+@@ -368,7 +368,7 @@ static int gscd_open(struct inode *ip, s
+  * On close, we flush all gscd blocks from the buffer cache.
+  */
+-static int gscd_release(struct inode *inode, struct file *file)
++static int gscd_release(struct gendisk *disk)
+ {
+ #ifdef GSCD_DEBUG
+--- linux-2.6.0-test6/drivers/cdrom/mcd.c      2003-09-08 13:58:56.000000000 -0700
++++ 25/drivers/cdrom/mcd.c     2003-10-05 00:34:01.000000000 -0700
+@@ -214,20 +214,20 @@ static struct cdrom_device_info mcd_info
+       .name           = "mcd",
+ };
+-static int mcd_block_open(struct inode *inode, struct file *file)
++static int mcd_block_open(struct block_device *bdev, struct file *file)
+ {
+-      return cdrom_open(&mcd_info, inode, file);
++      return cdrom_open(&mcd_info, bdev, file);
+ }
+-static int mcd_block_release(struct inode *inode, struct file *file)
++static int mcd_block_release(struct gendisk *disk)
+ {
+-      return cdrom_release(&mcd_info, file);
++      return cdrom_release(&mcd_info);
+ }
+-static int mcd_block_ioctl(struct inode *inode, struct file *file,
++static int mcd_block_ioctl(struct block_device *bdev, struct file *file,
+                               unsigned cmd, unsigned long arg)
+ {
+-      return cdrom_ioctl(&mcd_info, inode, cmd, arg);
++      return cdrom_ioctl(&mcd_info, bdev, cmd, arg);
+ }
+ static int mcd_block_media_changed(struct gendisk *disk)
+--- linux-2.6.0-test6/drivers/cdrom/mcdx.c     2003-09-08 13:58:56.000000000 -0700
++++ 25/drivers/cdrom/mcdx.c    2003-10-05 00:34:01.000000000 -0700
+@@ -221,23 +221,23 @@ struct s_drive_stuff {
+ int mcdx_init(void);
+ void do_mcdx_request(request_queue_t * q);
+-static int mcdx_block_open(struct inode *inode, struct file *file)
++static int mcdx_block_open(struct block_device *bdev, struct file *file)
+ {
+-      struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data;
+-      return cdrom_open(&p->info, inode, file);
++      struct s_drive_stuff *p = bdev->bd_disk->private_data;
++      return cdrom_open(&p->info, bdev, file);
+ }
+-static int mcdx_block_release(struct inode *inode, struct file *file)
++static int mcdx_block_release(struct gendisk *disk)
+ {
+-      struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data;
+-      return cdrom_release(&p->info, file);
++      struct s_drive_stuff *p = disk->private_data;
++      return cdrom_release(&p->info);
+ }
+-static int mcdx_block_ioctl(struct inode *inode, struct file *file,
++static int mcdx_block_ioctl(struct block_device *bdev, struct file *file,
+                               unsigned cmd, unsigned long arg)
+ {
+-      struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data;
+-      return cdrom_ioctl(&p->info, inode, cmd, arg);
++      struct s_drive_stuff *p = bdev->bd_disk->private_data;
++      return cdrom_ioctl(&p->info, bdev, cmd, arg);
+ }
+ static int mcdx_block_media_changed(struct gendisk *disk)
+--- linux-2.6.0-test6/drivers/cdrom/optcd.c    2003-09-08 13:58:56.000000000 -0700
++++ 25/drivers/cdrom/optcd.c   2003-10-05 00:34:01.000000000 -0700
+@@ -1713,16 +1713,13 @@ static int cdromreset(void)
+ /* VFS calls */
+-static int opt_ioctl(struct inode *ip, struct file *fp,
++static int opt_ioctl(struct block_device *bdev, struct file *fp,
+                      unsigned int cmd, unsigned long arg)
+ {
+       int status, err, retval = 0;
+       DEBUG((DEBUG_VFS, "starting opt_ioctl"));
+-      if (!ip)
+-              return -EINVAL;
+-
+       if (cmd == CDROMRESET)
+               return cdromreset();
+@@ -1844,7 +1841,7 @@ static int opt_ioctl(struct inode *ip, s
+ static int open_count = 0;
+ /* Open device special file; check that a disk is in. */
+-static int opt_open(struct inode *ip, struct file *fp)
++static int opt_open(struct block_device *bdev, struct file *fp)
+ {
+       DEBUG((DEBUG_VFS, "starting opt_open"));
+@@ -1904,13 +1901,12 @@ err_out:
+ /* Release device special file; flush all blocks from the buffer cache */
+-static int opt_release(struct inode *ip, struct file *fp)
++static int opt_release(struct gendisk *disk)
+ {
+       int status;
+       DEBUG((DEBUG_VFS, "executing opt_release"));
+-      DEBUG((DEBUG_VFS, "inode: %p, device: %s, file: %p\n",
+-              ip, ip->i_bdev->bd_disk->disk_name, fp));
++      DEBUG((DEBUG_VFS, "disk: %p, device: %s\n", disk, disk->disk_name));
+       if (!--open_count) {
+               toc_uptodate = 0;
+--- linux-2.6.0-test6/drivers/cdrom/sbpcd.c    2003-09-08 13:58:56.000000000 -0700
++++ 25/drivers/cdrom/sbpcd.c   2003-10-05 00:34:01.000000000 -0700
+@@ -363,7 +363,6 @@
+ #include <linux/module.h>
+-#include <linux/version.h>
+ #include <linux/errno.h>
+ #include <linux/sched.h>
+ #include <linux/mm.h>
+@@ -5357,23 +5356,23 @@ static int sbp_data(struct request *req)
+ }
+ /*==========================================================================*/
+-static int sbpcd_block_open(struct inode *inode, struct file *file)
++static int sbpcd_block_open(struct block_device *bdev, struct file *file)
+ {
+-      struct sbpcd_drive *p = inode->i_bdev->bd_disk->private_data;
+-      return cdrom_open(p->sbpcd_infop, inode, file);
++      struct sbpcd_drive *p = bdev->bd_disk->private_data;
++      return cdrom_open(p->sbpcd_infop, bdev, file);
+ }
+-static int sbpcd_block_release(struct inode *inode, struct file *file)
++static int sbpcd_block_release(struct gendisk *disk)
+ {
+-      struct sbpcd_drive *p = inode->i_bdev->bd_disk->private_data;
+-      return cdrom_release(p->sbpcd_infop, file);
++      struct sbpcd_drive *p = disk->private_data;
++      return cdrom_release(p->sbpcd_infop);
+ }
+-static int sbpcd_block_ioctl(struct inode *inode, struct file *file,
++static int sbpcd_block_ioctl(struct block_device *bdev, struct file *file,
+                               unsigned cmd, unsigned long arg)
+ {
+-      struct sbpcd_drive *p = inode->i_bdev->bd_disk->private_data;
+-      return cdrom_ioctl(p->sbpcd_infop, inode, cmd, arg);
++      struct sbpcd_drive *p = bdev->bd_disk->private_data;
++      return cdrom_ioctl(p->sbpcd_infop, bdev, cmd, arg);
+ }
+ static int sbpcd_block_media_changed(struct gendisk *disk)
+--- linux-2.6.0-test6/drivers/cdrom/sjcd.c     2003-09-08 13:58:56.000000000 -0700
++++ 25/drivers/cdrom/sjcd.c    2003-10-05 00:34:01.000000000 -0700
+@@ -713,16 +713,13 @@ static int sjcd_tray_open(void)
+ /*
+  * Do some user commands.
+  */
+-static int sjcd_ioctl(struct inode *ip, struct file *fp,
++static int sjcd_ioctl(struct block_device *bdev, struct file *fp,
+                     unsigned int cmd, unsigned long arg)
+ {
+ #if defined( SJCD_TRACE )
+       printk("SJCD:ioctl\n");
+ #endif
+-      if (ip == NULL)
+-              return (-EINVAL);
+-
+       sjcd_get_status();
+       if (!sjcd_status_valid)
+               return (-EIO);
+@@ -1522,7 +1519,7 @@ static void do_sjcd_request(request_queu
+ /*
+  * Open the device special file. Check disk is in.
+  */
+-static int sjcd_open(struct inode *ip, struct file *fp)
++static int sjcd_open(struct block_device *bdev, struct file *fp)
+ {
+       /*
+        * Check the presence of device.
+@@ -1607,7 +1604,7 @@ static int sjcd_open(struct inode *ip, s
+ /*
+  * On close, we flush all sjcd blocks from the buffer cache.
+  */
+-static int sjcd_release(struct inode *inode, struct file *file)
++static int sjcd_release(struct gendisk *disk)
+ {
+       int s;
+--- linux-2.6.0-test6/drivers/cdrom/sonycd535.c        2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/cdrom/sonycd535.c       2003-10-05 00:34:01.000000000 -0700
+@@ -201,7 +201,7 @@
+ static int read_subcode(void);
+ static void sony_get_toc(void);
+-static int cdu_open(struct inode *inode, struct file *filp);
++static int cdu_open(struct block_device *bdev, struct file *filp);
+ static inline unsigned int int_to_bcd(unsigned int val);
+ static unsigned int bcd_to_int(unsigned int bcd);
+ static int do_sony_cmd(Byte * cmd, int nCmd, Byte status[2],
+@@ -1061,7 +1061,7 @@ sony_get_subchnl_info(long arg)
+  * The big ugly ioctl handler.
+  */
+ static int
+-cdu_ioctl(struct inode *inode,
++cdu_ioctl(struct block_device *bdev,
+                 struct file *file,
+                 unsigned int cmd,
+                 unsigned long arg)
+@@ -1363,9 +1363,7 @@ cdu_ioctl(struct inode *inode,
+  * Open the drive for operations.  Spin the drive up and read the table of
+  * contents if these have not already been done.
+  */
+-static int
+-cdu_open(struct inode *inode,
+-               struct file *filp)
++static int cdu_open(struct block_device *bdev, struct file *filp)
+ {
+       Byte status[2], cmd_buff[2];
+@@ -1388,7 +1386,7 @@ cdu_open(struct inode *inode,
+               sony_inuse = 0;
+               return -EIO;
+       }
+-      check_disk_change(inode->i_bdev);
++      check_disk_change(bdev);
+       sony_usage++;
+ #ifdef LOCK_DOORS
+@@ -1405,9 +1403,7 @@ cdu_open(struct inode *inode,
+  * Close the drive.  Spin it down if no task is using it.  The spin
+  * down will fail if playing audio, so audio play is OK.
+  */
+-static int
+-cdu_release(struct inode *inode,
+-                      struct file *filp)
++static int cdu_release(struct gendisk *disk)
+ {
+       Byte status[2], cmd_no;
+--- linux-2.6.0-test6/drivers/char/agp/amd64-agp.c     2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/char/agp/amd64-agp.c    2003-10-05 00:33:24.000000000 -0700
+@@ -91,9 +91,9 @@ static int amd64_insert_memory(struct ag
+       for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
+               tmp = agp_bridge->driver->mask_memory(mem->memory[i], mem->type);
+-              BUG_ON(tmp & 0xffffff0000000ffc);
+-              pte = (tmp & 0x000000ff00000000) >> 28;
+-              pte |=(tmp & 0x00000000fffff000);
++              BUG_ON(tmp & 0xffffff0000000ffcULL);
++              pte = (tmp & 0x000000ff00000000ULL) >> 28;
++              pte |=(tmp & 0x00000000fffff000ULL);
+               pte |= GPTE_VALID | GPTE_COHERENT;
+               agp_bridge->gatt_table[j] = pte;
+--- linux-2.6.0-test6/drivers/char/agp/via-agp.c       2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/char/agp/via-agp.c      2003-10-05 00:33:24.000000000 -0700
+@@ -251,6 +251,11 @@ static struct agp_device_ids via_agp_dev
+               .chipset_name   = "Pro 266",
+       },
++      {
++              .device_id      = PCI_DEVICE_ID_VIA_XN266,
++              .chipset_name   = "Apollo Pro266",
++      },
++
+       /* VT8361 */
+       {
+               .device_id      = PCI_DEVICE_ID_VIA_8361,
+--- linux-2.6.0-test6/drivers/char/amiserial.c 2003-07-27 12:14:38.000000000 -0700
++++ 25/drivers/char/amiserial.c        2003-10-05 00:33:24.000000000 -0700
+@@ -32,7 +32,6 @@
+  */
+ #include <linux/config.h>
+-#include <linux/version.h>
+ #undef SERIAL_PARANOIA_CHECK
+ #define SERIAL_DO_RESTART
+--- linux-2.6.0-test6/drivers/char/cyclades.c  2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/char/cyclades.c 2003-10-05 00:33:24.000000000 -0700
+@@ -670,7 +670,6 @@ static char rcsid[] =
+ #include <linux/types.h>
+ #include <linux/kernel.h>
+ #include <linux/pci.h>
+-#include <linux/version.h>
+ #include <linux/stat.h>
+ #include <linux/proc_fs.h>
+--- linux-2.6.0-test6/drivers/char/dsp56k.c    2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/char/dsp56k.c   2003-10-05 00:33:24.000000000 -0700
+@@ -24,7 +24,6 @@
+  */
+ #include <linux/module.h>
+-#include <linux/version.h>
+ #include <linux/slab.h>       /* for kmalloc() and kfree() */
+ #include <linux/sched.h>      /* for struct wait_queue etc */
+ #include <linux/major.h>
+--- linux-2.6.0-test6/drivers/char/dtlk.c      2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/char/dtlk.c     2003-10-05 00:33:24.000000000 -0700
+@@ -48,7 +48,6 @@
+  */
+ #include <linux/module.h>
+-#include <linux/version.h>
+ #define KERNEL
+ #include <linux/types.h>
+--- linux-2.6.0-test6/drivers/char/dz.c        2003-06-14 12:17:57.000000000 -0700
++++ 25/drivers/char/dz.c       2003-10-05 00:33:24.000000000 -0700
+@@ -23,7 +23,6 @@ Qua Jun 27 15:02:26 BRT 2001
+ /* #define DEBUG_DZ 1 */
+-#include <linux/version.h>
+ #include <linux/module.h>
+ #include <linux/config.h>
+--- linux-2.6.0-test6/drivers/char/ftape/compressor/zftape-compress.c  2003-06-14 12:18:32.000000000 -0700
++++ 25/drivers/char/ftape/compressor/zftape-compress.c 2003-10-05 00:33:24.000000000 -0700
+@@ -31,6 +31,7 @@
+  char zftc_rev[] = "$Revision: 1.1.4.1 $";
+  char zftc_dat[] = "$Date: 2003/10/10 09:31:08 $";
++#include <linux/version.h>
+ #include <linux/errno.h>
+ #include <linux/mm.h>
+ #include <linux/module.h>
+--- linux-2.6.0-test6/drivers/char/ftape/lowlevel/fdc-io.c     2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/char/ftape/lowlevel/fdc-io.c    2003-10-05 00:33:24.000000000 -0700
+@@ -30,7 +30,6 @@
+ #include <linux/errno.h>
+ #include <linux/sched.h>
+ #include <linux/ioport.h>
+-#include <linux/version.h>
+ #include <linux/interrupt.h>
+ #include <asm/system.h>
+ #include <asm/io.h>
+--- linux-2.6.0-test6/drivers/char/generic_serial.c    2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/char/generic_serial.c   2003-10-05 00:33:24.000000000 -0700
+@@ -348,7 +348,7 @@ int gs_real_chars_in_buffer(struct tty_s
+ static int gs_wait_tx_flushed (void * ptr, int timeout) 
+ {
+       struct gs_port *port = ptr;
+-      long end_jiffies;
++      unsigned long end_jiffies;
+       int jiffies_to_transmit, charsleft = 0, rv = 0;
+       int rcib;
+--- linux-2.6.0-test6/drivers/char/i8k.c       2003-06-14 12:18:01.000000000 -0700
++++ 25/drivers/char/i8k.c      2003-10-05 00:33:24.000000000 -0700
+@@ -17,7 +17,6 @@
+  */
+ #include <linux/module.h>
+-#include <linux/version.h>
+ #include <linux/types.h>
+ #include <linux/init.h>
+ #include <linux/proc_fs.h>
+--- linux-2.6.0-test6/drivers/char/ip2/i2os.h  2003-07-27 12:14:38.000000000 -0700
++++ 25/drivers/char/ip2/i2os.h 2003-10-05 00:33:24.000000000 -0700
+@@ -25,7 +25,6 @@
+ #include "ip2types.h"
+ #include <asm/io.h>  /* For inb, etc */
+-#include <linux/version.h>
+ //------------------------------------
+ // Defines for I/O instructions:
+--- linux-2.6.0-test6/drivers/char/ip2main.c   2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/char/ip2main.c  2003-10-05 00:33:24.000000000 -0700
+@@ -84,8 +84,6 @@
+ /************/
+ #include <linux/config.h>
+-#include <linux/version.h>
+-
+ #include <linux/ctype.h>
+ #include <linux/string.h>
+ #include <linux/fcntl.h>
+--- linux-2.6.0-test6/drivers/char/isicom.c    2003-08-22 19:23:40.000000000 -0700
++++ 25/drivers/char/isicom.c   2003-10-05 00:33:24.000000000 -0700
+@@ -38,7 +38,6 @@
+  */
+ #include <linux/module.h>
+-#include <linux/version.h>
+ #include <linux/kernel.h>
+ #include <linux/tty.h>
+ #include <linux/termios.h>
+--- linux-2.6.0-test6/drivers/char/istallion.c 2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/char/istallion.c        2003-10-05 00:33:24.000000000 -0700
+@@ -35,7 +35,6 @@
+ #include <linux/serial.h>
+ #include <linux/cdk.h>
+ #include <linux/comstats.h>
+-#include <linux/version.h>
+ #include <linux/istallion.h>
+ #include <linux/ioport.h>
+ #include <linux/delay.h>
+--- linux-2.6.0-test6/drivers/char/Kconfig     2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/char/Kconfig    2003-10-05 00:33:24.000000000 -0700
+@@ -954,6 +954,15 @@ config RAW_DRIVER
+         Once bound, I/O against /dev/raw/rawN uses efficient zero-copy I/O. 
+         See the raw(8) manpage for more details.
++config MAX_RAW_DEVS
++      int "Maximum number of RAW devices to support (1-8192)"
++      depends on RAW_DRIVER
++      default "256"
++      help
++        The maximum number of RAW devices that are supported.
++        Default is 256. Increase this number in case you need lots of
++        raw devices.
++
+ config HANGCHECK_TIMER
+       tristate "Hangcheck timer"
+       depends on X86_64 || X86
+--- linux-2.6.0-test6/drivers/char/keyboard.c  2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/char/keyboard.c 2003-10-05 00:33:38.000000000 -0700
+@@ -1052,6 +1052,9 @@ void kbd_keycode(unsigned int keycode, i
+       }
+       if (sysrq_down && down && !rep) {
+               handle_sysrq(kbd_sysrq_xlate[keycode], regs, tty);
++#ifdef CONFIG_KGDB_SYSRQ
++                sysrq_down = 0;        /* in case we miss the "up" event */
++#endif
+               return;
+       }
+ #endif
+--- linux-2.6.0-test6/drivers/char/lp_old98.c  2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/char/lp_old98.c 2003-10-05 00:33:24.000000000 -0700
+@@ -23,7 +23,6 @@
+ #include <linux/fcntl.h>
+ #include <linux/delay.h>
+ #include <linux/console.h>
+-#include <linux/version.h>
+ #include <linux/fs.h>
+ #include <asm/io.h>
+--- linux-2.6.0-test6/drivers/char/mem.c       2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/char/mem.c      2003-10-05 00:36:19.000000000 -0700
+@@ -40,6 +40,7 @@ extern void fbmem_init(void);
+ extern void tapechar_init(void);
+ #endif
++#ifdef pgprot_noncached
+ /*
+  * Architectures vary in how they handle caching for addresses
+  * outside of main memory.
+@@ -65,19 +66,21 @@ static inline int uncached_access(struct
+         && addr >= __pa(high_memory);
+ #elif defined(CONFIG_IA64)
+       /*
+-       * On ia64, we ignore O_SYNC because we cannot tolerate memory attribute aliases.
++       * On ia64, we ignore O_SYNC because we cannot tolerate memory
++       * attribute aliases.
+        */
+       return !(efi_mem_attributes(addr) & EFI_MEMORY_WB);
+ #else
+       /*
+-       * Accessing memory above the top the kernel knows about or through a file pointer
+-       * that was marked O_SYNC will be done non-cached.
++       * Accessing memory above the top the kernel knows about or through a
++       * file pointer that was marked O_SYNC will be done non-cached.
+        */
+       if (file->f_flags & O_SYNC)
+               return 1;
+       return addr >= __pa(high_memory);
+ #endif
+ }
++#endif                /* pgprot_noncached */
+ static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp,
+                           const char * buf, size_t count, loff_t *ppos)
+@@ -159,28 +162,24 @@ static ssize_t write_mem(struct file * f
+       return do_write_mem(file, __va(p), p, buf, count, ppos);
+ }
+-static int mmap_mem(struct file * file, struct vm_area_struct * vma)
++static int mmap_mem(struct file *file, struct vm_area_struct *vma)
+ {
+       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+-      int uncached;
+-      uncached = uncached_access(file, offset);
+ #ifdef pgprot_noncached
+-      if (uncached)
++      if (uncached_access(file, offset))
+               vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ #endif
+-      /* Don't try to swap out physical pages.. */
+-      vma->vm_flags |= VM_RESERVED;
+-
+       /*
+-       * Don't dump addresses that are not real memory to a core file.
++       * Don't try to swap out physical pages..
++       * And treat /dev/mem mappings as "IO" regions: they may not
++       * describe valid pageframes.
+        */
+-      if (uncached)
+-              vma->vm_flags |= VM_IO;
++      vma->vm_flags |= VM_RESERVED|VM_IO;
+-      if (remap_page_range(vma, vma->vm_start, offset, vma->vm_end-vma->vm_start,
+-                           vma->vm_page_prot))
++      if (remap_page_range(vma, vma->vm_start, offset,
++                      vma->vm_end-vma->vm_start, vma->vm_page_prot))
+               return -EAGAIN;
+       return 0;
+ }
+--- linux-2.6.0-test6/drivers/char/misc.c      2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/char/misc.c     2003-10-05 00:33:24.000000000 -0700
+@@ -157,12 +157,11 @@ static int misc_open(struct inode * inod
+               list_for_each_entry(c, &misc_list, list) {
+                       if (c->minor == minor) {
+                               new_fops = fops_get(c->fops);
+-                              if (!new_fops)
+-                                      goto fail;
+                               break;
+                       }
+               }
+-              goto fail;
++              if (!new_fops)
++                      goto fail;
+       }
+       err = 0;
+--- linux-2.6.0-test6/drivers/char/moxa.c      2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/char/moxa.c     2003-10-05 00:33:24.000000000 -0700
+@@ -32,7 +32,6 @@
+ #include <linux/config.h>
+ #include <linux/module.h>
+ #include <linux/types.h>
+-#include <linux/version.h>
+ #include <linux/mm.h>
+ #include <linux/ioport.h>
+ #include <linux/errno.h>
+--- linux-2.6.0-test6/drivers/char/mxser.c     2003-08-08 22:55:11.000000000 -0700
++++ 25/drivers/char/mxser.c    2003-10-05 00:33:24.000000000 -0700
+@@ -39,7 +39,6 @@
+ #include <linux/config.h>
+ #include <linux/module.h>
+-#include <linux/version.h>
+ #include <linux/errno.h>
+ #include <linux/signal.h>
+ #include <linux/sched.h>
+--- linux-2.6.0-test6/drivers/char/n_tty.c     2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/char/n_tty.c    2003-10-05 00:36:15.000000000 -0700
+@@ -974,7 +974,8 @@ do_it_again:
+       /* NOTE: not yet done after every sleep pending a thorough
+          check of the logic of this change. -- jlc */
+       /* don't stop on /dev/console */
+-      if (file->f_op->write != redirected_tty_write && current->tty == tty) {
++      if (file->f_op->write != redirected_tty_write &&
++                      process_tty(current) == tty) {
+               if (tty->pgrp <= 0)
+                       printk("read_chan: tty->pgrp <= 0!\n");
+               else if (process_group(current) != tty->pgrp) {
+--- linux-2.6.0-test6/drivers/char/pcmcia/synclink_cs.c        2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/char/pcmcia/synclink_cs.c       2003-10-05 00:33:24.000000000 -0700
+@@ -37,7 +37,6 @@
+ #include <linux/config.h>     
+ #include <linux/module.h>
+-#include <linux/version.h>
+ #include <linux/errno.h>
+ #include <linux/signal.h>
+ #include <linux/sched.h>
+--- linux-2.6.0-test6/drivers/char/pcxx.c      2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/char/pcxx.c     2003-10-05 00:33:24.000000000 -0700
+@@ -65,7 +65,6 @@
+ #include <linux/tty_driver.h>
+ #include <linux/slab.h>
+ #include <linux/init.h>
+-#include <linux/version.h>
+ #ifndef MODULE
+ #include <linux/ctype.h> /* We only need it for parsing the "digi="-line */
+--- linux-2.6.0-test6/drivers/char/random.c    2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/char/random.c   2003-10-05 00:33:24.000000000 -0700
+@@ -1735,7 +1735,7 @@ random_ioctl(struct inode * inode, struc
+               tmp = kmalloc(size * sizeof(__u32), GFP_KERNEL);
+               if (!tmp)
+-                      return -EFAULT;
++                      return -ENOMEM;
+               spin_lock_irqsave(&random_state->lock, flags);
+               ent_count = random_state->entropy_count;
+--- linux-2.6.0-test6/drivers/char/raw.c       2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/char/raw.c      2003-10-05 00:34:12.000000000 -0700
+@@ -20,8 +20,6 @@
+ #include <asm/uaccess.h>
+-#define MAX_RAW_MINORS        256
+-
+ struct raw_device_data {
+       struct block_device *binding;
+       int inuse;
+@@ -76,9 +74,8 @@ static int raw_open(struct inode *inode,
+                       goto out;
+               }
+               filp->f_flags |= O_DIRECT;
+-              if (++raw_devices[minor].inuse == 1)
+-                      filp->f_dentry->d_inode->i_mapping =
+-                              bdev->bd_inode->i_mapping;
++              filp->f_mapping = bdev->bd_inode->i_mapping;
++              raw_devices[minor].inuse++;
+       }
+       filp->private_data = bdev;
+ out:
+@@ -97,11 +94,7 @@ static int raw_release(struct inode *ino
+       down(&raw_mutex);
+       bdev = raw_devices[minor].binding;
+-      if (--raw_devices[minor].inuse == 0) {
+-              /* Here  inode->i_mapping == bdev->bd_inode->i_mapping  */
+-              inode->i_mapping = &inode->i_data;
+-              inode->i_mapping->backing_dev_info = &default_backing_dev_info;
+-      }
++      --raw_devices[minor].inuse;
+       up(&raw_mutex);
+       bd_release(bdev);
+--- linux-2.6.0-test6/drivers/char/rio/rio_linux.c     2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/char/rio/rio_linux.c    2003-10-05 00:33:24.000000000 -0700
+@@ -53,7 +53,6 @@
+ #include <linux/fcntl.h>
+ #include <linux/major.h>
+ #include <linux/delay.h>
+-#include <linux/version.h>
+ #include <linux/pci.h>
+ #include <linux/slab.h>
+ #include <linux/miscdevice.h>
+--- linux-2.6.0-test6/drivers/char/rocket.c    2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/char/rocket.c   2003-10-05 00:36:15.000000000 -0700
+@@ -85,11 +85,9 @@
+ #include <linux/string.h>
+ #include <linux/fcntl.h>
+ #include <linux/ptrace.h>
+-#include <linux/major.h>
+ #include <linux/ioport.h>
+ #include <linux/delay.h>
+ #include <linux/wait.h>
+-#include <linux/delay.h>
+ #include <linux/pci.h>
+ #include <asm/uaccess.h>
+ #include <asm/atomic.h>
+@@ -955,7 +953,7 @@ static int rp_open(struct tty_struct *tt
+       /*
+        * Info->count is now 1; so it's safe to sleep now.
+        */
+-      info->session = current->session;
++      info->session = process_session(current);
+       info->pgrp = process_group(current);
+       if ((info->flags & ROCKET_INITIALIZED) == 0) {
+--- linux-2.6.0-test6/drivers/char/ser_a2232.c 2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/char/ser_a2232.c        2003-10-05 00:33:24.000000000 -0700
+@@ -703,7 +703,7 @@ static int a2232_init_drivers(void)
+       a2232_driver->name = "ttyY";
+       a2232_driver->major = A2232_NORMAL_MAJOR;
+       a2232_driver->type = TTY_DRIVER_TYPE_SERIAL;
+-      a2232_driver->subtype = SERIAL_TTY_NORMAL;
++      a2232_driver->subtype = SERIAL_TYPE_NORMAL;
+       a2232_driver->init_termios = tty_std_termios;
+       a2232_driver->init_termios.c_cflag =
+               B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+--- linux-2.6.0-test6/drivers/char/serial167.c 2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/char/serial167.c        2003-10-05 00:33:24.000000000 -0700
+@@ -70,7 +70,6 @@
+ #include <linux/types.h>
+ #include <linux/kernel.h>
+-#include <linux/version.h>
+ #include <asm/uaccess.h>
+ #include <linux/init.h>
+--- linux-2.6.0-test6/drivers/char/stallion.c  2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/char/stallion.c 2003-10-05 00:33:24.000000000 -0700
+@@ -28,7 +28,6 @@
+ #include <linux/config.h>
+ #include <linux/module.h>
+-#include <linux/version.h> /* for linux/stallion.h */
+ #include <linux/slab.h>
+ #include <linux/interrupt.h>
+ #include <linux/tty.h>
+--- linux-2.6.0-test6/drivers/char/sx.c        2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/char/sx.c       2003-10-05 00:33:24.000000000 -0700
+@@ -240,7 +240,6 @@
+ #include "sxwindow.h"
+ #include <linux/generic_serial.h>
+-#include <asm/uaccess.h>
+ #include "sx.h"
+--- linux-2.6.0-test6/drivers/char/sysrq.c     2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/char/sysrq.c    2003-10-05 00:33:38.000000000 -0700
+@@ -35,6 +35,25 @@
+ #include <linux/spinlock.h>
+ #include <asm/ptrace.h>
++#ifdef CONFIG_KGDB_SYSRQ
++
++#define  GDB_OP &kgdb_op
++static void kgdb_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty)
++{
++      printk("kgdb sysrq\n");
++      breakpoint();
++}
++
++static struct sysrq_key_op kgdb_op = {
++      .handler        = kgdb_sysrq,
++      .help_msg       = "kGdb|Fgdb",
++      .action_msg     = "Debug breakpoint\n",
++};
++
++#else
++#define  GDB_OP NULL
++#endif
++
+ extern void reset_vc(unsigned int);
+@@ -238,8 +257,8 @@ static struct sysrq_key_op *sysrq_key_ta
+ /* c */ NULL,
+ /* d */       NULL,
+ /* e */       &sysrq_term_op,
+-/* f */       NULL,
+-/* g */       NULL,
++/* f */       GDB_OP,
++/* g */       GDB_OP,
+ /* h */       NULL,
+ /* i */       &sysrq_kill_op,
+ /* j */       NULL,
+--- linux-2.6.0-test6/drivers/char/toshiba.c   2003-06-14 12:18:34.000000000 -0700
++++ 25/drivers/char/toshiba.c  2003-10-05 00:33:24.000000000 -0700
+@@ -57,7 +57,6 @@
+ #define TOSH_DEBUG 0
+ #include <linux/module.h>
+-#include <linux/version.h>
+ #include <linux/kernel.h>
+ #include <linux/sched.h>
+ #include <linux/types.h>
+@@ -85,7 +84,6 @@ static int tosh_fn = 0;
+ MODULE_PARM(tosh_fn, "i");
+-static int tosh_get_info(char *, char **, off_t, int);
+ static int tosh_ioctl(struct inode *, struct file *, unsigned int,
+       unsigned long);
+@@ -104,6 +102,7 @@ static struct miscdevice tosh_device = {
+ /*
+  * Read the Fn key status
+  */
++#ifdef CONFIG_PROC_FS
+ static int tosh_fn_status(void)
+ {
+         unsigned char scan;
+@@ -120,6 +119,7 @@ static int tosh_fn_status(void)
+         return (int) scan;
+ }
++#endif
+ /*
+@@ -291,6 +291,7 @@ static int tosh_ioctl(struct inode *ip, 
+ /*
+  * Print the information for /proc/toshiba
+  */
++#ifdef CONFIG_PROC_FS
+ int tosh_get_info(char *buffer, char **start, off_t fpos, int length)
+ {
+       char *temp;
+@@ -319,6 +320,7 @@ int tosh_get_info(char *buffer, char **s
+       return temp-buffer;
+ }
++#endif
+ /*
+--- linux-2.6.0-test6/drivers/char/tty_io.c    2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/char/tty_io.c   2003-10-05 00:36:15.000000000 -0700
+@@ -314,7 +314,7 @@ struct tty_driver *get_tty_driver(dev_t 
+  */
+ int tty_check_change(struct tty_struct * tty)
+ {
+-      if (current->tty != tty)
++      if (process_tty(current) != tty)
+               return 0;
+       if (tty->pgrp <= 0) {
+               printk(KERN_WARNING "tty_check_change: tty->pgrp <= 0!\n");
+@@ -481,14 +481,14 @@ void do_tty_hangup(void *data)
+       if (tty->session > 0) {
+               struct list_head *l;
+               for_each_task_pid(tty->session, PIDTYPE_SID, p, l, pid) {
+-                      if (p->tty == tty)
+-                              p->tty = NULL;
+-                      if (!p->leader)
++                      if (process_tty(p) == tty)
++                              p->signal->tty = NULL;
++                      if (!process_session_leader(p))
+                               continue;
+                       send_group_sig_info(SIGHUP, SEND_SIG_PRIV, p);
+                       send_group_sig_info(SIGCONT, SEND_SIG_PRIV, p);
+                       if (tty->pgrp > 0)
+-                              p->tty_old_pgrp = tty->pgrp;
++                              p->signal->tty_old_pgrp = tty->pgrp;
+               }
+       }
+       read_unlock(&tasklist_lock);
+@@ -565,15 +565,15 @@ void disassociate_ctty(int on_exit)
+       lock_kernel();
+-      tty = current->tty;
++      tty = process_tty(current);
+       if (tty) {
+               tty_pgrp = tty->pgrp;
+               if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY)
+                       tty_vhangup(tty);
+       } else {
+-              if (current->tty_old_pgrp) {
+-                      kill_pg(current->tty_old_pgrp, SIGHUP, on_exit);
+-                      kill_pg(current->tty_old_pgrp, SIGCONT, on_exit);
++              if (current->signal->tty_old_pgrp) {
++                      kill_pg(current->signal->tty_old_pgrp, SIGHUP, on_exit);
++                      kill_pg(current->signal->tty_old_pgrp, SIGCONT, on_exit);
+               }
+               unlock_kernel();        
+               return;
+@@ -584,13 +584,13 @@ void disassociate_ctty(int on_exit)
+                       kill_pg(tty_pgrp, SIGCONT, on_exit);
+       }
+-      current->tty_old_pgrp = 0;
++      current->signal->tty_old_pgrp = 0;
+       tty->session = 0;
+       tty->pgrp = -1;
+       read_lock(&tasklist_lock);
+-      for_each_task_pid(current->session, PIDTYPE_SID, p, l, pid)
+-              p->tty = NULL;
++      for_each_task_pid(process_session(current), PIDTYPE_SID, p, l, pid)
++              p->signal->tty = NULL;
+       read_unlock(&tasklist_lock);
+       unlock_kernel();
+ }
+@@ -1218,10 +1218,10 @@ static void release_dev(struct file * fi
+               read_lock(&tasklist_lock);
+               for_each_task_pid(tty->session, PIDTYPE_SID, p, l, pid)
+-                      p->tty = NULL;
++                      p->signal->tty = NULL;
+               if (o_tty)
+                       for_each_task_pid(o_tty->session, PIDTYPE_SID, p,l, pid)
+-                              p->tty = NULL;
++                              p->signal->tty = NULL;
+               read_unlock(&tasklist_lock);
+       }
+@@ -1292,10 +1292,10 @@ static int tty_open(struct inode * inode
+ retry_open:
+       noctty = filp->f_flags & O_NOCTTY;
+       if (device == MKDEV(TTYAUX_MAJOR,0)) {
+-              if (!current->tty)
++              if (!process_tty(current))
+                       return -ENXIO;
+-              driver = current->tty->driver;
+-              index = current->tty->index;
++              driver = process_tty(current)->driver;
++              index = process_tty(current)->index;
+               filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
+               /* noctty = 1; */
+               goto got_driver;
+@@ -1389,15 +1389,13 @@ got_driver:
+                       filp->f_op = &tty_fops;
+               goto retry_open;
+       }
+-      if (!noctty &&
+-          current->leader &&
+-          !current->tty &&
+-          tty->session == 0) {
++      if (!noctty && process_session_leader(current) &&
++                      !process_tty(current) && tty->session == 0) {
+               task_lock(current);
+-              current->tty = tty;
++              current->signal->tty = tty;
+               task_unlock(current);
+-              current->tty_old_pgrp = 0;
+-              tty->session = current->session;
++              current->signal->tty_old_pgrp = 0;
++              tty->session = process_session(current);
+               tty->pgrp = process_group(current);
+       }
+       return 0;
+@@ -1455,7 +1453,7 @@ static int tiocsti(struct tty_struct *tt
+ {
+       char ch, mbz = 0;
+-      if ((current->tty != tty) && !capable(CAP_SYS_ADMIN))
++      if ((process_tty(current) != tty) && !capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       if (get_user(ch, arg))
+               return -EFAULT;
+@@ -1541,14 +1539,14 @@ static int tiocsctty(struct tty_struct *
+       struct pid *pid;
+       task_t *p;
+-      if (current->leader &&
+-          (current->session == tty->session))
++      if (process_session_leader(current) &&
++                      (process_session(current) == tty->session))
+               return 0;
+       /*
+        * The process must be a session leader and
+        * not have a controlling tty already.
+        */
+-      if (!current->leader || current->tty)
++      if (!process_session_leader(current) || process_tty(current))
+               return -EPERM;
+       if (tty->session > 0) {
+               /*
+@@ -1562,16 +1560,16 @@ static int tiocsctty(struct tty_struct *
+                       read_lock(&tasklist_lock);
+                       for_each_task_pid(tty->session, PIDTYPE_SID, p, l, pid)
+-                              p->tty = NULL;
++                              p->signal->tty = NULL;
+                       read_unlock(&tasklist_lock);
+               } else
+                       return -EPERM;
+       }
+       task_lock(current);
+-      current->tty = tty;
++      current->signal->tty = tty;
+       task_unlock(current);
+-      current->tty_old_pgrp = 0;
+-      tty->session = current->session;
++      current->signal->tty_old_pgrp = 0;
++      tty->session = process_session(current);
+       tty->pgrp = process_group(current);
+       return 0;
+ }
+@@ -1582,12 +1580,13 @@ static int tiocgpgrp(struct tty_struct *
+        * (tty == real_tty) is a cheap way of
+        * testing if the tty is NOT a master pty.
+        */
+-      if (tty == real_tty && current->tty != real_tty)
++      if (tty == real_tty && process_tty(current) != real_tty)
+               return -ENOTTY;
+       return put_user(real_tty->pgrp, arg);
+ }
+-static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t *arg)
++static int tiocspgrp(struct tty_struct *tty,
++                      struct tty_struct *real_tty, pid_t *arg)
+ {
+       pid_t pgrp;
+       int retval = tty_check_change(real_tty);
+@@ -1596,15 +1595,14 @@ static int tiocspgrp(struct tty_struct *
+               return -ENOTTY;
+       if (retval)
+               return retval;
+-      if (!current->tty ||
+-          (current->tty != real_tty) ||
+-          (real_tty->session != current->session))
++      if (!process_tty(current) || (process_tty(current) != real_tty) ||
++                      (real_tty->session != process_session(current)))
+               return -ENOTTY;
+       if (get_user(pgrp, (pid_t *) arg))
+               return -EFAULT;
+       if (pgrp < 0)
+               return -EINVAL;
+-      if (session_of_pgrp(pgrp) != current->session)
++      if (session_of_pgrp(pgrp) != process_session(current))
+               return -EPERM;
+       real_tty->pgrp = pgrp;
+       return 0;
+@@ -1616,7 +1614,7 @@ static int tiocgsid(struct tty_struct *t
+        * (tty == real_tty) is a cheap way of
+        * testing if the tty is NOT a master pty.
+       */
+-      if (tty == real_tty && current->tty != real_tty)
++      if (tty == real_tty && process_tty(current) != real_tty)
+               return -ENOTTY;
+       if (real_tty->session <= 0)
+               return -ENOTTY;
+@@ -1774,12 +1772,12 @@ int tty_ioctl(struct inode * inode, stru
+                       clear_bit(TTY_EXCLUSIVE, &tty->flags);
+                       return 0;
+               case TIOCNOTTY:
+-                      if (current->tty != tty)
++                      if (process_tty(current) != tty)
+                               return -ENOTTY;
+-                      if (current->leader)
++                      if (process_session_leader(current))
+                               disassociate_ctty(0);
+                       task_lock(current);
+-                      current->tty = NULL;
++                      current->signal->tty = NULL;
+                       task_unlock(current);
+                       return 0;
+               case TIOCSCTTY:
+@@ -1883,10 +1881,10 @@ static void __do_SAK(void *arg)
+               tty->driver->flush_buffer(tty);
+       read_lock(&tasklist_lock);
+       for_each_task_pid(session, PIDTYPE_SID, p, l, pid) {
+-              if (p->tty == tty || session > 0) {
++              if (process_tty(p) == tty || session > 0) {
+                       printk(KERN_NOTICE "SAK: killed process %d"
+-                          " (%s): p->session==tty->session\n",
+-                          p->pid, p->comm);
++                              " (%s): process_session(p)==tty->session\n",
++                              p->pid, p->comm);
+                       send_sig(SIGKILL, p, 1);
+                       continue;
+               }
+--- linux-2.6.0-test6/drivers/char/vme_scc.c   2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/char/vme_scc.c  2003-10-05 00:33:24.000000000 -0700
+@@ -29,7 +29,6 @@
+ #include <linux/fcntl.h>
+ #include <linux/major.h>
+ #include <linux/delay.h>
+-#include <linux/version.h>
+ #include <linux/slab.h>
+ #include <linux/miscdevice.h>
+ #include <linux/console.h>
+--- linux-2.6.0-test6/drivers/char/vt.c        2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/char/vt.c       2003-10-05 00:36:15.000000000 -0700
+@@ -2226,7 +2226,7 @@ int tioclinux(struct tty_struct *tty, un
+       if (tty->driver->type != TTY_DRIVER_TYPE_CONSOLE)
+               return -EINVAL;
+-      if (current->tty != tty && !capable(CAP_SYS_ADMIN))
++      if (process_tty(current) != tty && !capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       if (get_user(type, (char *)arg))
+               return -EFAULT;
+--- linux-2.6.0-test6/drivers/char/vt_ioctl.c  2003-08-22 19:23:40.000000000 -0700
++++ 25/drivers/char/vt_ioctl.c 2003-10-05 00:36:15.000000000 -0700
+@@ -380,7 +380,7 @@ int vt_ioctl(struct tty_struct *tty, str
+        * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
+        */
+       perm = 0;
+-      if (current->tty == tty || capable(CAP_SYS_TTY_CONFIG))
++      if (process_tty(current) == tty || capable(CAP_SYS_TTY_CONFIG))
+               perm = 1;
+  
+       kbd = kbd_table + console;
+@@ -1188,4 +1188,3 @@ void change_console(unsigned int new_con
+       complete_change_console(new_console);
+ }
+-
+--- linux-2.6.0-test6/drivers/char/watchdog/amd7xx_tco.c       2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/char/watchdog/amd7xx_tco.c      2003-10-05 00:33:24.000000000 -0700
+@@ -19,13 +19,11 @@
+ #include <linux/config.h>
+ #include <linux/module.h>
+-#include <linux/version.h>
+ #include <linux/kernel.h>
+ #include <linux/miscdevice.h>
+ #include <linux/watchdog.h>
+ #include <linux/ioport.h>
+ #include <linux/spinlock.h>
+-#include <linux/ioport.h>
+ #include <asm/semaphore.h>
+ #include <asm/io.h>
+ #include <asm/uaccess.h>
+--- linux-2.6.0-test6/drivers/cpufreq/cpufreq.c        2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/cpufreq/cpufreq.c       2003-10-05 00:36:14.000000000 -0700
+@@ -449,6 +449,9 @@ static int cpufreq_remove_dev (struct sy
+       if (!kobject_get(&data->kobj))
+               return -EFAULT;
++      if (cpufreq_driver->target)
++              __cpufreq_governor(data, CPUFREQ_GOV_STOP);
++
+       kobject_unregister(&data->kobj);
+       kobject_put(&data->kobj);
+@@ -459,9 +462,6 @@ static int cpufreq_remove_dev (struct sy
+        */
+       wait_for_completion(&data->kobj_unregister);
+-      if (cpufreq_driver->target)
+-              __cpufreq_governor(data, CPUFREQ_GOV_STOP);
+-
+       if (cpufreq_driver->exit)
+               cpufreq_driver->exit(data);
+--- linux-2.6.0-test6/drivers/eisa/eisa-bus.c  2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/eisa/eisa-bus.c 2003-10-05 00:36:11.000000000 -0700
+@@ -33,23 +33,22 @@ static struct eisa_device_info __initdat
+ #endif
+ #define EISA_MAX_FORCED_DEV 16
+-#define EISA_FORCED_OFFSET  2
+-static int enable_dev[EISA_MAX_FORCED_DEV + EISA_FORCED_OFFSET]  = { 1, EISA_MAX_FORCED_DEV, };
+-static int disable_dev[EISA_MAX_FORCED_DEV + EISA_FORCED_OFFSET] = { 1, EISA_MAX_FORCED_DEV, };
++static int enable_dev[EISA_MAX_FORCED_DEV];
++static int enable_dev_count;
++static int disable_dev[EISA_MAX_FORCED_DEV];
++static int disable_dev_count;
+ static int is_forced_dev (int *forced_tab,
++                        int forced_count,
+                         struct eisa_root_device *root,
+                         struct eisa_device *edev)
+ {
+       int i, x;
+-      for (i = 0; i < EISA_MAX_FORCED_DEV; i++) {
+-              if (!forced_tab[EISA_FORCED_OFFSET + i])
+-                      return 0;
+-
++      for (i = 0; i < forced_count; i++) {
+               x = (root->bus_nr << 8) | edev->slot;
+-              if (forced_tab[EISA_FORCED_OFFSET + i] == x)
++              if (forced_tab[i] == x)
+                       return 1;
+       }
+@@ -198,10 +197,10 @@ static int __init eisa_init_device (stru
+ #endif
+       }
+-      if (is_forced_dev (enable_dev, root, edev))
++      if (is_forced_dev (enable_dev, enable_dev_count, root, edev))
+               edev->state = EISA_CONFIG_ENABLED | EISA_CONFIG_FORCED;
+       
+-      if (is_forced_dev (disable_dev, root, edev))
++      if (is_forced_dev (disable_dev, disable_dev_count, root, edev))
+               edev->state = EISA_CONFIG_FORCED;
+       return 0;
+@@ -418,20 +417,13 @@ static int __init eisa_init (void)
+       return 0;
+ }
+-/* Couldn't use intarray with checking on... :-( */
+-#undef  param_check_intarray
+-#define param_check_intarray(name, p)
+-
+-module_param(enable_dev,  intarray, 0444);
+-module_param(disable_dev, intarray, 0444);
++module_param_array(enable_dev, int, enable_dev_count, 0444);
++module_param_array(disable_dev, int, disable_dev_count, 0444);
+ postcore_initcall (eisa_init);
+-#ifndef CONFIG_EISA_ALWAYS
+-int EISA_bus;
+-EXPORT_SYMBOL(EISA_bus);
+-#endif
+-
++int EISA_bus;         /* for legacy drivers */
++EXPORT_SYMBOL (EISA_bus);
+ EXPORT_SYMBOL (eisa_bus_type);
+ EXPORT_SYMBOL (eisa_driver_register);
+ EXPORT_SYMBOL (eisa_driver_unregister);
+--- linux-2.6.0-test6/drivers/i2c/busses/Kconfig       2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/i2c/busses/Kconfig      2003-10-05 00:33:24.000000000 -0700
+@@ -285,7 +285,7 @@ config I2C_VELLEMAN
+         will be called i2c-velleman.
+ config I2C_VIA
+-      tristate "VIA 82C58B"
++      tristate "VIA 82C586B"
+       depends on I2C_ALGOBIT && PCI && EXPERIMENTAL
+       help
+--- linux-2.6.0-test6/drivers/i2c/i2c-sensor.c 2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/i2c/i2c-sensor.c        2003-10-05 00:33:24.000000000 -0700
+@@ -133,7 +133,7 @@ int i2c_detect(struct i2c_adapter *adapt
+                    i += 2) {
+                       if (((adapter_id == address_data->probe[i]) ||
+                            ((address_data->
+-                             probe[i] == ANY_I2C_BUS) & !is_isa))
++                             probe[i] == ANY_I2C_BUS) && !is_isa))
+                           && (addr == address_data->probe[i + 1])) {
+                               dev_dbg(&adapter->dev, "found probe parameter for adapter %d, addr %04x\n", adapter_id, addr);
+                               found = 1;
+@@ -141,7 +141,7 @@ int i2c_detect(struct i2c_adapter *adapt
+               }
+               for (i = 0; !found && (address_data->probe_range[i] != I2C_CLIENT_END); i += 3) {
+                       if ( ((adapter_id == address_data->probe_range[i]) ||
+-                            ((address_data->probe_range[i] == ANY_I2C_BUS) & !is_isa)) &&
++                            ((address_data->probe_range[i] == ANY_I2C_BUS) && !is_isa)) &&
+                            (addr >= address_data->probe_range[i + 1]) &&
+                            (addr <= address_data->probe_range[i + 2])) {
+                               found = 1;
+--- linux-2.6.0-test6/drivers/ide/ide.c        2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/ide/ide.c       2003-10-05 00:33:58.000000000 -0700
+@@ -457,7 +457,7 @@ void ide_probe_module (void)
+ EXPORT_SYMBOL(ide_probe_module);
+-static int ide_open (struct inode * inode, struct file * filp)
++static int ide_open (struct block_device *bdev, struct file * filp)
+ {
+       return -ENXIO;
+ }
+@@ -1800,27 +1800,26 @@ static int __init match_parm (char *s, c
+ #ifdef CONFIG_BLK_DEV_PDC4030
+ static int __initdata probe_pdc4030;
+-extern void init_pdc4030(void);
+ #endif
+ #ifdef CONFIG_BLK_DEV_ALI14XX
+ static int __initdata probe_ali14xx;
+-extern void init_ali14xx(void);
++extern int ali14xx_init(void);
+ #endif
+ #ifdef CONFIG_BLK_DEV_UMC8672
+ static int __initdata probe_umc8672;
+-extern void init_umc8672(void);
++extern int umc8672_init(void);
+ #endif
+ #ifdef CONFIG_BLK_DEV_DTC2278
+ static int __initdata probe_dtc2278;
+-extern void init_dtc2278(void);
++extern int dtc2278_init(void);
+ #endif
+ #ifdef CONFIG_BLK_DEV_HT6560B
+ static int __initdata probe_ht6560b;
+-extern void init_ht6560b(void);
++extern int ht6560b_init(void);
+ #endif
+ #ifdef CONFIG_BLK_DEV_QD65XX
+ static int __initdata probe_qd65xx;
+-extern void init_qd65xx(void);
++extern int qd65xx_init(void);
+ #endif
+ static int __initdata is_chipset_set[MAX_HWIFS];
+@@ -2238,8 +2237,9 @@ static void __init probe_for_hwifs (void
+ #endif /* CONFIG_BLK_DEV_CMD640 */
+ #ifdef CONFIG_BLK_DEV_PDC4030
+       {
+-              extern int ide_probe_for_pdc4030(void);
+-              (void) ide_probe_for_pdc4030();
++              extern int pdc4030_init(void);
++              if (probe_pdc4030)
++                      (void)pdc4030_init();
+       }
+ #endif /* CONFIG_BLK_DEV_PDC4030 */
+ #ifdef CONFIG_BLK_DEV_IDE_PMAC
+@@ -2595,29 +2595,25 @@ int __init ide_init (void)
+       init_ide_data();
+-#ifdef CONFIG_BLK_DEV_PDC4030
+-      if (probe_pdc4030)
+-              init_pdc4030();
+-#endif
+ #ifdef CONFIG_BLK_DEV_ALI14XX
+       if (probe_ali14xx)
+-              init_ali14xx();
++              (void)ali14xx_init();
+ #endif
+ #ifdef CONFIG_BLK_DEV_UMC8672
+       if (probe_umc8672)
+-              init_umc8672();
++              (void)umc8672_init();
+ #endif
+ #ifdef CONFIG_BLK_DEV_DTC2278
+       if (probe_dtc2278)
+-              init_dtc2278();
++              (void)dtc2278_init();
+ #endif
+ #ifdef CONFIG_BLK_DEV_HT6560B
+       if (probe_ht6560b)
+-              init_ht6560b();
++              (void)ht6560b_init();
+ #endif
+ #ifdef CONFIG_BLK_DEV_QD65XX
+       if (probe_qd65xx)
+-              init_qd65xx();
++              (void)qd65xx_init();
+ #endif
+       initializing = 1;
+--- linux-2.6.0-test6/drivers/ide/ide-cd.c     2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/ide/ide-cd.c    2003-10-05 00:34:01.000000000 -0700
+@@ -3331,39 +3331,38 @@ static ide_driver_t ide_cdrom_driver = {
+       .complete_power_step    = ide_cdrom_complete_power_step,
+ };
+-static int idecd_open(struct inode * inode, struct file * file)
++static int idecd_open(struct block_device *bdev, struct file * file)
+ {
+-      ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;
++      ide_drive_t *drive = bdev->bd_disk->private_data;
+       struct cdrom_info *info = drive->driver_data;
+       int rc = -ENOMEM;
+       drive->usage++;
+       if (!info->buffer)
+               info->buffer = (char *) kmalloc(SECTOR_BUFFER_SIZE, GFP_KERNEL);
+-        if (!info->buffer || (rc = cdrom_open(&info->devinfo, inode, file)))
++        if (!info->buffer || (rc = cdrom_open(&info->devinfo, bdev, file)))
+               drive->usage--;
+       return rc;
+ }
+-static int idecd_release(struct inode * inode, struct file * file)
++static int idecd_release(struct gendisk *disk)
+ {
+-      ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;
++      ide_drive_t *drive = disk->private_data;
+       struct cdrom_info *info = drive->driver_data;
+-      cdrom_release (&info->devinfo, file);
++      cdrom_release(&info->devinfo);
+       drive->usage--;
+       return 0;
+ }
+-static int idecd_ioctl (struct inode *inode, struct file *file,
++static int idecd_ioctl (struct block_device *bdev, struct file *file,
+                       unsigned int cmd, unsigned long arg)
+ {
+-      struct block_device *bdev = inode->i_bdev;
+       ide_drive_t *drive = bdev->bd_disk->private_data;
+       int err = generic_ide_ioctl(bdev, cmd, arg);
+       if (err == -EINVAL) {
+               struct cdrom_info *info = drive->driver_data;
+-              err = cdrom_ioctl(&info->devinfo, inode, cmd, arg);
++              err = cdrom_ioctl(&info->devinfo, bdev, cmd, arg);
+       }
+       return err;
+ }
+--- linux-2.6.0-test6/drivers/ide/ide-disk.c   2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/ide/ide-disk.c  2003-10-05 00:34:01.000000000 -0700
+@@ -1734,9 +1734,9 @@ static ide_driver_t idedisk_driver = {
+       .complete_power_step    = idedisk_complete_power_step,
+ };
+-static int idedisk_open(struct inode *inode, struct file *filp)
++static int idedisk_open(struct block_device *bdev, struct file *filp)
+ {
+-      ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;
++      ide_drive_t *drive = bdev->bd_disk->private_data;
+       drive->usage++;
+       if (drive->removable && drive->usage == 1) {
+               ide_task_t args;
+@@ -1744,7 +1744,7 @@ static int idedisk_open(struct inode *in
+               memset(&args, 0, sizeof(ide_task_t));
+               args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORLOCK;
+               args.command_type = ide_cmd_type_parser(&args);
+-              check_disk_change(inode->i_bdev);
++              check_disk_change(bdev);
+               /*
+                * Ignore the return code from door_lock,
+                * since the open() has already succeeded,
+@@ -1782,9 +1782,9 @@ static int ide_cacheflush_p(ide_drive_t 
+       return 0;
+ }
+-static int idedisk_release(struct inode *inode, struct file *filp)
++static int idedisk_release(struct gendisk *disk)
+ {
+-      ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;
++      ide_drive_t *drive = disk->private_data;
+       if (drive->removable && drive->usage == 1) {
+               ide_task_t args;
+               memset(&args, 0, sizeof(ide_task_t));
+@@ -1798,10 +1798,9 @@ static int idedisk_release(struct inode 
+       return 0;
+ }
+-static int idedisk_ioctl(struct inode *inode, struct file *file,
++static int idedisk_ioctl(struct block_device *bdev, struct file *file,
+                       unsigned int cmd, unsigned long arg)
+ {
+-      struct block_device *bdev = inode->i_bdev;
+       return generic_ide_ioctl(bdev, cmd, arg);
+ }
+--- linux-2.6.0-test6/drivers/ide/ide-floppy.c 2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/ide/ide-floppy.c        2003-10-05 00:34:01.000000000 -0700
+@@ -156,7 +156,6 @@ typedef struct idefloppy_packet_command_
+       int request_transfer;                   /* Bytes to transfer */
+       int actually_transferred;               /* Bytes actually transferred */
+       int buffer_size;                        /* Size of our data buffer */
+-      char *b_data;                           /* Pointer which runs on the buffers */
+       int b_count;                            /* Missing/Available data on the current buffer */
+       struct request *rq;                     /* The corresponding request */
+       u8 *buffer;                             /* Data buffer */
+@@ -515,9 +514,6 @@ typedef struct {
+       u8              reserved[4];
+ } idefloppy_mode_parameter_header_t;
+-#define IDEFLOPPY_MIN(a,b)    ((a)<(b) ? (a):(b))
+-#define       IDEFLOPPY_MAX(a,b)      ((a)>(b) ? (a):(b))
+-
+ /*
+  *    Too bad. The drive wants to send us data which we are not ready to accept.
+  *    Just throw it away.
+@@ -575,59 +571,68 @@ static int idefloppy_do_end_request(ide_
+ static void idefloppy_input_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, unsigned int bcount)
+ {
+       struct request *rq = pc->rq;
+-      struct bio *bio = rq->bio;
+-      int count;
++      struct bio_vec *bvec;
++      struct bio *bio;
++      unsigned long flags;
++      char *data;
++      int count, i, done = 0;
++
++      rq_for_each_bio(bio, rq) {
++              bio_for_each_segment(bvec, bio, i) {
++                      if (!bcount)
++                              break;
++
++                      count = min(bvec->bv_len, bcount);
++
++                      data = bvec_kmap_irq(bvec, &flags);
++                      atapi_input_bytes(drive, data, count);
++                      bvec_kunmap_irq(data, &flags);
+-      while (bcount) {
+-              if (pc->b_count == bio->bi_size) {
+-                      rq->sector += rq->current_nr_sectors;
+-                      rq->nr_sectors -= rq->current_nr_sectors;
+-                      idefloppy_do_end_request(drive, 1, 0);
+-                      if ((bio = rq->bio) != NULL)
+-                              pc->b_count = 0;
+-              }
+-              if (bio == NULL) {
+-                      printk(KERN_ERR "%s: bio == NULL in "
+-                              "idefloppy_input_buffers, bcount == %d\n",
+-                              drive->name, bcount);
+-                      idefloppy_discard_data(drive, bcount);
+-                      return;
+-              }
+-              count = IDEFLOPPY_MIN(bio->bi_size - pc->b_count, bcount);
+-              atapi_input_bytes(drive, bio_data(bio) + pc->b_count, count);
+-              bcount -= count;
+-              pc->b_count += count;
++                      bcount -= count;
++                      pc->b_count += count;
++                      done += count;
++              }
++      }
++
++      idefloppy_do_end_request(drive, 1, done >> 9);
++
++      if (bcount) {
++              printk(KERN_ERR "%s: leftover data in idefloppy_input_buffers, bcount == %d\n", drive->name, bcount);
++              idefloppy_discard_data(drive, bcount);
+       }
+ }
+ static void idefloppy_output_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, unsigned int bcount)
+ {
+       struct request *rq = pc->rq;
+-      struct bio *bio = rq->bio;
+-      int count;
+-      
+-      while (bcount) {
+-              if (!pc->b_count) {
+-                      rq->sector += rq->current_nr_sectors;
+-                      rq->nr_sectors -= rq->current_nr_sectors;
+-                      idefloppy_do_end_request(drive, 1, 0);
+-                      if ((bio = rq->bio) != NULL) {
+-                              pc->b_data = bio_data(bio);
+-                              pc->b_count = bio->bi_size;
+-                      }
++      struct bio *bio;
++      struct bio_vec *bvec;
++      unsigned long flags;
++      int count, i, done = 0;
++      char *data;
++
++      rq_for_each_bio(bio, rq) {
++              bio_for_each_segment(bvec, bio, i) {
++                      if (!bcount)
++                              break;
++
++                      count = min(bvec->bv_len, bcount);
++
++                      data = bvec_kmap_irq(bvec, &flags);
++                      atapi_output_bytes(drive, data, count);
++                      bvec_kunmap_irq(data, &flags);
++
++                      bcount -= count;
++                      pc->b_count += count;
++                      done += count;
+               }
+-              if (bio == NULL) {
+-                      printk(KERN_ERR "%s: bio == NULL in "
+-                              "idefloppy_output_buffers, bcount == %d\n",
+-                              drive->name, bcount);
+-                      idefloppy_write_zeros(drive, bcount);
+-                      return;
+-              }
+-              count = IDEFLOPPY_MIN(pc->b_count, bcount);
+-              atapi_output_bytes(drive, pc->b_data, count);
+-              bcount -= count;
+-              pc->b_data += count;
+-              pc->b_count -= count;
++      }
++
++      idefloppy_do_end_request(drive, 1, done >> 9);
++
++      if (bcount) {
++              printk(KERN_ERR "%s: leftover data in idefloppy_output_buffers, bcount == %d\n", drive->name, bcount);
++              idefloppy_write_zeros(drive, bcount);
+       }
+ }
+@@ -732,8 +737,6 @@ static void idefloppy_init_pc (idefloppy
+       pc->request_transfer = 0;
+       pc->buffer = pc->pc_buffer;
+       pc->buffer_size = IDEFLOPPY_PC_BUFFER_SIZE;
+-      pc->b_data = NULL;
+-//    pc->bio = NULL;
+       pc->callback = &idefloppy_pc_callback;
+ }
+@@ -1199,7 +1202,6 @@ static void idefloppy_create_rw_cmd (ide
+       put_unaligned(htonl(block), (unsigned int *) &pc->c[2]);
+       pc->callback = &idefloppy_rw_callback;
+       pc->rq = rq;
+-      pc->b_data = rq->buffer;
+       pc->b_count = cmd == READ ? 0 : rq->bio->bi_size;
+       if (rq->flags & REQ_RW)
+               set_bit(PC_WRITING, &pc->flags);
+@@ -1864,9 +1866,9 @@ static ide_driver_t idefloppy_driver = {
+       .drives                 = LIST_HEAD_INIT(idefloppy_driver.drives),
+ };
+-static int idefloppy_open(struct inode *inode, struct file *filp)
++static int idefloppy_open(struct block_device *bdev, struct file *filp)
+ {
+-      ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;
++      ide_drive_t *drive = bdev->bd_disk->private_data;
+       idefloppy_floppy_t *floppy = drive->driver_data;
+       idefloppy_pc_t pc;
+@@ -1906,7 +1908,7 @@ static int idefloppy_open(struct inode *
+                       idefloppy_create_prevent_cmd(&pc, 1);
+                       (void) idefloppy_queue_pc_tail(drive, &pc);
+               }
+-              check_disk_change(inode->i_bdev);
++              check_disk_change(bdev);
+       } else if (test_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags)) {
+               drive->usage--;
+               return -EBUSY;
+@@ -1914,9 +1916,9 @@ static int idefloppy_open(struct inode *
+       return 0;
+ }
+-static int idefloppy_release(struct inode *inode, struct file *filp)
++static int idefloppy_release(struct gendisk *disk)
+ {
+-      ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;
++      ide_drive_t *drive = disk->private_data;
+       idefloppy_pc_t pc;
+       
+       debug_log(KERN_INFO "Reached idefloppy_release\n");
+@@ -1936,10 +1938,9 @@ static int idefloppy_release(struct inod
+       return 0;
+ }
+-static int idefloppy_ioctl(struct inode *inode, struct file *file,
++static int idefloppy_ioctl(struct block_device *bdev, struct file *file,
+                       unsigned int cmd, unsigned long arg)
+ {
+-      struct block_device *bdev = inode->i_bdev;
+       ide_drive_t *drive = bdev->bd_disk->private_data;
+       idefloppy_floppy_t *floppy = drive->driver_data;
+       int err = generic_ide_ioctl(bdev, cmd, arg);
+--- linux-2.6.0-test6/drivers/ide/ide-proc.c   2003-06-14 12:18:22.000000000 -0700
++++ 25/drivers/ide/ide-proc.c  2003-10-05 00:33:24.000000000 -0700
+@@ -522,7 +522,8 @@ int proc_ide_write_settings
+                       if (*p != ':')
+                               goto parse_error;
+                       len = IDE_MIN(p - start, MAX_LEN);
+-                      strlcpy(name, start, IDE_MIN(len, MAX_LEN));
++                      strncpy(name, start, IDE_MIN(len, MAX_LEN));
++                      name[len] = 0;
+                       if (n > 0) {
+                               --n;
+--- linux-2.6.0-test6/drivers/ide/ide-tape.c   2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/ide/ide-tape.c  2003-10-05 00:34:01.000000000 -0700
+@@ -6338,24 +6338,23 @@ static struct file_operations idetape_fo
+       .release        = idetape_chrdev_release,
+ };
+-static int idetape_open(struct inode *inode, struct file *filp)
++static int idetape_open(struct block_device *bdev, struct file *filp)
+ {
+-      ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;
++      ide_drive_t *drive = bdev->bd_disk->private_data;
+       drive->usage++;
+       return 0;
+ }
+-static int idetape_release(struct inode *inode, struct file *filp)
++static int idetape_release(struct gendisk *disk)
+ {
+-      ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;
++      ide_drive_t *drive = disk->private_data;
+       drive->usage--;
+       return 0;
+ }
+-static int idetape_ioctl(struct inode *inode, struct file *file,
++static int idetape_ioctl(struct block_device *bdev, struct file *file,
+                       unsigned int cmd, unsigned long arg)
+ {
+-      struct block_device *bdev = inode->i_bdev;
+       ide_drive_t *drive = bdev->bd_disk->private_data;
+       int err = generic_ide_ioctl(bdev, cmd, arg);
+       if (err == -EINVAL)
+--- linux-2.6.0-test6/drivers/ide/Kconfig      2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/ide/Kconfig     2003-10-05 00:36:28.000000000 -0700
+@@ -740,6 +740,13 @@ config BLK_DEV_SVWKS
+         This driver adds PIO/(U)DMA support for the ServerWorks OSB4/CSB5
+         chipsets.
++config BLK_DEV_SGIIOC4
++      tristate "Silicon Graphics IOC4 chipset support"
++      help
++        This driver adds PIO & MultiMode DMA-2 support for the SGI IOC4
++        chipset.  Please say Y here, if you have an Altix System from
++        Silicon Graphics Inc.
++
+ config BLK_DEV_SIIMAGE
+       tristate "Silicon Image chipset support"
+       help
+--- linux-2.6.0-test6/drivers/ide/legacy/ali14xx.c     2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/ide/legacy/ali14xx.c    2003-10-05 00:33:24.000000000 -0700
+@@ -198,22 +198,12 @@ static int __init initRegisters (void) {
+       return t;
+ }
+-int __init probe_ali14xx (void)
++static int __init ali14xx_probe(void)
+ {
+-      /* auto-detect IDE controller port */
+-      if (!findPort()) {
+-              printk(KERN_ERR "ali14xx: not found.\n");
+-              return 1;
+-      }
++      ide_hwif_t *hwif, *mate;
+-      printk(KERN_DEBUG "ali14xx: base= 0x%03x, regOn = 0x%02x.\n", basePort, regOn);
+-      ide_hwifs[0].chipset = ide_ali14xx;
+-      ide_hwifs[1].chipset = ide_ali14xx;
+-      ide_hwifs[0].tuneproc = &ali14xx_tune_drive;
+-      ide_hwifs[1].tuneproc = &ali14xx_tune_drive;
+-      ide_hwifs[0].mate = &ide_hwifs[1];
+-      ide_hwifs[1].mate = &ide_hwifs[0];
+-      ide_hwifs[1].channel = 1;
++      printk(KERN_DEBUG "ali14xx: base=0x%03x, regOn=0x%02x.\n",
++                        basePort, regOn);
+       /* initialize controller registers */
+       if (!initRegisters()) {
+@@ -221,74 +211,59 @@ int __init probe_ali14xx (void)
+               return 1;
+       }
+-      probe_hwif_init(&ide_hwifs[0]);
+-      probe_hwif_init(&ide_hwifs[1]);
++      hwif = &ide_hwifs[0];
++      mate = &ide_hwifs[1];
+-      return 0;
+-}
++      hwif->chipset = ide_ali14xx;
++      hwif->tuneproc = &ali14xx_tune_drive;
++      hwif->mate = mate;
++
++      mate->chipset = ide_ali14xx;
++      mate->tuneproc = &ali14xx_tune_drive;
++      mate->mate = hwif;
++      mate->channel = 1;
+-static void ali14xx_release (void)
+-{
+-      if (ide_hwifs[0].chipset != ide_ali14xx &&
+-          ide_hwifs[1].chipset != ide_ali14xx)
+-              return;
++      probe_hwif_init(hwif);
++      probe_hwif_init(mate);
+-      ide_hwifs[0].chipset = ide_unknown;
+-      ide_hwifs[1].chipset = ide_unknown;
+-      ide_hwifs[0].tuneproc = NULL;
+-      ide_hwifs[1].tuneproc = NULL;
+-      ide_hwifs[0].mate = NULL;
+-      ide_hwifs[1].mate = NULL;
++      return 0;
+ }
+-#ifndef MODULE
+-/*
+- * init_ali14xx:
+- *
+- * called by ide.c when parsing command line
+- */
+-
+-void __init init_ali14xx (void)
++/* Can be called directly from ide.c. */
++int __init ali14xx_init(void)
+ {
+       /* auto-detect IDE controller port */
+-        if (findPort())
+-              if (probe_ali14xx())
+-                      goto no_detect;
+-      return;
+-
+-no_detect:
++      if (findPort()) {
++              if (ali14xx_probe())
++                      return -ENODEV;
++              return 0;
++      }
+       printk(KERN_ERR "ali14xx: not found.\n");
+-      ali14xx_release();
++      return -ENODEV;
+ }
+-#else
+-
+-MODULE_AUTHOR("see local file");
+-MODULE_DESCRIPTION("support of ALI 14XX IDE chipsets");
+-MODULE_LICENSE("GPL");
+-
+-static int __init ali14xx_mod_init(void)
++#ifdef MODULE
++static void __exit ali14xx_release_hwif(ide_hwif_t *hwif)
+ {
+-      /* auto-detect IDE controller port */
+-      if (findPort())
+-              if (probe_ali14xx()) {
+-                      ali14xx_release();
+-                      return -ENODEV;
+-              }
++      if (hwif->chipset != ide_ali14xx)
++              return;
+-      if (ide_hwifs[0].chipset != ide_ali14xx &&
+-          ide_hwifs[1].chipset != ide_ali14xx) {
+-              ali14xx_release();
+-              return -ENODEV;
+-      }
+-      return 0;
++      hwif->chipset = ide_unknown;
++      hwif->tuneproc = NULL;
++      hwif->mate = NULL;
++      hwif->channel = 0;
+ }
+-module_init(ali14xx_mod_init);
+-static void __exit ali14xx_mod_exit(void)
++static void __exit ali14xx_exit(void)
+ {
+-      ali14xx_release();
++      ali14xx_release_hwif(&ide_hwifs[0]);
++      ali14xx_release_hwif(&ide_hwifs[1]);
+ }
+-module_exit(ali14xx_mod_exit);
++
++module_init(ali14xx_init);
++module_exit(ali14xx_exit);
+ #endif
++MODULE_AUTHOR("see local file");
++MODULE_DESCRIPTION("support of ALI 14XX IDE chipsets");
++MODULE_LICENSE("GPL");
+--- linux-2.6.0-test6/drivers/ide/legacy/dtc2278.c     2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/ide/legacy/dtc2278.c    2003-10-05 00:33:24.000000000 -0700
+@@ -95,9 +95,16 @@ static void tune_dtc2278 (ide_drive_t *d
+       HWIF(drive)->drives[!drive->select.b.unit].io_32bit = 1;
+ }
+-void __init probe_dtc2278 (void)
++static int __init probe_dtc2278(void)
+ {
+       unsigned long flags;
++      ide_hwif_t *hwif, *mate;
++
++      hwif = &ide_hwifs[0];
++      mate = &ide_hwifs[1];
++
++      if (hwif->chipset != ide_unknown || mate->chipset != ide_unknown)
++              return 1;
+       local_irq_save(flags);
+       /*
+@@ -117,76 +124,60 @@ void __init probe_dtc2278 (void)
+ #endif
+       local_irq_restore(flags);
+-      ide_hwifs[0].serialized = 1;
+-      ide_hwifs[1].serialized = 1;
+-      ide_hwifs[0].chipset = ide_dtc2278;
+-      ide_hwifs[1].chipset = ide_dtc2278;
+-      ide_hwifs[0].tuneproc = &tune_dtc2278;
+-      ide_hwifs[0].drives[0].no_unmask = 1;
+-      ide_hwifs[0].drives[1].no_unmask = 1;
+-      ide_hwifs[1].drives[0].no_unmask = 1;
+-      ide_hwifs[1].drives[1].no_unmask = 1;
+-      ide_hwifs[0].mate = &ide_hwifs[1];
+-      ide_hwifs[1].mate = &ide_hwifs[0];
+-      ide_hwifs[1].channel = 1;
++      hwif->serialized = 1;
++      hwif->chipset = ide_dtc2278;
++      hwif->tuneproc = &tune_dtc2278;
++      hwif->drives[0].no_unmask = 1;
++      hwif->drives[1].no_unmask = 1;
++      hwif->mate = mate;
++
++      mate->serialized = 1;
++      mate->chipset = ide_dtc2278;
++      mate->drives[0].no_unmask = 1;
++      mate->drives[1].no_unmask = 1;
++      mate->mate = hwif;
++      mate->channel = 1;
++
++      probe_hwif_init(hwif);
++      probe_hwif_init(mate);
+-      probe_hwif_init(&ide_hwifs[0]);
+-      probe_hwif_init(&ide_hwifs[1]);
++      return 0;
+ }
+-static void dtc2278_release (void)
++/* Can be called directly from ide.c. */
++int __init dtc2278_init(void)
+ {
+-      if (ide_hwifs[0].chipset != ide_dtc2278 &&
+-          ide_hwifs[1].chipset != ide_dtc2278)
++      if (probe_dtc2278()) {
++              printk(KERN_ERR "dtc2278: ide interfaces already in use!\n");
++              return -EBUSY;
++      }
++      return 0;
++}
++
++#ifdef MODULE
++static void __exit dtc2278_release_hwif(ide_hwif_t *hwif)
++{
++      if (hwif->chipset != ide_dtc2278)
+               return;
+-      ide_hwifs[0].serialized = 0;
+-      ide_hwifs[1].serialized = 0;
+-      ide_hwifs[0].chipset = ide_unknown;
+-      ide_hwifs[1].chipset = ide_unknown;
+-      ide_hwifs[0].tuneproc = NULL;
+-      ide_hwifs[0].drives[0].no_unmask = 0;
+-      ide_hwifs[0].drives[1].no_unmask = 0;
+-      ide_hwifs[1].drives[0].no_unmask = 0;
+-      ide_hwifs[1].drives[1].no_unmask = 0;
+-      ide_hwifs[0].mate = NULL;
+-      ide_hwifs[1].mate = NULL;
++      hwif->serialized = 0;
++      hwif->chipset = ide_unknown;
++      hwif->tuneproc = NULL;
++      hwif->drives[0].no_unmask = 0;
++      hwif->drives[1].no_unmask = 0;
++      hwif->mate = NULL;
+ }
+-#ifndef MODULE
+-/*
+- * init_dtc2278:
+- *
+- * called by ide.c when parsing command line
+- */
+-
+-void __init init_dtc2278 (void)
++static void __exit dtc2278_exit(void)
+ {
+-      probe_dtc2278();
++      dtc2278_release_hwif(&ide_hwifs[0]);
++      dtc2278_release_hwif(&ide_hwifs[1]);
+ }
+-#else
++module_init(dtc2278_init);
++module_exit(dtc2278_exit);
++#endif
+ MODULE_AUTHOR("See Local File");
+ MODULE_DESCRIPTION("support of DTC-2278 VLB IDE chipsets");
+ MODULE_LICENSE("GPL");
+-
+-static int __init dtc2278_mod_init(void)
+-{
+-      probe_dtc2278();
+-      if (ide_hwifs[0].chipset != ide_dtc2278 &&
+-          ide_hwifs[1].chipset != ide_dtc2278) {
+-              dtc2278_release();
+-              return -ENODEV;
+-      }
+-      return 0;
+-}
+-module_init(dtc2278_mod_init);
+-
+-static void __exit dtc2278_mod_exit(void)
+-{
+-      dtc2278_release();
+-}
+-module_exit(dtc2278_mod_exit);
+-#endif
+-
+--- linux-2.6.0-test6/drivers/ide/legacy/hd98.c        2003-08-08 22:55:11.000000000 -0700
++++ 25/drivers/ide/legacy/hd98.c       2003-10-05 00:33:54.000000000 -0700
+@@ -652,10 +652,10 @@ static void do_hd_request (request_queue
+       enable_irq(HD_IRQ);
+ }
+-static int hd_ioctl(struct inode * inode, struct file * file,
++static int hd_ioctl(struct block_device *bdev, struct file *file,
+       unsigned int cmd, unsigned long arg)
+ {
+-      struct hd_i_struct *disk = inode->i_bdev->bd_disk->private_data;
++      struct hd_i_struct *disk = bdev->bd_disk->private_data;
+       struct hd_geometry *loc = (struct hd_geometry *) arg;
+       struct hd_geometry g; 
+@@ -666,7 +666,7 @@ static int hd_ioctl(struct inode * inode
+       g.heads = disk->head;
+       g.sectors = disk->sect;
+       g.cylinders = disk->cyl;
+-      g.start = get_start_sect(inode->i_bdev);
++      g.start = get_start_sect(bdev);
+       return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0; 
+ }
+--- linux-2.6.0-test6/drivers/ide/legacy/hd.c  2003-08-22 19:23:40.000000000 -0700
++++ 25/drivers/ide/legacy/hd.c 2003-10-05 00:33:54.000000000 -0700
+@@ -656,10 +656,10 @@ static void do_hd_request (request_queue
+       enable_irq(HD_IRQ);
+ }
+-static int hd_ioctl(struct inode * inode, struct file * file,
++static int hd_ioctl(struct block_device *bdev, struct file *file,
+       unsigned int cmd, unsigned long arg)
+ {
+-      struct hd_i_struct *disk = inode->i_bdev->bd_disk->private_data;
++      struct hd_i_struct *disk = bdev->bd_disk->private_data;
+       struct hd_geometry *loc = (struct hd_geometry *) arg;
+       struct hd_geometry g; 
+@@ -670,7 +670,7 @@ static int hd_ioctl(struct inode * inode
+       g.heads = disk->head;
+       g.sectors = disk->sect;
+       g.cylinders = disk->cyl;
+-      g.start = get_start_sect(inode->i_bdev);
++      g.start = get_start_sect(bdev);
+       return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0; 
+ }
+--- linux-2.6.0-test6/drivers/ide/legacy/ht6560b.c     2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/ide/legacy/ht6560b.c    2003-10-05 00:33:24.000000000 -0700
+@@ -304,35 +304,16 @@ static void tune_ht6560b (ide_drive_t *d
+ #endif
+ }
+-void ht6560b_release (void)
+-{
+-      if (ide_hwifs[0].chipset != ide_ht6560b &&
+-          ide_hwifs[1].chipset != ide_ht6560b)
+-                return;
+-
+-      ide_hwifs[0].chipset = ide_unknown;
+-      ide_hwifs[1].chipset = ide_unknown;
+-      ide_hwifs[0].tuneproc = NULL;
+-      ide_hwifs[1].tuneproc = NULL;
+-      ide_hwifs[0].selectproc = NULL;
+-      ide_hwifs[1].selectproc = NULL;
+-      ide_hwifs[0].serialized = 0;
+-      ide_hwifs[1].serialized = 0;
+-      ide_hwifs[0].mate = NULL;
+-      ide_hwifs[1].mate = NULL;
+-
+-      ide_hwifs[0].drives[0].drive_data = 0;
+-      ide_hwifs[0].drives[1].drive_data = 0;
+-      ide_hwifs[1].drives[0].drive_data = 0;
+-      ide_hwifs[1].drives[1].drive_data = 0;
+-      release_region(HT_CONFIG_PORT, 1);
+-}
+-
+-static int __init ht6560b_mod_init(void)
++/* Can be called directly from ide.c. */
++int __init ht6560b_init(void)
+ {
++      ide_hwif_t *hwif, *mate;
+       int t;
+-      if (!request_region(HT_CONFIG_PORT, 1, ide_hwifs[0].name)) {
++      hwif = &ide_hwifs[0];
++      mate = &ide_hwifs[1];
++
++      if (!request_region(HT_CONFIG_PORT, 1, hwif->name)) {
+               printk(KERN_NOTICE "%s: HT_CONFIG_PORT not found\n",
+                       __FUNCTION__);
+               return -ENODEV;
+@@ -343,39 +324,33 @@ static int __init ht6560b_mod_init(void)
+               goto release_region;
+       }
+-      ide_hwifs[0].chipset = ide_ht6560b;
+-      ide_hwifs[1].chipset = ide_ht6560b;
+-      ide_hwifs[0].selectproc = &ht6560b_selectproc;
+-      ide_hwifs[1].selectproc = &ht6560b_selectproc;
+-      ide_hwifs[0].tuneproc = &tune_ht6560b;
+-      ide_hwifs[1].tuneproc = &tune_ht6560b;
+-      ide_hwifs[0].serialized = 1;  /* is this needed? */
+-      ide_hwifs[1].serialized = 1;  /* is this needed? */
+-      ide_hwifs[0].mate = &ide_hwifs[1];
+-      ide_hwifs[1].mate = &ide_hwifs[0];
+-      ide_hwifs[1].channel = 1;
++      hwif->chipset = ide_ht6560b;
++      hwif->selectproc = &ht6560b_selectproc;
++      hwif->tuneproc = &tune_ht6560b;
++      hwif->serialized = 1;   /* is this needed? */
++      hwif->mate = mate;
++
++      mate->chipset = ide_ht6560b;
++      mate->selectproc = &ht6560b_selectproc;
++      mate->tuneproc = &tune_ht6560b;
++      mate->serialized = 1;   /* is this needed? */
++      mate->mate = hwif;
++      mate->channel = 1;
+       /*
+        * Setting default configurations for drives
+        */
+       t = (HT_CONFIG_DEFAULT << 8);
+       t |= HT_TIMING_DEFAULT;
+-      ide_hwifs[0].drives[0].drive_data = t;
+-      ide_hwifs[0].drives[1].drive_data = t;
+-      t |= (HT_SECONDARY_IF << 8);
+-      ide_hwifs[1].drives[0].drive_data = t;
+-      ide_hwifs[1].drives[1].drive_data = t;
++      hwif->drives[0].drive_data = t;
++      hwif->drives[1].drive_data = t;
+-      probe_hwif_init(&ide_hwifs[0]);
+-      probe_hwif_init(&ide_hwifs[1]);
++      t |= (HT_SECONDARY_IF << 8);
++      mate->drives[0].drive_data = t;
++      mate->drives[1].drive_data = t;
+-#ifdef MODULE
+-      if (ide_hwifs[0].chipset != ide_ht6560b &&
+-          ide_hwifs[1].chipset != ide_ht6560b) {
+-              ht6560b_release();
+-              return -ENODEV;
+-      }
+-#endif
++      probe_hwif_init(hwif);
++      probe_hwif_init(mate);
+       return 0;
+@@ -384,24 +359,34 @@ release_region:
+       return -ENODEV;
+ }
+-MODULE_AUTHOR("See Local File");
+-MODULE_DESCRIPTION("HT-6560B EIDE-controller support");
+-MODULE_LICENSE("GPL");
+-
+ #ifdef MODULE
+-static void __exit ht6560b_mod_exit(void)
++static void __exit ht6560b_release_hwif(ide_hwif_t *hwif)
+ {
+-        ht6560b_release();
++      if (hwif->chipset != ide_ht6560b)
++              return;
++
++      hwif->chipset = ide_unknown;
++      hwif->tuneproc = NULL;
++      hwif->selectproc = NULL;
++      hwif->serialized = 0;
++      hwif->mate = NULL;
++      hwif->channel = 0;
++
++      hwif->drives[0].drive_data = 0;
++      hwif->drives[1].drive_data = 0;
+ }
+-module_init(ht6560b_mod_init);
+-module_exit(ht6560b_mod_exit);
+-#else
+-/*
+- * called by ide.c when parsing command line
+- */
+-void __init init_ht6560b (void)
++static void __exit ht6560b_exit(void)
+ {
+-      ht6560b_mod_init();     /* ignore return value */
++      ht6560b_release_hwif(&ide_hwifs[0]);
++      ht6560b_release_hwif(&ide_hwifs[1]);
++      release_region(HT_CONFIG_PORT, 1);
+ }
++
++module_init(ht6560b_init);
++module_exit(ht6560b_exit);
+ #endif
++
++MODULE_AUTHOR("See Local File");
++MODULE_DESCRIPTION("HT-6560B EIDE-controller support");
++MODULE_LICENSE("GPL");
+--- linux-2.6.0-test6/drivers/ide/legacy/pdc4030.c     2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/ide/legacy/pdc4030.c    2003-10-05 00:33:24.000000000 -0700
+@@ -147,8 +147,6 @@ int pdc4030_identify(ide_drive_t *drive)
+       return pdc4030_cmd(drive, PROMISE_IDENTIFY);
+ }
+-int enable_promise_support;
+-
+ /*
+  * setup_pdc4030()
+  * Completes the setup of a Promise DC4030 controller card, once found.
+@@ -296,33 +294,24 @@ int __init detect_pdc4030(ide_hwif_t *hw
+       }
+ }
+-
+-int __init ide_probe_for_pdc4030(void)
++int __init pdc4030_init(void)
+ {
+       unsigned int    index;
+       ide_hwif_t      *hwif;
+-#ifndef MODULE
+-      if (enable_promise_support == 0)
+-              return;
+-#endif
+-
+       for (index = 0; index < MAX_HWIFS; index++) {
+               hwif = &ide_hwifs[index];
+               if (hwif->chipset == ide_unknown && detect_pdc4030(hwif)) {
+-#ifndef MODULE
+-                      setup_pdc4030(hwif);
+-#else
+-                      return setup_pdc4030(hwif);
+-#endif
++                      if (!setup_pdc4030(hwif))
++                              return -ENODEV;
++                      return 0;
+               }
+       }
+-#ifdef MODULE
+-      return 0;
+-#endif
++      return -ENODEV;
+ }
+-static void __exit release_pdc4030(ide_hwif_t *hwif, ide_hwif_t *mate)
++#ifdef MODULE
++static void __exit pdc4030_release_hwif(ide_hwif_t *hwif)
+ {
+       hwif->chipset = ide_unknown;
+       hwif->selectproc = NULL;
+@@ -333,72 +322,24 @@ static void __exit release_pdc4030(ide_h
+       hwif->drives[1].keep_settings = 0;
+       hwif->drives[0].noprobe = 0;
+       hwif->drives[1].noprobe = 0;
+-
+-      if (mate != NULL) {
+-              mate->chipset = ide_unknown;
+-              mate->selectproc = NULL;
+-              mate->serialized = 0;
+-              mate->drives[0].io_32bit = 0;
+-              mate->drives[1].io_32bit = 0;
+-              mate->drives[0].keep_settings = 0;
+-              mate->drives[1].keep_settings = 0;
+-              mate->drives[0].noprobe = 0;
+-              mate->drives[1].noprobe = 0;
+-      }
+ }
+-#ifndef MODULE
+-/*
+- * init_pdc4030:
+- *
+- * called by ide.c when parsing command line
+- */
+-
+-void __init init_pdc4030(void)
++static void __exit pdc4030_exit(void)
+ {
+-      enable_promise_support = 1;
++      unsigned int index;
++
++      for (index = 0; index < MAX_HWIFS; index++)
++              pdc4030_release_hwif(&ide_hwifs[index]);
+ }
+-#else
++module_init(pdc4030_init);
++module_exit(pdc4030_exit);
++#endif
+ MODULE_AUTHOR("Peter Denison");
+ MODULE_DESCRIPTION("Support of Promise 4030 VLB series IDE chipsets");
+ MODULE_LICENSE("GPL");
+-static int __init pdc4030_mod_init(void)
+-{
+-      if (enable_promise_support == 0)
+-              enable_promise_support = 1;
+-
+-      if (!ide_probe_for_pdc4030())
+-              return -ENODEV;
+-        return 0;
+-}
+-module_init(pdc4030_mod_init);
+-
+-static void __exit pdc4030_mod_exit(void)
+-{
+-      unsigned int    index;
+-      ide_hwif_t      *hwif;
+-
+-      if (enable_promise_support == 0)
+-              return;
+- 
+-      for (index = 0; index < MAX_HWIFS; index++) {
+-              hwif = &ide_hwifs[index];
+-              if (hwif->chipset == ide_pdc4030) {
+-                      ide_hwif_t *mate = &ide_hwifs[hwif->index+1];
+-                      if (mate->chipset == ide_pdc4030)
+-                              release_pdc4030(hwif, mate);
+-                      else
+-                              release_pdc4030(hwif, NULL);
+-                }
+-        }
+-      enable_promise_support = 0;
+-}
+-module_exit(pdc4030_mod_exit);
+-#endif
+-
+ /*
+  * promise_read_intr() is the handler for disk read/multread interrupts
+  */
+--- linux-2.6.0-test6/drivers/ide/legacy/qd65xx.c      2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/ide/legacy/qd65xx.c     2003-10-05 00:33:24.000000000 -0700
+@@ -338,12 +338,12 @@ static int __init qd_testreg(int port)
+  * called to setup an ata channel : adjusts attributes & links for tuning
+  */
+-void __init qd_setup (int unit, int base, int config, unsigned int data0, unsigned int data1, void (*tuneproc) (ide_drive_t *, u8 pio))
++static void __init qd_setup(ide_hwif_t *hwif, int base, int config,
++                          unsigned int data0, unsigned int data1,
++                          void (*tuneproc) (ide_drive_t *, u8 pio))
+ {
+-      ide_hwif_t *hwif = &ide_hwifs[unit];
+-
+       hwif->chipset = ide_qd65xx;
+-      hwif->channel = unit;
++      hwif->channel = hwif->index;
+       hwif->select_data = base;
+       hwif->config_data = config;
+       hwif->drives[0].drive_data = data0;
+@@ -354,19 +354,20 @@ void __init qd_setup (int unit, int base
+       probe_hwif_init(hwif);
+ }
++#ifdef MODULE
+ /*
+  * qd_unsetup:
+  *
+  * called to unsetup an ata channel : back to default values, unlinks tuning
+  */
+-static void __exit qd_unsetup (int unit)
++static void __exit qd_unsetup(ide_hwif_t *hwif)
+ {
+-      ide_hwif_t *hwif = &ide_hwifs[unit];
+       u8 config = hwif->config_data;
+       int base = hwif->select_data;
+       void *tuneproc = (void *) hwif->tuneproc;
+-      if (!(hwif->chipset == ide_qd65xx)) return;
++      if (hwif->chipset != ide_qd65xx)
++              return;
+       printk(KERN_NOTICE "%s: back to defaults\n", hwif->name);
+@@ -381,13 +382,14 @@ static void __exit qd_unsetup (int unit)
+                       qd_write_reg(QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
+                       qd_write_reg(QD6580_DEF_DATA2, QD_TIMREG(&hwif->drives[1]));
+               } else {
+-                      qd_write_reg(unit?QD6580_DEF_DATA2:QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
++                      qd_write_reg(hwif->channel ? QD6580_DEF_DATA2 : QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
+               }
+       } else {
+               printk(KERN_WARNING "Unknown qd65xx tuning fonction !\n");
+               printk(KERN_WARNING "keeping settings !\n");
+       }
+ }
++#endif
+ /*
+  * qd_probe:
+@@ -396,8 +398,9 @@ static void __exit qd_unsetup (int unit)
+  * return 1 if another qd may be probed
+  */
+-int __init qd_probe (int base)
++static int __init qd_probe(int base)
+ {
++      ide_hwif_t *hwif;
+       u8 config;
+       u8 unit;
+@@ -414,9 +417,8 @@ int __init qd_probe (int base)
+               /* qd6500 found */
+-              printk(KERN_NOTICE "%s: qd6500 at %#x\n",
+-                      ide_hwifs[unit].name, base);
+-              
++              hwif = &ide_hwifs[unit];
++              printk(KERN_NOTICE "%s: qd6500 at %#x\n", hwif->name, base);
+               printk(KERN_DEBUG "qd6500: config=%#x, ID3=%u\n",
+                       config, QD_ID3);
+               
+@@ -425,8 +427,8 @@ int __init qd_probe (int base)
+                       return 1;
+               }
+-              qd_setup(unit, base, config, QD6500_DEF_DATA,
+-                      QD6500_DEF_DATA, &qd6500_tune_drive);
++              qd_setup(hwif, base, config, QD6500_DEF_DATA, QD6500_DEF_DATA,
++                       &qd6500_tune_drive);
+               return 1;
+       }
+@@ -448,25 +450,31 @@ int __init qd_probe (int base)
+               if (control & QD_CONTR_SEC_DISABLED) {
+                       /* secondary disabled */
++
++                      hwif = &ide_hwifs[unit];
+                       printk(KERN_INFO "%s: qd6580: single IDE board\n",
+-                                      ide_hwifs[unit].name);
+-                      qd_setup(unit, base, config | (control << 8),
+-                              QD6580_DEF_DATA, QD6580_DEF_DATA2,
+-                              &qd6580_tune_drive);
++                                       hwif->name);
++                      qd_setup(hwif, base, config | (control << 8),
++                               QD6580_DEF_DATA, QD6580_DEF_DATA2,
++                               &qd6580_tune_drive);
+                       qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
+                       return 1;
+               } else {
++                      ide_hwif_t *mate;
++
++                      hwif = &ide_hwifs[0];
++                      mate = &ide_hwifs[1];
+                       /* secondary enabled */
+                       printk(KERN_INFO "%s&%s: qd6580: dual IDE board\n",
+-                                      ide_hwifs[0].name,ide_hwifs[1].name);
++                                      hwif->name, mate->name);
+-                      qd_setup(0, base, config | (control << 8),
+-                              QD6580_DEF_DATA, QD6580_DEF_DATA,
+-                              &qd6580_tune_drive);
+-                      qd_setup(1, base, config | (control << 8),
+-                              QD6580_DEF_DATA2, QD6580_DEF_DATA2,
+-                              &qd6580_tune_drive);
++                      qd_setup(hwif, base, config | (control << 8),
++                               QD6580_DEF_DATA, QD6580_DEF_DATA,
++                               &qd6580_tune_drive);
++                      qd_setup(mate, base, config | (control << 8),
++                               QD6580_DEF_DATA2, QD6580_DEF_DATA2,
++                               &qd6580_tune_drive);
+                       qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
+                       return 0; /* no other qd65xx possible */
+@@ -476,38 +484,28 @@ int __init qd_probe (int base)
+       return 1;
+ }
+-#ifndef MODULE
+-/*
+- * init_qd65xx:
+- *
+- * called by ide.c when parsing command line
+- */
+-
+-void __init init_qd65xx (void)
+-{
+-      if (qd_probe(0x30)) qd_probe(0xb0);
+-}
+-
+-#else
+-
+-MODULE_AUTHOR("Samuel Thibault");
+-MODULE_DESCRIPTION("support of qd65xx vlb ide chipset");
+-MODULE_LICENSE("GPL");
+-
+-static int __init qd65xx_mod_init(void)
++/* Can be called directly from ide.c. */
++int __init qd65xx_init(void)
+ {
+-      if (qd_probe(0x30)) qd_probe(0xb0);
++      if (qd_probe(0x30))
++              qd_probe(0xb0);
+       if (ide_hwifs[0].chipset != ide_qd65xx &&
+           ide_hwifs[1].chipset != ide_qd65xx)
+               return -ENODEV;
+       return 0;
+ }
+-module_init(qd65xx_mod_init);
+-static void __exit qd65xx_mod_exit(void)
++#ifdef MODULE
++static void __exit qd65xx_exit(void)
+ {
+-      qd_unsetup(0);
+-      qd_unsetup(1);
++      qd_unsetup(&ide_hwifs[0]);
++      qd_unsetup(&ide_hwifs[1]);
+ }
+-module_exit(qd65xx_mod_exit);
++
++module_init(qd65xx_init);
++module_exit(qd65xx_exit);
+ #endif
++
++MODULE_AUTHOR("Samuel Thibault");
++MODULE_DESCRIPTION("support of qd65xx vlb ide chipset");
++MODULE_LICENSE("GPL");
+--- linux-2.6.0-test6/drivers/ide/legacy/umc8672.c     2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/ide/legacy/umc8672.c    2003-10-05 00:33:24.000000000 -0700
+@@ -124,16 +124,16 @@ static void tune_umc (ide_drive_t *drive
+       spin_unlock_irqrestore(&ide_lock, flags);
+ }
+-int __init probe_umc8672 (void)
++static int __init umc8672_probe(void)
+ {
+       unsigned long flags;
++      ide_hwif_t *hwif, *mate;
+-      local_irq_save(flags);
+       if (!request_region(0x108, 2, "umc8672")) {
+-              local_irq_restore(flags);
+               printk(KERN_ERR "umc8672: ports 0x108-0x109 already in use.\n");
+               return 1;
+       }
++      local_irq_save(flags);
+       outb_p(0x5A,0x108); /* enable umc */
+       if (in_umc (0xd5) != 0xa0) {
+               local_irq_restore(flags);
+@@ -146,82 +146,62 @@ int __init probe_umc8672 (void)
+       umc_set_speeds (current_speeds);
+       local_irq_restore(flags);
+-      ide_hwifs[0].chipset = ide_umc8672;
+-      ide_hwifs[1].chipset = ide_umc8672;
+-      ide_hwifs[0].tuneproc = &tune_umc;
+-      ide_hwifs[1].tuneproc = &tune_umc;
+-      ide_hwifs[0].mate = &ide_hwifs[1];
+-      ide_hwifs[1].mate = &ide_hwifs[0];
+-      ide_hwifs[1].channel = 1;
++      hwif = &ide_hwifs[0];
++      mate = &ide_hwifs[1];
+-      probe_hwif_init(&ide_hwifs[0]);
+-      probe_hwif_init(&ide_hwifs[1]);
++      hwif->chipset = ide_umc8672;
++      hwif->tuneproc = &tune_umc;
++      hwif->mate = mate;
++
++      mate->chipset = ide_umc8672;
++      mate->tuneproc = &tune_umc;
++      mate->mate = hwif;
++      mate->channel = 1;
++
++      probe_hwif_init(hwif);
++      probe_hwif_init(mate);
+       return 0;
+ }
+-static void umc8672_release (void)
++/* Can be called directly from ide.c. */
++int __init umc8672_init(void)
+ {
+-      unsigned long flags;
++      if (umc8672_probe())
++              return -ENODEV;
++      return 0;
++}
+-      local_irq_save(flags);
+-      if (ide_hwifs[0].chipset != ide_umc8672 &&
+-          ide_hwifs[1].chipset != ide_umc8672) {
+-              local_irq_restore(flags);
++#ifdef MODULE
++static void __exit umc8672_release_hwif(ide_hwif_t *hwif)
++{
++      if (hwif->chipset != ide_umc8672)
+               return;
+-      }
+-      ide_hwifs[0].chipset = ide_unknown;
+-      ide_hwifs[1].chipset = ide_unknown;     
+-      ide_hwifs[0].tuneproc = NULL;
+-      ide_hwifs[1].tuneproc = NULL;
+-      ide_hwifs[0].mate = NULL;
+-      ide_hwifs[1].mate = NULL;
+-      ide_hwifs[0].channel = 0;
+-      ide_hwifs[1].channel = 0;
+-
+-      outb_p(0xa5,0x108); /* disable umc */
+-
+-      release_region(0x108, 2);
+-      local_irq_restore(flags);
++      hwif->chipset = ide_unknown;
++      hwif->tuneproc = NULL;
++      hwif->mate = NULL;
++      hwif->channel = 0;
+ }
+-#ifndef MODULE
+-/*
+- * init_umc8672:
+- *
+- * called by ide.c when parsing command line
+- */
+-
+-void __init init_umc8672 (void)
++static void __exit umc8672_exit(void)
+ {
+-      if (probe_umc8672())
+-              printk(KERN_ERR "init_umc8672: umc8672 controller not found.\n");
+-}
++      unsigned long flags;
+-#else
++      umc8672_release_hwif(&ide_hwifs[0]);
++      umc8672_release_hwif(&ide_hwifs[1]);
+-MODULE_AUTHOR("Wolfram Podien");
+-MODULE_DESCRIPTION("Support for UMC 8672 IDE chipset");
+-MODULE_LICENSE("GPL");
++      local_irq_save(flags);
++      outb_p(0xa5, 0x108);    /* disable umc */
++      local_irq_restore(flags);
+-static int __init umc8672_mod_init(void)
+-{
+-      if (probe_umc8672())
+-              return -ENODEV;
+-      if (ide_hwifs[0].chipset != ide_umc8672 &&
+-          ide_hwifs[1].chipset != ide_umc8672) {
+-              umc8672_release();
+-              return -ENODEV;
+-      }
+-      return 0;
++      release_region(0x108, 2);
+ }
+-module_init(umc8672_mod_init);
+-static void __exit umc8672_mod_exit(void)
+-{
+-        umc8672_release();
+-}
+-module_exit(umc8672_mod_exit);
++module_init(umc8672_init);
++module_exit(umc8672_exit);
+ #endif
++MODULE_AUTHOR("Wolfram Podien");
++MODULE_DESCRIPTION("Support for UMC 8672 IDE chipset");
++MODULE_LICENSE("GPL");
+--- linux-2.6.0-test6/drivers/ide/pci/amd74xx.c        2003-08-22 19:23:40.000000000 -0700
++++ 25/drivers/ide/pci/amd74xx.c       2003-10-05 00:33:24.000000000 -0700
+@@ -1,5 +1,5 @@
+ /*
+- * Version 2.9
++ * Version 2.11
+  *
+  * AMD 755/756/766/8111 and nVidia nForce IDE driver for Linux.
+  *
+@@ -65,7 +65,6 @@ static struct amd_ide_chip {
+ };
+ static struct amd_ide_chip *amd_config;
+-static unsigned char amd_enabled;
+ static unsigned int amd_80w;
+ static unsigned int amd_clock;
+@@ -103,7 +102,7 @@ static int amd74xx_get_info(char *buffer
+       amd_print("----------AMD BusMastering IDE Configuration----------------");
+-      amd_print("Driver Version:                     2.9");
++      amd_print("Driver Version:                     2.11");
+       amd_print("South Bridge:                       %s", pci_name(bmide_dev));
+       pci_read_config_byte(dev, PCI_REVISION_ID, &t);
+@@ -250,9 +249,6 @@ static int amd_set_drive(ide_drive_t *dr
+ static void amd74xx_tune_drive(ide_drive_t *drive, u8 pio)
+ {
+-      if (!((amd_enabled >> HWIF(drive)->channel) & 1))
+-              return;
+-
+       if (pio == 255) {
+               amd_set_drive(drive, ide_find_best_mode(drive, XFER_PIO | XFER_EPIO));
+               return;
+@@ -330,9 +326,6 @@ static unsigned int __init init_chipset_
+                       break;
+       }
+-      pci_read_config_dword(dev, AMD_IDE_ENABLE, &u);
+-      amd_enabled = ((u & 1) ? 2 : 0) | ((u & 2) ? 1 : 0);
+-
+ /*
+  * Take care of prefetch & postwrite.
+  */
+@@ -408,8 +401,8 @@ static void __init init_hwif_amd74xx(ide
+         hwif->mwdma_mask = 0x07;
+         hwif->swdma_mask = 0x07;
+-        if (!(hwif->udma_four))
+-                hwif->udma_four = ((amd_enabled & amd_80w) >> hwif->channel) & 1;
++      if (!hwif->udma_four)
++              hwif->udma_four = (amd_80w >> hwif->channel) & 1;
+         hwif->ide_dma_check = &amd74xx_ide_dma_check;
+         if (!noautodma)
+                 hwif->autodma = 1;
+@@ -417,16 +410,6 @@ static void __init init_hwif_amd74xx(ide
+         hwif->drives[1].autodma = hwif->autodma;
+ }
+-/*
+- * We allow the BM-DMA driver only work on enabled interfaces.
+- */
+-
+-static void __init init_dma_amd74xx(ide_hwif_t *hwif, unsigned long dmabase)
+-{
+-      if ((amd_enabled >> hwif->channel) & 1)
+-              ide_setup_dma(hwif, dmabase, 8);
+-}
+-
+ extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+ static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id)
+--- linux-2.6.0-test6/drivers/ide/pci/amd74xx.h        2003-06-14 12:17:57.000000000 -0700
++++ 25/drivers/ide/pci/amd74xx.h       2003-10-05 00:33:24.000000000 -0700
+@@ -27,7 +27,6 @@ static ide_pci_host_proc_t amd74xx_procs
+ static unsigned int init_chipset_amd74xx(struct pci_dev *, const char *);
+ static void init_hwif_amd74xx(ide_hwif_t *);
+-static void init_dma_amd74xx(ide_hwif_t *, unsigned long);
+ static ide_pci_device_t amd74xx_chipsets[] __devinitdata = {
+       {       /* 0 */
+@@ -35,9 +34,7 @@ static ide_pci_device_t amd74xx_chipsets
+               .device         = PCI_DEVICE_ID_AMD_COBRA_7401,
+               .name           = "AMD7401",
+               .init_chipset   = init_chipset_amd74xx,
+-              .init_iops      = NULL,
+               .init_hwif      = init_hwif_amd74xx,
+-              .init_dma       = init_dma_amd74xx,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
+@@ -48,9 +45,7 @@ static ide_pci_device_t amd74xx_chipsets
+               .device         = PCI_DEVICE_ID_AMD_VIPER_7409,
+               .name           = "AMD7409",
+               .init_chipset   = init_chipset_amd74xx,
+-              .init_iops      = NULL,
+               .init_hwif      = init_hwif_amd74xx,
+-              .init_dma       = init_dma_amd74xx,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
+@@ -61,9 +56,7 @@ static ide_pci_device_t amd74xx_chipsets
+               .device         = PCI_DEVICE_ID_AMD_VIPER_7411,
+               .name           = "AMD7411",
+               .init_chipset   = init_chipset_amd74xx,
+-              .init_iops      = NULL,
+               .init_hwif      = init_hwif_amd74xx,
+-              .init_dma       = init_dma_amd74xx,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
+@@ -74,9 +67,7 @@ static ide_pci_device_t amd74xx_chipsets
+               .device         = PCI_DEVICE_ID_AMD_OPUS_7441,
+               .name           = "AMD7441",
+               .init_chipset   = init_chipset_amd74xx,
+-              .init_iops      = NULL,
+               .init_hwif      = init_hwif_amd74xx,
+-              .init_dma       = init_dma_amd74xx,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
+@@ -87,9 +78,7 @@ static ide_pci_device_t amd74xx_chipsets
+               .device         = PCI_DEVICE_ID_AMD_8111_IDE,
+               .name           = "AMD8111",
+               .init_chipset   = init_chipset_amd74xx,
+-              .init_iops      = NULL,
+               .init_hwif      = init_hwif_amd74xx,
+-              .init_dma       = init_dma_amd74xx,
+               .autodma        = AUTODMA,
+               .channels       = 2,
+               .enablebits     = {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
+@@ -101,9 +90,7 @@ static ide_pci_device_t amd74xx_chipsets
+               .device         = PCI_DEVICE_ID_NVIDIA_NFORCE_IDE,
+               .name           = "NFORCE",
+               .init_chipset   = init_chipset_amd74xx,
+-              .init_iops      = NULL,
+               .init_hwif      = init_hwif_amd74xx,
+-              .init_dma       = init_dma_amd74xx,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x50,0x02,0x02}, {0x50,0x01,0x01}},
+@@ -115,9 +102,7 @@ static ide_pci_device_t amd74xx_chipsets
+               .device         = PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE,
+               .name           = "NFORCE2",
+               .init_chipset   = init_chipset_amd74xx,
+-              .init_iops      = NULL,
+               .init_hwif      = init_hwif_amd74xx,
+-              .init_dma       = init_dma_amd74xx,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x50,0x02,0x02}, {0x50,0x01,0x01}},
+--- linux-2.6.0-test6/drivers/ide/pci/cmd64x.c 2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/ide/pci/cmd64x.c        2003-10-05 00:33:24.000000000 -0700
+@@ -742,11 +742,6 @@ static void __init init_hwif_cmd64x (ide
+       hwif->drives[1].autodma = hwif->autodma;
+ }
+-static void __init init_dma_cmd64x (ide_hwif_t *hwif, unsigned long dmabase)
+-{
+-      ide_setup_dma(hwif, dmabase, 8);
+-}
+-
+ extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+ static int __devinit cmd64x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+--- linux-2.6.0-test6/drivers/ide/pci/cmd64x.h 2003-06-14 12:18:08.000000000 -0700
++++ 25/drivers/ide/pci/cmd64x.h        2003-10-05 00:33:24.000000000 -0700
+@@ -81,7 +81,6 @@ static ide_pci_host_proc_t cmd64x_procs[
+ static unsigned int init_chipset_cmd64x(struct pci_dev *, const char *);
+ static void init_hwif_cmd64x(ide_hwif_t *);
+-static void init_dma_cmd64x(ide_hwif_t *, unsigned long);
+ static ide_pci_device_t cmd64x_chipsets[] __devinitdata = {
+       {       /* 0 */
+@@ -91,7 +90,6 @@ static ide_pci_device_t cmd64x_chipsets[
+               .init_chipset   = init_chipset_cmd64x,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_cmd64x,
+-              .init_dma       = init_dma_cmd64x,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+@@ -104,7 +102,6 @@ static ide_pci_device_t cmd64x_chipsets[
+               .init_chipset   = init_chipset_cmd64x,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_cmd64x,
+-              .init_dma       = init_dma_cmd64x,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x00,0x00,0x00}, {0x51,0x80,0x80}},
+@@ -117,7 +114,6 @@ static ide_pci_device_t cmd64x_chipsets[
+               .init_chipset   = init_chipset_cmd64x,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_cmd64x,
+-              .init_dma       = init_dma_cmd64x,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+@@ -130,7 +126,6 @@ static ide_pci_device_t cmd64x_chipsets[
+               .init_chipset   = init_chipset_cmd64x,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_cmd64x,
+-              .init_dma       = init_dma_cmd64x,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+--- linux-2.6.0-test6/drivers/ide/pci/cs5530.c 2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/ide/pci/cs5530.c        2003-10-05 00:33:24.000000000 -0700
+@@ -404,19 +404,6 @@ static void __init init_hwif_cs5530 (ide
+       hwif->drives[1].autodma = hwif->autodma;
+ }
+-/**
+- *    init_dma_cs5530         -       set up for DMA
+- *    @hwif: interface
+- *    @dmabase: DMA base address
+- *
+- *    FIXME: this can go away
+- */
+- 
+-static void __init init_dma_cs5530 (ide_hwif_t *hwif, unsigned long dmabase)
+-{
+-      ide_setup_dma(hwif, dmabase, 8);
+-}
+-
+ extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+--- linux-2.6.0-test6/drivers/ide/pci/cs5530.h 2003-06-14 12:17:57.000000000 -0700
++++ 25/drivers/ide/pci/cs5530.h        2003-10-05 00:33:24.000000000 -0700
+@@ -27,7 +27,6 @@ static ide_pci_host_proc_t cs5530_procs[
+ static unsigned int init_chipset_cs5530(struct pci_dev *, const char *);
+ static void init_hwif_cs5530(ide_hwif_t *);
+-static void init_dma_cs5530(ide_hwif_t *, unsigned long);
+ static ide_pci_device_t cs5530_chipsets[] __devinitdata = {
+       {       /* 0 */
+@@ -37,7 +36,6 @@ static ide_pci_device_t cs5530_chipsets[
+               .init_chipset   = init_chipset_cs5530,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_cs5530,
+-              .init_dma       = init_dma_cs5530,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+--- linux-2.6.0-test6/drivers/ide/pci/generic.c        2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/ide/pci/generic.c       2003-10-05 00:33:24.000000000 -0700
+@@ -72,11 +72,6 @@ static void __init init_hwif_generic (id
+       hwif->drives[1].autodma = hwif->autodma;
+ }
+-static void init_dma_generic (ide_hwif_t *hwif, unsigned long dmabase)
+-{
+-      ide_setup_dma(hwif, dmabase, 8);
+-}
+-
+ extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+ #if 0
+--- linux-2.6.0-test6/drivers/ide/pci/generic.h        2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/ide/pci/generic.h       2003-10-05 00:33:24.000000000 -0700
+@@ -7,7 +7,6 @@
+ static unsigned int init_chipset_generic(struct pci_dev *, const char *);
+ static void init_hwif_generic(ide_hwif_t *);
+-static void init_dma_generic(ide_hwif_t *, unsigned long);
+ static ide_pci_device_t generic_chipsets[] __devinitdata = {
+       {       /* 0 */
+@@ -17,7 +16,6 @@ static ide_pci_device_t generic_chipsets
+               .init_chipset   = init_chipset_generic,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_generic,
+-              .init_dma       = init_dma_generic,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x43,0x08,0x08}, {0x47,0x08,0x08}},
+@@ -30,7 +28,6 @@ static ide_pci_device_t generic_chipsets
+               .init_chipset   = init_chipset_generic,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_generic,
+-              .init_dma       = init_dma_generic,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+@@ -43,7 +40,6 @@ static ide_pci_device_t generic_chipsets
+               .init_chipset   = init_chipset_generic,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_generic,
+-              .init_dma       = init_dma_generic,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+@@ -56,7 +52,6 @@ static ide_pci_device_t generic_chipsets
+               .init_chipset   = init_chipset_generic,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_generic,
+-              .init_dma       = init_dma_generic,
+               .channels       = 2,
+               .autodma        = NODMA,
+               .enablebits     = {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+@@ -69,7 +64,6 @@ static ide_pci_device_t generic_chipsets
+               .init_chipset   = init_chipset_generic,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_generic,
+-              .init_dma       = init_dma_generic,
+               .channels       = 2,
+               .autodma        = NODMA,
+               .enablebits     = {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+@@ -82,7 +76,6 @@ static ide_pci_device_t generic_chipsets
+               .init_chipset   = init_chipset_generic,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_generic,
+-              .init_dma       = init_dma_generic,
+               .channels       = 2,
+               .autodma        = NODMA,
+               .enablebits     = {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+@@ -95,7 +88,6 @@ static ide_pci_device_t generic_chipsets
+               .init_chipset   = init_chipset_generic,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_generic,
+-              .init_dma       = init_dma_generic,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+@@ -108,7 +100,6 @@ static ide_pci_device_t generic_chipsets
+               .init_chipset   = init_chipset_generic,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_generic,
+-              .init_dma       = init_dma_generic,
+               .channels       = 2,
+               .autodma        = NOAUTODMA,
+               .enablebits     = {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+@@ -121,7 +112,6 @@ static ide_pci_device_t generic_chipsets
+               .init_chipset   = init_chipset_generic,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_generic,
+-              .init_dma       = init_dma_generic,
+               .channels       = 2,
+               .autodma        = NOAUTODMA,
+               .enablebits     = {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+@@ -134,7 +124,6 @@ static ide_pci_device_t generic_chipsets
+               .init_chipset   = init_chipset_generic,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_generic,
+-              .init_dma       = init_dma_generic,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+@@ -157,7 +146,6 @@ static ide_pci_device_t unknown_chipset[
+               .init_chipset   = init_chipset_generic,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_generic,
+-              .init_dma       = init_dma_generic,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+--- linux-2.6.0-test6/drivers/ide/pci/hpt34x.c 2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/ide/pci/hpt34x.c        2003-10-05 00:33:24.000000000 -0700
+@@ -315,11 +315,6 @@ static void __init init_hwif_hpt34x (ide
+       hwif->drives[1].autodma = hwif->autodma;
+ }
+-static void __init init_dma_hpt34x (ide_hwif_t *hwif, unsigned long dmabase)
+-{
+-      ide_setup_dma(hwif, dmabase, 8);
+-}
+-
+ extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+ static int __devinit hpt34x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+--- linux-2.6.0-test6/drivers/ide/pci/hpt34x.h 2003-06-14 12:17:56.000000000 -0700
++++ 25/drivers/ide/pci/hpt34x.h        2003-10-05 00:33:24.000000000 -0700
+@@ -33,7 +33,6 @@ static ide_pci_host_proc_t hpt34x_procs[
+ static unsigned int init_chipset_hpt34x(struct pci_dev *, const char *);
+ static void init_hwif_hpt34x(ide_hwif_t *);
+-static void init_dma_hpt34x(ide_hwif_t *, unsigned long);
+ static ide_pci_device_t hpt34x_chipsets[] __devinitdata = {
+       {       /* 0 */
+@@ -43,7 +42,6 @@ static ide_pci_device_t hpt34x_chipsets[
+               .init_chipset   = init_chipset_hpt34x,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_hpt34x,
+-              .init_dma       = init_dma_hpt34x,
+               .channels       = 2,
+               .autodma        = NOAUTODMA,
+               .enablebits     = {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+--- linux-2.6.0-test6/drivers/ide/pci/it8172.c 2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/ide/pci/it8172.c        2003-10-05 00:33:24.000000000 -0700
+@@ -284,11 +284,6 @@ static void __init init_hwif_it8172 (ide
+       hwif->drives[1].autodma = hwif->autodma;
+ }
+-static void __init init_dma_it8172 (ide_hwif_t *hwif, unsigned long dmabase)
+-{
+-      ide_setup_dma(hwif, dmabase, 8);
+-}
+-
+ extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+ static int __devinit it8172_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+--- linux-2.6.0-test6/drivers/ide/pci/it8172.h 2003-06-14 12:18:08.000000000 -0700
++++ 25/drivers/ide/pci/it8172.h        2003-10-05 00:33:24.000000000 -0700
+@@ -17,7 +17,6 @@ static int it8172_config_chipset_for_dma
+ static void init_setup_it8172(struct pci_dev *, ide_pci_device_t *);
+ static unsigned int init_chipset_it8172(struct pci_dev *, const char *);
+ static void init_hwif_it8172(ide_hwif_t *);
+-static void init_dma_it8172(ide_hwif_t *, unsigned long);
+ static ide_pci_device_t it8172_chipsets[] __devinitdata = {
+       {       /* 0 */
+@@ -28,7 +27,6 @@ static ide_pci_device_t it8172_chipsets[
+               .init_chipset   = init_chipset_it8172,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_it8172,
+-                .init_dma     = init_dma_it8172,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x00,0x00,0x00}, {0x40,0x00,0x01}},
+--- linux-2.6.0-test6/drivers/ide/pci/Makefile 2003-06-14 12:17:59.000000000 -0700
++++ 25/drivers/ide/pci/Makefile        2003-10-05 00:36:28.000000000 -0700
+@@ -18,10 +18,10 @@ obj-$(CONFIG_BLK_DEV_NS87415)              += ns8741
+ obj-$(CONFIG_BLK_DEV_OPTI621)         += opti621.o
+ obj-$(CONFIG_BLK_DEV_PDC202XX_OLD)    += pdc202xx_old.o
+ obj-$(CONFIG_BLK_DEV_PDC202XX_NEW)    += pdc202xx_new.o
+-obj-$(CONFIG_BLK_DEV_PDC_ADMA)                += pdcadma.o ide-adma.o
+ obj-$(CONFIG_BLK_DEV_PIIX)            += piix.o
+ obj-$(CONFIG_BLK_DEV_RZ1000)          += rz1000.o
+ obj-$(CONFIG_BLK_DEV_SVWKS)           += serverworks.o
++obj-$(CONFIG_BLK_DEV_SGIIOC4)         += sgiioc4.o
+ obj-$(CONFIG_BLK_DEV_SIIMAGE)         += siimage.o
+ obj-$(CONFIG_BLK_DEV_SIS5513)         += sis5513.o
+ obj-$(CONFIG_BLK_DEV_SL82C105)                += sl82c105.o
+--- linux-2.6.0-test6/drivers/ide/pci/ns87415.c        2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/ide/pci/ns87415.c       2003-10-05 00:33:24.000000000 -0700
+@@ -217,11 +217,6 @@ static void __init init_hwif_ns87415 (id
+       hwif->drives[1].autodma = hwif->autodma;
+ }
+-static void __init init_dma_ns87415 (ide_hwif_t *hwif, unsigned long dmabase)
+-{
+-      ide_setup_dma(hwif, dmabase, 8);
+-}
+-
+ extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+ static int __devinit ns87415_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+--- linux-2.6.0-test6/drivers/ide/pci/ns87415.h        2003-06-14 12:17:57.000000000 -0700
++++ 25/drivers/ide/pci/ns87415.h       2003-10-05 00:33:24.000000000 -0700
+@@ -6,7 +6,6 @@
+ #include <linux/ide.h>
+ static void init_hwif_ns87415(ide_hwif_t *);
+-static void init_dma_ns87415(ide_hwif_t *, unsigned long);
+ static ide_pci_device_t ns87415_chipsets[] __devinitdata = {
+       {       /* 0 */
+@@ -16,7 +15,6 @@ static ide_pci_device_t ns87415_chipsets
+               .init_chipset   = NULL,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_ns87415,
+-                .init_dma     = init_dma_ns87415,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+--- linux-2.6.0-test6/drivers/ide/pci/opti621.c        2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/ide/pci/opti621.c       2003-10-05 00:33:24.000000000 -0700
+@@ -348,11 +348,6 @@ static void __init init_hwif_opti621 (id
+       hwif->drives[1].autodma = hwif->autodma;
+ }
+-static void __init init_dma_opti621 (ide_hwif_t *hwif, unsigned long dmabase)
+-{
+-      ide_setup_dma(hwif, dmabase, 8);
+-}
+-
+ extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+ static void __init init_setup_opti621 (struct pci_dev *dev, ide_pci_device_t *d)
+--- linux-2.6.0-test6/drivers/ide/pci/opti621.h        2003-06-14 12:18:33.000000000 -0700
++++ 25/drivers/ide/pci/opti621.h       2003-10-05 00:33:24.000000000 -0700
+@@ -7,7 +7,6 @@
+ static void init_setup_opti621(struct pci_dev *, ide_pci_device_t *);
+ static void init_hwif_opti621(ide_hwif_t *);
+-static void init_dma_opti621(ide_hwif_t *, unsigned long);
+ static ide_pci_device_t opti621_chipsets[] __devinitdata = {
+       {       /* 0 */
+@@ -18,7 +17,6 @@ static ide_pci_device_t opti621_chipsets
+               .init_chipset   = NULL,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_opti621,
+-              .init_dma       = init_dma_opti621,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x45,0x80,0x00}, {0x40,0x08,0x00}},
+@@ -32,7 +30,6 @@ static ide_pci_device_t opti621_chipsets
+               .init_chipset   = NULL,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_opti621,
+-                .init_dma     = init_dma_opti621,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x45,0x80,0x00}, {0x40,0x08,0x00}},
+--- linux-2.6.0-test6/drivers/ide/pci/pdc202xx_new.c   2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/ide/pci/pdc202xx_new.c  2003-10-05 00:33:24.000000000 -0700
+@@ -563,11 +563,6 @@ static void __init init_hwif_pdc202new (
+ #endif /* PDC202_DEBUG_CABLE */
+ }
+-static void __init init_dma_pdc202new (ide_hwif_t *hwif, unsigned long dmabase)
+-{
+-      ide_setup_dma(hwif, dmabase, 8);
+-}
+-
+ extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+ extern void ide_setup_pci_devices(struct pci_dev *, struct pci_dev *, ide_pci_device_t *);
+--- linux-2.6.0-test6/drivers/ide/pci/pdc202xx_new.h   2003-06-14 12:17:57.000000000 -0700
++++ 25/drivers/ide/pci/pdc202xx_new.h  2003-10-05 00:33:24.000000000 -0700
+@@ -188,7 +188,6 @@ static void init_setup_pdc20270(struct p
+ static void init_setup_pdc20276(struct pci_dev *dev, ide_pci_device_t *d);
+ static unsigned int init_chipset_pdcnew(struct pci_dev *, const char *);
+ static void init_hwif_pdc202new(ide_hwif_t *);
+-static void init_dma_pdc202new(ide_hwif_t *, unsigned long);
+ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
+       {       /* 0 */
+@@ -199,7 +198,6 @@ static ide_pci_device_t pdcnew_chipsets[
+               .init_chipset   = init_chipset_pdcnew,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_pdc202new,
+-              .init_dma       = init_dma_pdc202new,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+@@ -213,7 +211,6 @@ static ide_pci_device_t pdcnew_chipsets[
+               .init_chipset   = init_chipset_pdcnew,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_pdc202new,
+-              .init_dma       = init_dma_pdc202new,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+@@ -227,7 +224,6 @@ static ide_pci_device_t pdcnew_chipsets[
+               .init_chipset   = init_chipset_pdcnew,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_pdc202new,
+-              .init_dma       = init_dma_pdc202new,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+ #ifdef CONFIG_PDC202XX_FORCE
+@@ -245,7 +241,6 @@ static ide_pci_device_t pdcnew_chipsets[
+               .init_chipset   = init_chipset_pdcnew,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_pdc202new,
+-              .init_dma       = init_dma_pdc202new,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+@@ -259,7 +254,6 @@ static ide_pci_device_t pdcnew_chipsets[
+               .init_chipset   = init_chipset_pdcnew,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_pdc202new,
+-              .init_dma       = init_dma_pdc202new,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+@@ -273,7 +267,6 @@ static ide_pci_device_t pdcnew_chipsets[
+               .init_chipset   = init_chipset_pdcnew,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_pdc202new,
+-              .init_dma       = init_dma_pdc202new,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+ #ifdef CONFIG_PDC202XX_FORCE
+@@ -291,7 +284,6 @@ static ide_pci_device_t pdcnew_chipsets[
+               .init_chipset   = init_chipset_pdcnew,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_pdc202new,
+-              .init_dma       = init_dma_pdc202new,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+--- linux-2.6.0-test6/drivers/ide/pci/pdcadma.c        2003-09-08 13:58:57.000000000 -0700
++++ /dev/null  2002-08-30 16:31:37.000000000 -0700
+@@ -1,162 +0,0 @@
+-/*
+- * linux/drivers/ide/pci/pdcadma.c            Version 0.05    Sept 10, 2002
+- *
+- * Copyright (C) 1999-2000            Andre Hedrick <andre@linux-ide.org>
+- * May be copied or modified under the terms of the GNU General Public License
+- *
+- */
+-
+-#include <linux/config.h>
+-#include <linux/types.h>
+-#include <linux/kernel.h>
+-#include <linux/delay.h>
+-#include <linux/timer.h>
+-#include <linux/mm.h>
+-#include <linux/ioport.h>
+-#include <linux/blkdev.h>
+-#include <linux/hdreg.h>
+-
+-#include <linux/interrupt.h>
+-#include <linux/init.h>
+-#include <linux/pci.h>
+-#include <linux/ide.h>
+-
+-#include <asm/io.h>
+-#include <asm/irq.h>
+-
+-#include "pdcadma.h"
+-
+-#if defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS)
+-#include <linux/stat.h>
+-#include <linux/proc_fs.h>
+-
+-static u8 pdcadma_proc = 0;
+-#define PDC_MAX_DEVS          5
+-static struct pci_dev *pdc_devs[PDC_MAX_DEVS];
+-static int n_pdc_devs;
+-
+-static int pdcadma_get_info (char *buffer, char **addr, off_t offset, int count)
+-{
+-      char *p = buffer;
+-      int i;
+-
+-      for (i = 0; i < n_pdc_devs; i++) {
+-              struct pci_dev *dev     = pdc_devs[i];
+-              unsigned long bibma = pci_resource_start(dev, 4);
+-
+-              p += sprintf(p, "\n                                "
+-                      "PDC ADMA %04X Chipset.\n", dev->device);
+-              p += sprintf(p, "UDMA\n");
+-              p += sprintf(p, "PIO\n");
+-
+-      }
+-      return p-buffer;        /* => must be less than 4k! */
+-}
+-#endif  /* defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS) */
+-
+-/*
+- * pdcadma_dma functions() initiates/aborts (U)DMA read/write
+- * operations on a drive.
+- */
+-#if 0
+-        int (*ide_dma_read)(ide_drive_t *drive);
+-        int (*ide_dma_write)(ide_drive_t *drive);
+-        int (*ide_dma_begin)(ide_drive_t *drive);
+-        int (*ide_dma_end)(ide_drive_t *drive);
+-        int (*ide_dma_check)(ide_drive_t *drive);
+-        int (*ide_dma_on)(ide_drive_t *drive);
+-        int (*ide_dma_off)(ide_drive_t *drive);
+-        int (*ide_dma_off_quietly)(ide_drive_t *drive);
+-        int (*ide_dma_test_irq)(ide_drive_t *drive);
+-        int (*ide_dma_host_on)(ide_drive_t *drive);
+-        int (*ide_dma_host_off)(ide_drive_t *drive);
+-        int (*ide_dma_bad_drive)(ide_drive_t *drive);
+-        int (*ide_dma_good_drive)(ide_drive_t *drive);
+-        int (*ide_dma_count)(ide_drive_t *drive);
+-        int (*ide_dma_verbose)(ide_drive_t *drive);
+-        int (*ide_dma_retune)(ide_drive_t *drive);
+-        int (*ide_dma_lostirq)(ide_drive_t *drive);
+-        int (*ide_dma_timeout)(ide_drive_t *drive);
+-
+-#endif
+-
+-static unsigned int __init init_chipset_pdcadma (struct pci_dev *dev, const char *name)
+-{
+-#if defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS)
+-      pdc_devs[n_pdc_devs++] = dev;
+-
+-      if (!pdcadma_proc) {
+-              pdcadma_proc = 1;
+-              ide_pci_register_host_proc(&pdcadma_procs[0]);
+-      }
+-#endif /* DISPLAY_PDCADMA_TIMINGS && CONFIG_PROC_FS */
+-      return 0;
+-}
+-
+-static void __init init_hwif_pdcadma (ide_hwif_t *hwif)
+-{
+-      hwif->autodma = 0;
+-      hwif->dma_base = 0;
+-
+-//    hwif->tuneproc = &pdcadma_tune_drive;
+-//    hwif->speedproc = &pdcadma_tune_chipset;
+-
+-//    if (hwif->dma_base) {
+-//            hwif->autodma = 1;
+-//    }
+-
+-      hwif->udma_four = 1;
+-
+-//    hwif->atapi_dma = 1;
+-//    hwif->ultra_mask = 0x7f;
+-//    hwif->mwdma_mask = 0x07;
+-//    hwif->swdma_mask = 0x07;
+-
+-}
+-
+-static void __init init_dma_pdcadma (ide_hwif_t *hwif, unsigned long dmabase)
+-{
+-#if 0
+-      ide_setup_dma(hwif, dmabase, 8);
+-#endif
+-}
+-
+-extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+-
+-static int __devinit pdcadma_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+-{
+-      ide_pci_device_t *d = &pdcadma_chipsets[id->driver_data];
+-      if (dev->device != d->device)
+-              BUG();
+-      ide_setup_pci_device(dev, d);
+-      MOD_INC_USE_COUNT;
+-      return 1;
+-}
+-
+-static struct pci_device_id pdcadma_pci_tbl[] = {
+-      { PCI_VENDOR_ID_PDC, PCI_DEVICE_ID_PDC_1841, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+-      { 0, },
+-};
+-
+-static struct pci_driver driver = {
+-      .name           = "PDCADMA-IDE",
+-      .id_table       = pdcadma_pci_tbl,
+-      .probe          = pdcadma_init_one,
+-};
+-
+-static int pdcadma_ide_init(void)
+-{
+-      return ide_pci_register_driver(&driver);
+-}
+-
+-static void pdcadma_ide_exit(void)
+-{
+-      ide_pci_unregister_driver(&driver);
+-}
+-
+-module_init(pdcadma_ide_init);
+-module_exit(pdcadma_ide_exit);
+-
+-MODULE_AUTHOR("Andre Hedrick");
+-MODULE_DESCRIPTION("PCI driver module for PDCADMA IDE");
+-MODULE_LICENSE("GPL");
+--- linux-2.6.0-test6/drivers/ide/pci/pdcadma.h        2003-06-14 12:17:56.000000000 -0700
++++ /dev/null  2002-08-30 16:31:37.000000000 -0700
+@@ -1,56 +0,0 @@
+-#ifndef PDC_ADMA_H
+-#define PDC_ADMA_H
+-
+-#include <linux/config.h>
+-#include <linux/pci.h>
+-#include <linux/ide.h>
+-
+-#undef DISPLAY_PDCADMA_TIMINGS
+-
+-#if defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS)
+-#include <linux/stat.h>
+-#include <linux/proc_fs.h>
+-
+-static u8 pdcadma_proc;
+-
+-static int pdcadma_get_info(char *, char **, off_t, int);
+-
+-static ide_pci_host_proc_t pdcadma_procs[] __initdata = {
+-      {
+-              .name           = "pdcadma",
+-              .set            = 1,
+-              .get_info       = pdcadma_get_info,
+-              .parent         = NULL,
+-      },
+-};
+-#endif  /* defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS) */
+-
+-static void init_setup_pdcadma(struct pci_dev *, ide_pci_device_t *);
+-static unsigned int init_chipset_pdcadma(struct pci_dev *, const char *);
+-static void init_hwif_pdcadma(ide_hwif_t *);
+-static void init_dma_pdcadma(ide_hwif_t *, unsigned long);
+-
+-static ide_pci_device_t pdcadma_chipsets[] __devinitdata = {
+-      {       /* 0 */
+-              .vendor         = PCI_VENDOR_ID_PDC,
+-              .device         = PCI_DEVICE_ID_PDC_1841,
+-              .name           = "PDCADMA",
+-              .init_setup     = init_setup_pdcadma,
+-              .init_chipset   = init_chipset_pdcadma,
+-              .init_iops      = NULL,
+-              .init_hwif      = init_hwif_pdcadma,
+-              .init_dma       = init_dma_pdcadma,
+-              .channels       = 2,
+-              .autodma        = NODMA,
+-              .enablebits     = {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+-              .bootable       = OFF_BOARD,
+-              .extra          = 0,
+-      },{
+-              .vendor         = 0,
+-              .device         = 0,
+-              .channels       = 0,
+-              .bootable       = EOL,
+-      }
+-};
+-
+-#endif /* PDC_ADMA_H */
+--- linux-2.6.0-test6/drivers/ide/pci/piix.c   2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/ide/pci/piix.c  2003-10-05 00:33:24.000000000 -0700
+@@ -709,21 +709,6 @@ static void __init init_hwif_piix (ide_h
+       hwif->drives[0].autodma = hwif->autodma;
+ }
+-/**
+- *    init_dma_piix           -       set up the PIIX DMA
+- *    @hwif: IDE interface
+- *    @dmabase: DMA PCI base
+- *
+- *    Set up the DMA on the PIIX controller, providing a DMA base is
+- *    available. The PIIX follows the normal specs so we do nothing
+- *    magical here.
+- */
+-
+-static void __init init_dma_piix (ide_hwif_t *hwif, unsigned long dmabase)
+-{
+-      ide_setup_dma(hwif, dmabase, 8);
+-}
+-
+ extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+ /**
+--- linux-2.6.0-test6/drivers/ide/pci/piix.h   2003-06-14 12:18:00.000000000 -0700
++++ 25/drivers/ide/pci/piix.h  2003-10-05 00:33:24.000000000 -0700
+@@ -30,8 +30,6 @@ static ide_pci_host_proc_t piix_procs[] 
+ static void init_setup_piix(struct pci_dev *, ide_pci_device_t *);
+ static unsigned int __devinit init_chipset_piix(struct pci_dev *, const char *);
+ static void init_hwif_piix(ide_hwif_t *);
+-static void init_dma_piix(ide_hwif_t *, unsigned long);
+-
+ /*
+  *    Table of the various PIIX capability blocks
+@@ -47,7 +45,6 @@ static ide_pci_device_t piix_pci_info[] 
+               .init_chipset   = init_chipset_piix,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_piix,
+-              .init_dma       = init_dma_piix,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+@@ -61,7 +58,6 @@ static ide_pci_device_t piix_pci_info[] 
+               .init_chipset   = init_chipset_piix,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_piix,
+-              .init_dma       = init_dma_piix,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+@@ -75,7 +71,6 @@ static ide_pci_device_t piix_pci_info[] 
+               .init_chipset   = NULL,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_piix,
+-              .init_dma       = NULL,
+               .channels       = 2,
+               .autodma        = NODMA,
+               .enablebits     = {{0x6D,0x80,0x80}, {0x6F,0x80,0x80}},
+@@ -89,7 +84,6 @@ static ide_pci_device_t piix_pci_info[] 
+               .init_chipset   = init_chipset_piix,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_piix,
+-              .init_dma       = init_dma_piix,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+@@ -103,7 +97,6 @@ static ide_pci_device_t piix_pci_info[] 
+               .init_chipset   = init_chipset_piix,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_piix,
+-              .init_dma       = init_dma_piix,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+@@ -117,7 +110,6 @@ static ide_pci_device_t piix_pci_info[] 
+               .init_chipset   = init_chipset_piix,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_piix,
+-              .init_dma       = init_dma_piix,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+@@ -131,7 +123,6 @@ static ide_pci_device_t piix_pci_info[] 
+               .init_chipset   = init_chipset_piix,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_piix,
+-              .init_dma       = init_dma_piix,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+@@ -145,7 +136,6 @@ static ide_pci_device_t piix_pci_info[] 
+               .init_chipset   = init_chipset_piix,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_piix,
+-              .init_dma       = init_dma_piix,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+@@ -159,7 +149,6 @@ static ide_pci_device_t piix_pci_info[] 
+               .init_chipset   = init_chipset_piix,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_piix,
+-              .init_dma       = init_dma_piix,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+@@ -173,7 +162,6 @@ static ide_pci_device_t piix_pci_info[] 
+               .init_chipset   = init_chipset_piix,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_piix,
+-              .init_dma       = init_dma_piix,
+               .channels       = 2,
+               .autodma        = NOAUTODMA,
+               .enablebits     = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+@@ -187,7 +175,6 @@ static ide_pci_device_t piix_pci_info[] 
+               .init_chipset   = init_chipset_piix,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_piix,
+-              .init_dma       = init_dma_piix,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+@@ -201,7 +188,6 @@ static ide_pci_device_t piix_pci_info[] 
+               .init_chipset   = init_chipset_piix,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_piix,
+-              .init_dma       = init_dma_piix,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+@@ -215,7 +201,6 @@ static ide_pci_device_t piix_pci_info[] 
+               .init_chipset   = init_chipset_piix,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_piix,
+-              .init_dma       = init_dma_piix,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+@@ -229,7 +214,6 @@ static ide_pci_device_t piix_pci_info[] 
+               .init_chipset   = init_chipset_piix,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_piix,
+-              .init_dma       = init_dma_piix,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+@@ -243,7 +227,6 @@ static ide_pci_device_t piix_pci_info[] 
+               .init_chipset   = init_chipset_piix,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_piix,
+-              .init_dma       = init_dma_piix,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+@@ -257,7 +240,6 @@ static ide_pci_device_t piix_pci_info[] 
+               .init_chipset   = init_chipset_piix,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_piix,
+-              .init_dma       = init_dma_piix,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+@@ -271,7 +253,6 @@ static ide_pci_device_t piix_pci_info[] 
+               .init_chipset   = init_chipset_piix,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_piix,
+-              .init_dma       = init_dma_piix,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+@@ -285,7 +266,6 @@ static ide_pci_device_t piix_pci_info[] 
+               .init_chipset   = init_chipset_piix,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_piix,
+-              .init_dma       = init_dma_piix,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+@@ -299,7 +279,6 @@ static ide_pci_device_t piix_pci_info[] 
+               .init_chipset   = init_chipset_piix,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_piix,
+-              .init_dma       = init_dma_piix,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+--- linux-2.6.0-test6/drivers/ide/pci/sc1200.c 2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/ide/pci/sc1200.c        2003-10-05 00:33:24.000000000 -0700
+@@ -396,44 +396,44 @@ typedef struct sc1200_saved_state_s {
+       __u32           regs[4];
+ } sc1200_saved_state_t;
+-static int sc1200_save_state (struct pci_dev *dev, u32 state)
++
++static int sc1200_suspend (struct pci_dev *dev, u32 state)
+ {
+       ide_hwif_t              *hwif = NULL;
+-printk("SC1200: save_state(%u)\n", state);
+-      if (state != 0)
+-              return 0;       // we only save state when going from full power to less
+-      //
+-      // Loop over all interfaces that are part of this PCI device:
+-      //
+-      while ((hwif = lookup_pci_dev(hwif, dev)) != NULL) {
+-              sc1200_saved_state_t    *ss;
+-              unsigned int            basereg, r;
+-              //
+-              // allocate a permanent save area, if not already allocated
+-              //
+-              ss = (sc1200_saved_state_t *)hwif->config_data;
+-              if (ss == NULL) {
+-                      ss = kmalloc(sizeof(sc1200_saved_state_t), GFP_KERNEL);
+-                      if (ss == NULL)
+-                              return -ENOMEM;
+-                      (sc1200_saved_state_t *)hwif->config_data = ss;
+-              }
+-              ss = (sc1200_saved_state_t *)hwif->config_data;
++      printk("SC1200: suspend(%u)\n", state);
++
++      if (state == 0) {
++              // we only save state when going from full power to less
++
+               //
+-              // Save timing registers:  this may be unnecessary if BIOS also does it
++              // Loop over all interfaces that are part of this PCI device:
+               //
+-              basereg = hwif->channel ? 0x50 : 0x40;
+-              for (r = 0; r < 4; ++r) {
+-                      pci_read_config_dword (hwif->pci_dev, basereg + (r<<2), &ss->regs[r]);
++              while ((hwif = lookup_pci_dev(hwif, dev)) != NULL) {
++                      sc1200_saved_state_t    *ss;
++                      unsigned int            basereg, r;
++                      //
++                      // allocate a permanent save area, if not already allocated
++                      //
++                      ss = (sc1200_saved_state_t *)hwif->config_data;
++                      if (ss == NULL) {
++                              ss = kmalloc(sizeof(sc1200_saved_state_t), GFP_KERNEL);
++                              if (ss == NULL)
++                                      return -ENOMEM;
++                              (sc1200_saved_state_t *)hwif->config_data = ss;
++                      }
++                      ss = (sc1200_saved_state_t *)hwif->config_data;
++                      //
++                      // Save timing registers:  this may be unnecessary if 
++                      // BIOS also does it
++                      //
++                      basereg = hwif->channel ? 0x50 : 0x40;
++                      for (r = 0; r < 4; ++r) {
++                              pci_read_config_dword (hwif->pci_dev, basereg + (r<<2), &ss->regs[r]);
++                      }
+               }
+       }
+-      return 0;
+-}
+-static int sc1200_suspend (struct pci_dev *dev, u32 state)
+-{
+-      printk("SC1200: suspend(%u)\n", state);
+       /* You don't need to iterate over disks -- sysfs should have done that for you already */ 
+       pci_disable_device(dev);
+@@ -545,11 +545,6 @@ static void __init init_hwif_sc1200 (ide
+         hwif->drives[1].autodma = hwif->autodma;
+ }
+-static void __init init_dma_sc1200 (ide_hwif_t *hwif, unsigned long dmabase)
+-{
+-      ide_setup_dma(hwif, dmabase, 8);
+-}
+-
+ extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+@@ -572,7 +567,6 @@ static struct pci_driver driver = {
+       .name           = "SC1200 IDE",
+       .id_table       = sc1200_pci_tbl,
+       .probe          = sc1200_init_one,
+-      .save_state     = sc1200_save_state,
+       .suspend        = sc1200_suspend,
+       .resume         = sc1200_resume,
+ };
+--- linux-2.6.0-test6/drivers/ide/pci/sc1200.h 2003-06-14 12:18:05.000000000 -0700
++++ 25/drivers/ide/pci/sc1200.h        2003-10-05 00:33:24.000000000 -0700
+@@ -27,7 +27,6 @@ static ide_pci_host_proc_t sc1200_procs[
+ static unsigned int init_chipset_sc1200(struct pci_dev *, const char *);
+ static void init_hwif_sc1200(ide_hwif_t *);
+-static void init_dma_sc1200(ide_hwif_t *, unsigned long);
+ static ide_pci_device_t sc1200_chipsets[] __devinitdata = {
+       {       /* 0 */
+@@ -37,7 +36,6 @@ static ide_pci_device_t sc1200_chipsets[
+               .init_chipset   = init_chipset_sc1200,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_sc1200,
+-              .init_dma       = init_dma_sc1200,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/drivers/ide/pci/sgiioc4.c       2003-10-05 00:36:28.000000000 -0700
+@@ -0,0 +1,1053 @@
++/*
++ * Copyright (c) 2003 Silicon Graphics, Inc.  All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of version 2 of the GNU General Public License
++ * as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it would be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * You should have received a copy of the GNU General Public
++ * License along with this program; if not, write the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
++ *
++ * Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
++ * Mountain View, CA  94043, or:
++ *
++ * http://www.sgi.com
++ *
++ * For further information regarding this notice, see:
++ *
++ * http://oss.sgi.com/projects/GenInfo/NoticeExplan
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/pci.h>
++#include <linux/delay.h>
++#include <linux/hdreg.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/timer.h>
++#include <linux/mm.h>
++#include <linux/ioport.h>
++#include <linux/blkdev.h>
++#include <asm/io.h>
++
++#define IDE_ARCH_ACK_INTR     1
++#include <linux/ide.h>
++
++/* IOC4 Specific Definitions */
++#define IOC4_CMD_OFFSET               0x100
++#define IOC4_CTRL_OFFSET      0x120
++#define IOC4_DMA_OFFSET               0x140
++#define IOC4_INTR_OFFSET      0x0
++
++#define IOC4_TIMING           0x00
++#define IOC4_DMA_PTR_L                0x01
++#define IOC4_DMA_PTR_H                0x02
++#define IOC4_DMA_ADDR_L               0x03
++#define IOC4_DMA_ADDR_H               0x04
++#define IOC4_BC_DEV           0x05
++#define IOC4_BC_MEM           0x06
++#define       IOC4_DMA_CTRL           0x07
++#define       IOC4_DMA_END_ADDR       0x08
++
++/* Bits in the IOC4 Control/Status Register */
++#define       IOC4_S_DMA_START        0x01
++#define       IOC4_S_DMA_STOP         0x02
++#define       IOC4_S_DMA_DIR          0x04
++#define       IOC4_S_DMA_ACTIVE       0x08
++#define       IOC4_S_DMA_ERROR        0x10
++#define       IOC4_ATA_MEMERR         0x02
++
++/* Read/Write Directions */
++#define       IOC4_DMA_WRITE          0x04
++#define       IOC4_DMA_READ           0x00
++
++/* Interrupt Register Offsets */
++#define IOC4_INTR_REG         0x03
++#define       IOC4_INTR_SET           0x05
++#define       IOC4_INTR_CLEAR         0x07
++
++#define IOC4_IDE_CACHELINE_SIZE       128
++#define IOC4_CMD_CTL_BLK_SIZE 0x20
++#define IOC4_SUPPORTED_FIRMWARE_REV 46
++
++/* Weeds out non-IDE interrupts to the IOC4 */
++#define ide_ack_intr(hwif) ((hwif)->hw.ack_intr ? (hwif)->hw.ack_intr(hwif) : 1)
++
++#define SGIIOC4_MAX_DEVS      32
++
++#if  defined(CONFIG_PROC_FS)
++#include <linux/stat.h>
++#include <linux/proc_fs.h>
++
++static u8 sgiioc4_proc;
++
++static struct pci_dev *sgiioc4_devs[SGIIOC4_MAX_DEVS];
++static int sgiioc4_get_info(char *, char **, off_t, int);
++
++static ide_pci_host_proc_t sgiioc4_procs[] __initdata = {
++      {
++       .name = "sgiioc4",
++       .set = 1,
++       .get_info = sgiioc4_get_info,
++       .parent = NULL,
++       }
++};
++#endif
++
++typedef struct {
++      u32 timing_reg0;
++      u32 timing_reg1;
++      u32 low_mem_ptr;
++      u32 high_mem_ptr;
++      u32 low_mem_addr;
++      u32 high_mem_addr;
++      u32 dev_byte_count;
++      u32 mem_byte_count;
++      u32 status;
++} ioc4_dma_regs_t;
++
++/* Each Physical Region Descriptor Entry size is 16 bytes (2 * 64 bits) */
++/* IOC4 has only 1 IDE channel */
++#define IOC4_PRD_BYTES       16
++#define IOC4_PRD_ENTRIES     (PAGE_SIZE /(4*IOC4_PRD_BYTES))
++
++typedef enum pciio_endian_e {
++      PCIDMA_ENDIAN_BIG,
++      PCIDMA_ENDIAN_LITTLE
++} pciio_endian_t;
++
++static void sgiioc4_init_hwif_ports(hw_regs_t * hw, unsigned long data_port,
++                                  unsigned long ctrl_port,
++                                  unsigned long irq_port);
++static void sgiioc4_ide_setup_pci_device(struct pci_dev *dev,
++                                       ide_pci_device_t * d);
++static void sgiioc4_resetproc(ide_drive_t * drive);
++static void sgiioc4_maskproc(ide_drive_t * drive, int mask);
++static void sgiioc4_configure_for_dma(int dma_direction, ide_drive_t * drive);
++static void __init ide_init_sgiioc4(ide_hwif_t * hwif);
++static void __init ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base);
++static int sgiioc4_checkirq(ide_hwif_t * hwif);
++static int sgiioc4_clearirq(ide_drive_t * drive);
++static int sgiioc4_get_info(char *buffer, char **addr, off_t offset, int count);
++static int sgiioc4_ide_dma_read(ide_drive_t * drive);
++static int sgiioc4_ide_dma_write(ide_drive_t * drive);
++static int sgiioc4_ide_dma_begin(ide_drive_t * drive);
++static int sgiioc4_ide_dma_end(ide_drive_t * drive);
++static int sgiioc4_ide_dma_check(ide_drive_t * drive);
++static int sgiioc4_ide_dma_on(ide_drive_t * drive);
++static int sgiioc4_ide_dma_off(ide_drive_t * drive);
++static int sgiioc4_ide_dma_off_quietly(ide_drive_t * drive);
++static int sgiioc4_ide_dma_test_irq(ide_drive_t * drive);
++static int sgiioc4_ide_dma_host_on(ide_drive_t * drive);
++static int sgiioc4_ide_dma_host_off(ide_drive_t * drive);
++static int sgiioc4_ide_dma_count(ide_drive_t * drive);
++static int sgiioc4_ide_dma_verbose(ide_drive_t * drive);
++static int sgiioc4_ide_dma_lostirq(ide_drive_t * drive);
++static int sgiioc4_ide_dma_timeout(ide_drive_t * drive);
++static int sgiioc4_ide_build_sglist(ide_drive_t * drive, struct request *rq);
++static int sgiioc4_ide_raw_build_sglist(ide_drive_t * drive,
++                                      struct request *rq);
++static u8 sgiioc4_INB(unsigned long port);
++static inline void xide_delay(long ticks);
++static unsigned int sgiioc4_build_dma_table(ide_drive_t * drive,
++                                          struct request *rq, int ddir);
++static unsigned int __init pci_init_sgiioc4(struct pci_dev *dev,
++                                          ide_pci_device_t * d);
++
++static ide_pci_device_t sgiioc4_chipsets[] __devinitdata = {
++      {
++       /* Channel 0 */
++       .vendor = PCI_VENDOR_ID_SGI,
++       .device = PCI_DEVICE_ID_SGI_IOC4,
++       .name = "SGIIOC4",
++       .init_chipset = NULL,
++       .init_iops = NULL,
++       .init_hwif = ide_init_sgiioc4,
++       .init_dma = ide_dma_sgiioc4,
++       .channels = 1,
++       .autodma = AUTODMA,
++       .enablebits = {{0x00, 0x00, 0x00}, {0x00, 0x00, 0x00}},
++       .bootable = ON_BOARD,
++       .extra = 0,
++       }
++};
++
++#ifdef CONFIG_PROC_FS
++static u8 sgiioc4_proc;
++#endif                                /* CONFIG_PROC_FS */
++
++static int n_sgiioc4_devs;
++
++static inline void
++xide_delay(long ticks)
++{
++      if (!ticks)
++              return;
++
++      current->state = TASK_UNINTERRUPTIBLE;
++      schedule_timeout(ticks);
++}
++static void __init
++sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d)
++{
++      unsigned long base = 0, ctl = 0, dma_base = 0, irqport = 0;
++      ide_hwif_t *hwif = NULL;
++      int h = 0;
++
++      /*  Get the CmdBlk and CtrlBlk Base Registers */
++      base = pci_resource_start(dev, 0) + IOC4_CMD_OFFSET;
++      ctl = pci_resource_start(dev, 0) + IOC4_CTRL_OFFSET;
++      irqport = pci_resource_start(dev, 0) + IOC4_INTR_OFFSET;
++      dma_base = pci_resource_start(dev, 0) + IOC4_DMA_OFFSET;
++
++      if (!request_region(base, IOC4_CMD_CTL_BLK_SIZE, hwif->name)) {
++              printk(KERN_ERR
++                      "%s : %s -- Warning, Port Addresses "
++                      "0x%p to 0x%p ALREADY in use\n",
++                     __FUNCTION__, hwif->name, (void *) base,
++                     (void *) base + IOC4_CMD_CTL_BLK_SIZE);
++      }
++
++      for (h = 0; h < MAX_HWIFS; ++h) {
++              hwif = &ide_hwifs[h];
++              /* Find an empty HWIF */
++              if (hwif->chipset == ide_unknown)
++                      break;
++      }
++
++      if (hwif->io_ports[IDE_DATA_OFFSET] != base) {
++              /* Initialize the IO registers */
++              sgiioc4_init_hwif_ports(&hwif->hw, base, ctl, irqport);
++              memcpy(hwif->io_ports, hwif->hw.io_ports,
++                     sizeof (hwif->io_ports));
++              hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
++      }
++
++      hwif->irq = dev->irq;
++      hwif->chipset = ide_pci;
++      hwif->pci_dev = dev;
++      hwif->channel = 0;      /* Single Channel chip */
++      hwif->cds = (struct ide_pci_device_s *) d;
++      hwif->hw.ack_intr = &sgiioc4_checkirq;  /* MultiFunction Chip */
++      hwif->gendev.parent = &dev->dev;/* setup proper ancestral information */
++
++      /* Initializing chipset IRQ Registers */
++      hwif->OUTL(0x03, irqport + IOC4_INTR_SET * 4);
++
++      (void) ide_init_sgiioc4(hwif);
++
++      if (dma_base)
++              ide_dma_sgiioc4(hwif, dma_base);
++      else
++              printk(KERN_INFO "%s: %s Bus-Master DMA disabled\n",
++                     hwif->name, d->name);
++
++      probe_hwif_init(hwif);
++}
++
++/* This ensures that we can build this for generic kernels without
++ * having all the SN2 code sync'd and merged.
++ */
++
++pciio_endian_t __attribute__ ((weak)) snia_pciio_endian_set(struct pci_dev
++                                          *pci_dev, pciio_endian_t device_end,
++                                          pciio_endian_t desired_end);
++
++static unsigned int __init
++pci_init_sgiioc4(struct pci_dev *dev, ide_pci_device_t * d)
++{
++      if (pci_enable_device(dev)) {
++              printk(KERN_INFO
++                     "Failed to enable device %s at slot %s\n",
++                     d->name, dev->slot_name);
++              return 1;
++      }
++      pci_set_master(dev);
++
++      /* Enable Byte Swapping in the PIC... */
++      if (snia_pciio_endian_set) {
++              snia_pciio_endian_set(dev, PCIDMA_ENDIAN_LITTLE,
++                                    PCIDMA_ENDIAN_BIG);
++      } else {
++              printk(KERN_INFO
++                     "Failed to set endianness for device %s at slot %s\n",
++                     d->name, dev->slot_name);
++              return 1;
++      }
++
++#ifdef CONFIG_PROC_FS
++      sgiioc4_devs[n_sgiioc4_devs++] = dev;
++      if (!sgiioc4_proc) {
++              sgiioc4_proc = 1;
++              ide_pci_register_host_proc(&sgiioc4_procs[0]);
++      }
++#endif
++      sgiioc4_ide_setup_pci_device(dev, d);
++
++      return 0;
++}
++
++static void
++sgiioc4_init_hwif_ports(hw_regs_t * hw, unsigned long data_port,
++                      unsigned long ctrl_port, unsigned long irq_port)
++{
++      unsigned long reg = data_port;
++      int i;
++
++      /* Registers are word (32 bit) aligned */
++      for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
++              hw->io_ports[i] = reg + i * 4;
++
++      if (ctrl_port)
++              hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
++
++      if (irq_port)
++              hw->io_ports[IDE_IRQ_OFFSET] = irq_port;
++}
++
++static void
++sgiioc4_resetproc(ide_drive_t * drive)
++{
++      sgiioc4_ide_dma_end(drive);
++      sgiioc4_clearirq(drive);
++}
++
++static void
++sgiioc4_maskproc(ide_drive_t * drive, int mask)
++{
++      ide_hwif_t *hwif = HWIF(drive);
++      hwif->OUTB(mask ? (drive->ctl | 2) : (drive->ctl & ~2),
++                 IDE_CONTROL_REG);
++}
++
++static void __init
++ide_init_sgiioc4(ide_hwif_t * hwif)
++{
++      hwif->mmio = 2;
++      hwif->autodma = 1;
++      hwif->atapi_dma = 1;
++      hwif->ultra_mask = 0x0; /* Disable Ultra DMA */
++      hwif->mwdma_mask = 0x2; /* Multimode-2 DMA  */
++      hwif->swdma_mask = 0x2;
++      hwif->identify = NULL;
++      hwif->tuneproc = NULL;  /* Sets timing for PIO mode */
++      hwif->speedproc = NULL; /* Sets timing for DMA &/or PIO modes */
++      hwif->selectproc = NULL;/* Use the default routine to select drive */
++      hwif->reset_poll = NULL;/* No HBA specific reset_poll needed */
++      hwif->pre_reset = NULL; /* No HBA specific pre_set needed */
++      hwif->resetproc = &sgiioc4_resetproc;/* Reset DMA engine,
++                                              clear interrupts */
++      hwif->intrproc = NULL;  /* Enable or Disable interrupt from drive */
++      hwif->maskproc = &sgiioc4_maskproc;     /* Mask on/off NIEN register */
++      hwif->quirkproc = NULL;
++      hwif->busproc = NULL;
++
++      hwif->ide_dma_read = &sgiioc4_ide_dma_read;
++      hwif->ide_dma_write = &sgiioc4_ide_dma_write;
++      hwif->ide_dma_begin = &sgiioc4_ide_dma_begin;
++      hwif->ide_dma_end = &sgiioc4_ide_dma_end;
++      hwif->ide_dma_check = &sgiioc4_ide_dma_check;
++      hwif->ide_dma_on = &sgiioc4_ide_dma_on;
++      hwif->ide_dma_off = &sgiioc4_ide_dma_off;
++      hwif->ide_dma_off_quietly = &sgiioc4_ide_dma_off_quietly;
++      hwif->ide_dma_test_irq = &sgiioc4_ide_dma_test_irq;
++      hwif->ide_dma_host_on = &sgiioc4_ide_dma_host_on;
++      hwif->ide_dma_host_off = &sgiioc4_ide_dma_host_off;
++      hwif->ide_dma_bad_drive = &__ide_dma_bad_drive;
++      hwif->ide_dma_good_drive = &__ide_dma_good_drive;
++      hwif->ide_dma_count = &sgiioc4_ide_dma_count;
++      hwif->ide_dma_verbose = &sgiioc4_ide_dma_verbose;
++      hwif->ide_dma_retune = &__ide_dma_retune;
++      hwif->ide_dma_lostirq = &sgiioc4_ide_dma_lostirq;
++      hwif->ide_dma_timeout = &sgiioc4_ide_dma_timeout;
++      hwif->INB = &sgiioc4_INB;
++}
++
++static int
++sgiioc4_ide_dma_read(ide_drive_t * drive)
++{
++      struct request *rq = HWGROUP(drive)->rq;
++      unsigned int count = 0;
++
++      if (!(count = sgiioc4_build_dma_table(drive, rq, PCI_DMA_FROMDEVICE))) {
++              /* try PIO instead of DMA */
++              return 1;
++      }
++      /* Writes FROM the IOC4 TO Main Memory */
++      sgiioc4_configure_for_dma(IOC4_DMA_WRITE, drive);
++
++      return 0;
++}
++
++static int
++sgiioc4_ide_dma_write(ide_drive_t * drive)
++{
++      struct request *rq = HWGROUP(drive)->rq;
++      unsigned int count = 0;
++
++      if (!(count = sgiioc4_build_dma_table(drive, rq, PCI_DMA_TODEVICE))) {
++              /* try PIO instead of DMA */
++              return 1;
++      }
++
++      sgiioc4_configure_for_dma(IOC4_DMA_READ, drive);
++      /* Writes TO the IOC4 FROM Main Memory */
++
++      return 0;
++}
++
++static int
++sgiioc4_ide_dma_begin(ide_drive_t * drive)
++{
++      ide_hwif_t *hwif = HWIF(drive);
++      unsigned int reg = hwif->INL(hwif->dma_base + IOC4_DMA_CTRL * 4);
++      unsigned int temp_reg = reg | IOC4_S_DMA_START;
++
++      hwif->OUTL(temp_reg, hwif->dma_base + IOC4_DMA_CTRL * 4);
++
++      return 0;
++}
++
++/* Stops the IOC4 DMA Engine */
++static int
++sgiioc4_ide_dma_end(ide_drive_t * drive)
++{
++      u32 ioc4_dma, bc_dev, bc_mem, num, valid = 0, cnt = 0;
++      ide_hwif_t *hwif = HWIF(drive);
++      uint64_t dma_base = hwif->dma_base;
++      int dma_stat = 0, count;
++      unsigned long *ending_dma = (unsigned long *) hwif->dma_base2;
++
++      hwif->OUTL(IOC4_S_DMA_STOP, dma_base + IOC4_DMA_CTRL * 4);
++
++      count = 0;
++      do {
++              xide_delay(count);
++              ioc4_dma = hwif->INL(dma_base + IOC4_DMA_CTRL * 4);
++              count += 10;
++      } while ((ioc4_dma & IOC4_S_DMA_STOP) && (count < 100));
++
++      if (ioc4_dma & IOC4_S_DMA_STOP) {
++              printk(KERN_ERR
++                     "%s(%s): IOC4 DMA STOP bit is still 1 :"
++                     "ioc4_dma_reg 0x%x\n",
++                     __FUNCTION__, drive->name, ioc4_dma);
++              dma_stat = 1;
++      }
++
++      if (ending_dma) {
++              do {
++                      for (num = 0; num < 16; num++) {
++                              if (ending_dma[num] & (~0ul)) {
++                                      valid = 1;
++                                      break;
++                              }
++                      }
++                      xide_delay(cnt);
++              } while ((cnt++ < 100) && (!valid));
++      }
++
++      if (!valid)
++              printk(KERN_INFO "%s(%s) : Stale DMA Data in Memory\n",
++                     __FUNCTION__, drive->name);
++
++      bc_dev = hwif->INL(dma_base + IOC4_BC_DEV * 4);
++      bc_mem = hwif->INL(dma_base + IOC4_BC_MEM * 4);
++
++      if ((bc_dev & 0x01FF) || (bc_mem & 0x1FF)) {
++              if (bc_dev > bc_mem + 8) {
++                      printk(KERN_ERR
++                             "%s(%s): WARNING!! byte_count_dev %d "
++                             "!= byte_count_mem %d\n",
++                             __FUNCTION__, drive->name, bc_dev, bc_mem);
++              }
++      }
++
++      drive->waiting_for_dma = 0;
++      ide_destroy_dmatable(drive);
++
++      return dma_stat;
++}
++
++static int
++sgiioc4_ide_dma_check(ide_drive_t * drive)
++{
++      if (ide_config_drive_speed(drive, XFER_MW_DMA_2) != 0) {
++              printk(KERN_INFO
++                     "Couldnot set %s in Multimode-2 DMA mode | "
++                         "Drive %s using PIO instead\n",
++                     drive->name, drive->name);
++              drive->using_dma = 0;
++      } else
++              drive->using_dma = 1;
++
++      return 0;
++}
++
++static int
++sgiioc4_ide_dma_on(ide_drive_t * drive)
++{
++      drive->using_dma = 1;
++
++      return HWIF(drive)->ide_dma_host_on(drive);
++}
++
++static int
++sgiioc4_ide_dma_off(ide_drive_t * drive)
++{
++      printk(KERN_INFO "%s: DMA disabled\n", drive->name);
++
++      return HWIF(drive)->ide_dma_off_quietly(drive);
++}
++
++static int
++sgiioc4_ide_dma_off_quietly(ide_drive_t * drive)
++{
++      drive->using_dma = 0;
++
++      return HWIF(drive)->ide_dma_host_off(drive);
++}
++
++/* returns 1 if dma irq issued, 0 otherwise */
++static int
++sgiioc4_ide_dma_test_irq(ide_drive_t * drive)
++{
++      return sgiioc4_checkirq(HWIF(drive));
++}
++
++static int
++sgiioc4_ide_dma_host_on(ide_drive_t * drive)
++{
++      if (drive->using_dma)
++              return 0;
++
++      return 1;
++}
++
++static int
++sgiioc4_ide_dma_host_off(ide_drive_t * drive)
++{
++      sgiioc4_clearirq(drive);
++
++      return 0;
++}
++
++static int
++sgiioc4_ide_dma_count(ide_drive_t * drive)
++{
++      return HWIF(drive)->ide_dma_begin(drive);
++}
++
++static int
++sgiioc4_ide_dma_verbose(ide_drive_t * drive)
++{
++      if (drive->using_dma == 1)
++              printk(", UDMA(16)");
++      else
++              printk(", PIO");
++
++      return 1;
++}
++
++static int
++sgiioc4_ide_dma_lostirq(ide_drive_t * drive)
++{
++      HWIF(drive)->resetproc(drive);
++
++      return __ide_dma_lostirq(drive);
++}
++
++static int
++sgiioc4_ide_dma_timeout(ide_drive_t * drive)
++{
++      printk(KERN_ERR "%s: timeout waiting for DMA\n", drive->name);
++      if (HWIF(drive)->ide_dma_test_irq(drive))
++              return 0;
++
++      return HWIF(drive)->ide_dma_end(drive);
++}
++
++static u8
++sgiioc4_INB(unsigned long port)
++{
++      u8 reg = (u8) inb(port);
++
++      if ((port & 0xFFF) == 0x11C) {  /* Status register of IOC4 */
++              if (reg & 0x51) {       /* Not busy...check for interrupt */
++                      unsigned long other_ir = port - 0x110;
++                      unsigned int intr_reg = (u32) inl(other_ir);
++
++                      /* Clear the Interrupt, Error bits on the IOC4 */
++                      if (intr_reg & 0x03) {
++                              outl(0x03, other_ir);
++                              intr_reg = (u32) inl(other_ir);
++                      }
++              }
++      }
++
++      return reg;
++}
++
++/* Creates a dma map for the scatter-gather list entries */
++static void __init
++ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base)
++{
++      int num_ports = sizeof (ioc4_dma_regs_t);
++
++      printk(KERN_INFO "%s: BM-DMA at 0x%04lx-0x%04lx\n", hwif->name,
++             dma_base, dma_base + num_ports - 1);
++
++      if (!request_region(dma_base, num_ports, hwif->name)) {
++              printk(KERN_ERR
++                     "%s(%s) -- WARNING, Addresses 0x%p to 0x%p "
++                     "ALREADY in use\n",
++                     __FUNCTION__, hwif->name, (void *) dma_base,
++                     (void *) dma_base + num_ports - 1);
++      }
++
++      hwif->dma_base = dma_base;
++      hwif->dmatable_cpu = pci_alloc_consistent(hwif->pci_dev,
++                                        IOC4_PRD_ENTRIES * IOC4_PRD_BYTES,
++                                        &hwif->dmatable_dma);
++
++      if (!hwif->dmatable_cpu)
++              goto dma_alloc_failure;
++
++      hwif->sg_table =
++          kmalloc(sizeof (struct scatterlist) * IOC4_PRD_ENTRIES, GFP_KERNEL);
++
++      if (!hwif->sg_table) {
++              pci_free_consistent(hwif->pci_dev,
++                                  IOC4_PRD_ENTRIES * IOC4_PRD_BYTES,
++                                  hwif->dmatable_cpu, hwif->dmatable_dma);
++              goto dma_alloc_failure;
++      }
++
++      hwif->dma_base2 = (unsigned long)
++              pci_alloc_consistent(hwif->pci_dev,
++                                   IOC4_IDE_CACHELINE_SIZE,
++                                   (dma_addr_t *) &(hwif->dma_status));
++
++      if (!hwif->dma_base2) {
++              pci_free_consistent(hwif->pci_dev,
++                                  IOC4_PRD_ENTRIES * IOC4_PRD_BYTES,
++                                  hwif->dmatable_cpu, hwif->dmatable_dma);
++              kfree(hwif->sg_table);
++              goto dma_alloc_failure;
++      }
++
++      return;
++
++      dma_alloc_failure:
++      printk(KERN_INFO
++             "%s() -- Error! Unable to allocate DMA Maps for drive %s\n",
++             __FUNCTION__, hwif->name);
++      printk(KERN_INFO
++             "Changing from DMA to PIO mode for Drive %s\n", hwif->name);
++
++      /* Disable DMA because we couldnot allocate any DMA maps */
++      hwif->autodma = 0;
++      hwif->atapi_dma = 0;
++}
++
++/* Initializes the IOC4 DMA Engine */
++static void
++sgiioc4_configure_for_dma(int dma_direction, ide_drive_t * drive)
++{
++      u32 ioc4_dma;
++      int count;
++      ide_hwif_t *hwif = HWIF(drive);
++      uint64_t dma_base = hwif->dma_base;
++      uint32_t dma_addr, ending_dma_addr;
++
++      ioc4_dma = hwif->INL(dma_base + IOC4_DMA_CTRL * 4);
++
++      if (ioc4_dma & IOC4_S_DMA_ACTIVE) {
++              printk(KERN_WARNING
++                      "%s(%s):Warning!! DMA from previous transfer was still active\n",
++                     __FUNCTION__, drive->name);
++              hwif->OUTL(IOC4_S_DMA_STOP, dma_base + IOC4_DMA_CTRL * 4);
++              count = 0;
++              do {
++                      xide_delay(count);
++                      ioc4_dma = hwif->INL(dma_base + IOC4_DMA_CTRL * 4);
++                      count += 10;
++              } while ((ioc4_dma & IOC4_S_DMA_STOP) && (count < 100));
++
++              if (ioc4_dma & IOC4_S_DMA_STOP)
++                      printk(KERN_ERR
++                             "%s(%s) : IOC4 Dma STOP bit is still 1\n",
++                             __FUNCTION__, drive->name);
++      }
++
++      ioc4_dma = hwif->INL(dma_base + IOC4_DMA_CTRL * 4);
++      if (ioc4_dma & IOC4_S_DMA_ERROR) {
++              printk(KERN_WARNING
++                     "%s(%s) : Warning!! - DMA Error during Previous"
++                     " transfer | status 0x%x\n",
++                     __FUNCTION__, drive->name, ioc4_dma);
++              hwif->OUTL(IOC4_S_DMA_STOP, dma_base + IOC4_DMA_CTRL * 4);
++              count = 0;
++              do {
++                      ioc4_dma = hwif->INL(dma_base + IOC4_DMA_CTRL * 4);
++                      xide_delay(count);
++                      count += 10;
++              } while ((ioc4_dma & IOC4_S_DMA_STOP) && (count < 100));
++
++              if (ioc4_dma & IOC4_S_DMA_STOP)
++                      printk(KERN_ERR
++                             "%s(%s) : IOC4 DMA STOP bit is still 1\n",
++                             __FUNCTION__, drive->name);
++      }
++
++      /* Address of the Scatter Gather List */
++      dma_addr = cpu_to_le32(hwif->dmatable_dma);
++      hwif->OUTL(dma_addr, dma_base + IOC4_DMA_PTR_L * 4);
++
++      /* Address of the Ending DMA */
++      memset((unsigned int *) hwif->dma_base2, 0, IOC4_IDE_CACHELINE_SIZE);
++      ending_dma_addr = cpu_to_le32(hwif->dma_status);
++      hwif->OUTL(ending_dma_addr, dma_base + IOC4_DMA_END_ADDR * 4);
++
++      hwif->OUTL(dma_direction, dma_base + IOC4_DMA_CTRL * 4);
++      drive->waiting_for_dma = 1;
++}
++
++/* IOC4 Scatter Gather list Format                                     */
++/* 128 Bit entries to support 64 bit addresses in the future           */
++/* The Scatter Gather list Entry should be in the BIG-ENDIAN Format    */
++/* --------------------------------------------------------------------- */
++/* | Upper 32 bits - Zero           |         Lower 32 bits- address | */
++/* --------------------------------------------------------------------- */
++/* | Upper 32 bits - Zero         |EOL| 15 unused     | 16 Bit Length| */
++/* --------------------------------------------------------------------- */
++/* Creates the scatter gather list, DMA Table */
++static unsigned int
++sgiioc4_build_dma_table(ide_drive_t * drive, struct request *rq, int ddir)
++{
++      ide_hwif_t *hwif = HWIF(drive);
++      unsigned int *table = hwif->dmatable_cpu;
++      unsigned int count = 0, i = 1;
++      struct scatterlist *sg;
++
++      if (HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE)
++              hwif->sg_nents = i = sgiioc4_ide_raw_build_sglist(drive, rq);
++      else
++              hwif->sg_nents = i = sgiioc4_ide_build_sglist(drive, rq);
++
++      if (!i)
++              return 0;       /* sglist of length Zero */
++
++      sg = hwif->sg_table;
++      while (i && sg_dma_len(sg)) {
++              dma_addr_t cur_addr;
++              int cur_len;
++              cur_addr = sg_dma_address(sg);
++              cur_len = sg_dma_len(sg);
++
++              while (cur_len) {
++                      if (count++ >= IOC4_PRD_ENTRIES) {
++                              printk(KERN_WARNING
++                                     "%s: DMA table too small\n",
++                                     drive->name);
++                              goto use_pio_instead;
++                      } else {
++                              uint32_t xcount, bcount =
++                                  0x10000 - (cur_addr & 0xffff);
++
++                              if (bcount > cur_len)
++                                      bcount = cur_len;
++
++                              /* put the addr, length in
++                               * the IOC4 dma-table format */
++                              *table = 0x0;
++                              table++;
++                              *table = cpu_to_be32(cur_addr);
++                              table++;
++                              *table = 0x0;
++                              table++;
++
++                              xcount = bcount & 0xffff;
++                              *table = cpu_to_be32(xcount);
++                              table++;
++
++                              cur_addr += bcount;
++                              cur_len -= bcount;
++                      }
++              }
++
++              sg++;
++              i--;
++      }
++
++      if (count) {
++              table--;
++              *table |= cpu_to_be32(0x80000000);
++              return count;
++      }
++
++      use_pio_instead:
++      pci_unmap_sg(hwif->pci_dev, hwif->sg_table, hwif->sg_nents,
++                   hwif->sg_dma_direction);
++      hwif->sg_dma_active = 0;
++
++      return 0;               /* revert to PIO for this request */
++}
++
++static int
++sgiioc4_checkirq(ide_hwif_t * hwif)
++{
++      uint8_t intr_reg =
++          hwif->INL(hwif->io_ports[IDE_IRQ_OFFSET] + IOC4_INTR_REG * 4);
++
++      if (intr_reg & 0x03)
++              return 1;
++
++      return 0;
++}
++
++static int
++sgiioc4_clearirq(ide_drive_t * drive)
++{
++      u32 intr_reg;
++      ide_hwif_t *hwif = HWIF(drive);
++      unsigned long other_ir =
++          hwif->io_ports[IDE_IRQ_OFFSET] + (IOC4_INTR_REG << 2);
++
++      /* Code to check for PCI error conditions */
++      intr_reg = hwif->INL(other_ir);
++      if (intr_reg & 0x03) {
++              /* Valid IOC4-IDE interrupt */
++              u8 stat = hwif->INB(IDE_STATUS_REG);
++              int count = 0;
++              do {
++                      xide_delay(count);
++                      stat = hwif->INB(IDE_STATUS_REG);
++                      /* Removes Interrupt from IDE Device */
++              } while ((stat & 0x80) && (count++ < 1024));
++
++              if (intr_reg & 0x02) {
++                      /* Error when transferring DMA data on PCI bus */
++                      uint32_t pci_err_addr_low, pci_err_addr_high,
++                          pci_stat_cmd_reg;
++
++                      pci_err_addr_low =
++                              hwif->INL(hwif->io_ports[IDE_IRQ_OFFSET]);
++                      pci_err_addr_high =
++                              hwif->INL(hwif->io_ports[IDE_IRQ_OFFSET] + 4);
++                      pci_read_config_dword(hwif->pci_dev, PCI_COMMAND,
++                                            &pci_stat_cmd_reg);
++                      printk(KERN_ERR
++                             "%s(%s) : PCI Bus Error when doing DMA:"
++                                 " status-cmd reg is 0x%x\n",
++                             __FUNCTION__, drive->name, pci_stat_cmd_reg);
++                      printk(KERN_ERR
++                             "%s(%s) : PCI Error Address is 0x%x%x\n",
++                             __FUNCTION__, drive->name,
++                             pci_err_addr_high, pci_err_addr_low);
++                      /* Clear the PCI Error indicator */
++                      pci_write_config_dword(hwif->pci_dev, PCI_COMMAND,
++                                             0x00000146);
++              }
++
++              /* Clear the Interrupt, Error bits on the IOC4 */
++              hwif->OUTL(0x03, other_ir);
++
++              intr_reg = hwif->INL(other_ir);
++      }
++
++      return intr_reg;
++}
++
++/**
++ *    "Copied from drivers/ide/ide-dma.c"
++ *    sgiioc4_ide_build_sglist - map IDE scatter gather for DMA I/O
++ *    @hwif: the interface to build the DMA table for
++ *    @rq: the request holding the sg list
++ *    @ddir: data direction
++ *
++ *    Perform the PCI mapping magic neccessary to access the source
++ *    or target buffers of a request via PCI DMA. The lower layers
++ *    of the kernel provide the neccessary cache management so that
++ *    we can operate in a portable fashion.
++ *
++ *    This code is identical to ide_build_sglist in ide-dma.c
++ *    however that is not exported.
++ */
++
++static int
++sgiioc4_ide_build_sglist(ide_drive_t * drive, struct request *rq)
++{
++      ide_hwif_t *hwif = HWIF(drive);
++      struct scatterlist *sg = hwif->sg_table;
++      int nents;
++
++      if (hwif->sg_dma_active)
++              BUG();
++
++      nents = blk_rq_map_sg(drive->queue, rq, hwif->sg_table);
++
++      if (rq_data_dir(rq) == READ)
++              hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
++      else
++              hwif->sg_dma_direction = PCI_DMA_TODEVICE;
++
++      return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction);
++}
++
++/**
++ *    Copied from drivers/ide/ide-dma.c
++ *    sgiioc4_ide_raw_build_sglist    -       map IDE scatter gather for DMA
++ *    @hwif: the interface to build the DMA table for
++ *    @rq: the request holding the sg list
++ *
++ *    Perform the PCI mapping magic neccessary to access the source or
++ *    target buffers of a taskfile request via PCI DMA. The lower layers
++ *    of the  kernel provide the neccessary cache management so that we can
++ *    operate in a portable fashion
++ *
++ *    This code is identical to ide_raw_build_sglist in ide-dma.c
++ *    however that is not exported
++ */
++
++static int
++sgiioc4_ide_raw_build_sglist(ide_drive_t * drive, struct request *rq)
++{
++      ide_hwif_t *hwif = HWIF(drive);
++      struct scatterlist *sg = hwif->sg_table;
++      int nents = 0;
++      ide_task_t *args = rq->special;
++      u8 *virt_addr = rq->buffer;
++      int sector_count = rq->nr_sectors;
++
++      if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
++              hwif->sg_dma_direction = PCI_DMA_TODEVICE;
++      else
++              hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
++
++#if 1
++      if (sector_count > 256)
++              BUG();
++
++      if (sector_count > 128) {
++#else
++      while (sector_count > 128) {
++#endif
++              memset(&sg[nents], 0, sizeof (*sg));
++              sg[nents].page = virt_to_page(virt_addr);
++              sg[nents].offset = offset_in_page(virt_addr);
++              sg[nents].length = 128 * SECTOR_SIZE;
++              nents++;
++              virt_addr = virt_addr + (128 * SECTOR_SIZE);
++              sector_count -= 128;
++      }
++      memset(&sg[nents], 0, sizeof (*sg));
++      sg[nents].page = virt_to_page(virt_addr);
++      sg[nents].offset = offset_in_page(virt_addr);
++      sg[nents].length = sector_count * SECTOR_SIZE;
++      nents++;
++
++      return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction);
++}
++
++#ifdef CONFIG_PROC_FS
++
++static int
++sgiioc4_get_info(char *buffer, char **addr, off_t offset, int count)
++{
++      char *p = buffer;
++      unsigned int class_rev;
++      int i = 0;
++
++      while (i < n_sgiioc4_devs) {
++              pci_read_config_dword(sgiioc4_devs[i], PCI_CLASS_REVISION, &class_rev);
++              class_rev &= 0xff;
++
++              if (sgiioc4_devs[i]->device == PCI_DEVICE_ID_SGI_IOC4) {
++                      p += sprintf(p,
++      "\n\tSGI IOC4 Chipset rev %d.\n\t"
++      "Chipset has 1 IDE channel and supports 2 devices on that channel.\n\t"
++      "Chipset supports DMA in MultiMode-2 data transfer protocol.\n",
++                              class_rev);
++                      /* Do we need more info. here? */
++              }
++              i++;
++      }
++
++      return p - buffer;
++}
++
++#endif                                /* CONFIG_PROC_FS */
++
++static int __devinit
++sgiioc4_init_one(struct pci_dev *dev, const struct pci_device_id *id)
++{
++      unsigned int class_rev;
++      ide_pci_device_t *d = &sgiioc4_chipsets[id->driver_data];
++      if (dev->device != d->device) {
++              printk(KERN_ERR "Error in %s(dev 0x%p | id 0x%p )\n",
++                     __FUNCTION__, (void *) dev, (void *) id);
++              BUG();
++      }
++
++      pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
++      class_rev &= 0xff;
++
++      if (class_rev < IOC4_SUPPORTED_FIRMWARE_REV) {
++              printk(KERN_INFO
++                     "Disabling IOC4 IDE Part due to "
++                     "unsupported Firmware Rev (%d)",
++                     class_rev);
++              printk(KERN_INFO
++                     "\nPlease upgrade to Firmware Rev 46 or higher\n");
++              return 0;
++      }
++
++      printk(KERN_INFO "%s: IDE controller at PCI slot %s\n", d->name,
++             dev->slot_name);
++
++      if (pci_init_sgiioc4(dev, d))
++              return 0;
++
++      MOD_INC_USE_COUNT;
++
++      return 0;
++}
++
++static struct pci_device_id sgiioc4_pci_tbl[] = {
++      {PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC4, PCI_ANY_ID,
++       PCI_ANY_ID, 0x0b4000, 0xFFFFFF, 0},
++      {0}
++};
++
++static struct pci_driver driver = {
++      .name = "SGI-IOC4 IDE",
++      .id_table = sgiioc4_pci_tbl,
++      .probe = sgiioc4_init_one,
++};
++
++static int
++sgiioc4_ide_init(void)
++{
++      return ide_pci_register_driver(&driver);
++}
++
++static void
++sgiioc4_ide_exit(void)
++{
++      ide_pci_unregister_driver(&driver);
++}
++
++module_init(sgiioc4_ide_init);
++module_exit(sgiioc4_ide_exit);
++
++MODULE_AUTHOR("Aniket Malatpure - Silicon Graphics Inc. (SGI)");
++MODULE_DESCRIPTION("PCI driver module for SGI IOC4 Base-IO Card");
++MODULE_LICENSE("GPL");
+--- linux-2.6.0-test6/drivers/ide/pci/siimage.c        2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/ide/pci/siimage.c       2003-10-05 00:33:24.000000000 -0700
+@@ -1150,20 +1150,6 @@ static void __init init_hwif_siimage (id
+       hwif->drives[1].autodma = hwif->autodma;
+ }
+-/**
+- *    init_dma_siimage        -       set up IDE DMA
+- *    @hwif: interface
+- *    @dmabase: DMA base address to use
+- *    
+- *    For the SI chips this requires no special set up so we can just
+- *    let the IDE DMA core do the usual work.
+- */
+- 
+-static void __init init_dma_siimage (ide_hwif_t *hwif, unsigned long dmabase)
+-{
+-      ide_setup_dma(hwif, dmabase, 8);
+-}
+-
+ extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+--- linux-2.6.0-test6/drivers/ide/pci/siimage.h        2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/ide/pci/siimage.h       2003-10-05 00:33:24.000000000 -0700
+@@ -44,7 +44,6 @@ static ide_pci_host_proc_t siimage_procs
+ static unsigned int init_chipset_siimage(struct pci_dev *, const char *);
+ static void init_iops_siimage(ide_hwif_t *);
+ static void init_hwif_siimage(ide_hwif_t *);
+-static void init_dma_siimage(ide_hwif_t *, unsigned long);
+ static ide_pci_device_t siimage_chipsets[] __devinitdata = {
+       {       /* 0 */
+@@ -54,7 +53,6 @@ static ide_pci_device_t siimage_chipsets
+               .init_chipset   = init_chipset_siimage,
+               .init_iops      = init_iops_siimage,
+               .init_hwif      = init_hwif_siimage,
+-              .init_dma       = init_dma_siimage,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+@@ -67,7 +65,6 @@ static ide_pci_device_t siimage_chipsets
+               .init_chipset   = init_chipset_siimage,
+               .init_iops      = init_iops_siimage,
+               .init_hwif      = init_hwif_siimage,
+-              .init_dma       = init_dma_siimage,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+@@ -80,7 +77,6 @@ static ide_pci_device_t siimage_chipsets
+               .init_chipset   = init_chipset_siimage,
+               .init_iops      = init_iops_siimage,
+               .init_hwif      = init_hwif_siimage,
+-              .init_dma       = init_dma_siimage,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+--- linux-2.6.0-test6/drivers/ide/pci/sis5513.c        2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/ide/pci/sis5513.c       2003-10-05 00:33:24.000000000 -0700
+@@ -942,11 +942,6 @@ static void __init init_hwif_sis5513 (id
+       return;
+ }
+-static void __init init_dma_sis5513 (ide_hwif_t *hwif, unsigned long dmabase)
+-{
+-      ide_setup_dma(hwif, dmabase, 8);
+-}
+-
+ extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+--- linux-2.6.0-test6/drivers/ide/pci/sis5513.h        2003-06-14 12:18:24.000000000 -0700
++++ 25/drivers/ide/pci/sis5513.h       2003-10-05 00:33:24.000000000 -0700
+@@ -27,7 +27,6 @@ static ide_pci_host_proc_t sis_procs[] _
+ static unsigned int init_chipset_sis5513(struct pci_dev *, const char *);
+ static void init_hwif_sis5513(ide_hwif_t *);
+-static void init_dma_sis5513(ide_hwif_t *, unsigned long);
+ static ide_pci_device_t sis5513_chipsets[] __devinitdata = {
+       {       /* 0 */
+@@ -37,7 +36,6 @@ static ide_pci_device_t sis5513_chipsets
+               .init_chipset   = init_chipset_sis5513,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_sis5513,
+-              .init_dma       = init_dma_sis5513,
+               .channels       = 2,
+               .autodma        = NOAUTODMA,
+               .enablebits     = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
+--- linux-2.6.0-test6/drivers/ide/pci/slc90e66.c       2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/ide/pci/slc90e66.c      2003-10-05 00:33:24.000000000 -0700
+@@ -362,11 +362,6 @@ static void __init init_hwif_slc90e66 (i
+ #endif /* !CONFIG_BLK_DEV_IDEDMA */
+ }
+-static void __init init_dma_slc90e66 (ide_hwif_t *hwif, unsigned long dmabase)
+-{
+-      ide_setup_dma(hwif, dmabase, 8);
+-}
+-
+ extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+--- linux-2.6.0-test6/drivers/ide/pci/slc90e66.h       2003-06-14 12:18:05.000000000 -0700
++++ 25/drivers/ide/pci/slc90e66.h      2003-10-05 00:33:24.000000000 -0700
+@@ -29,7 +29,6 @@ static ide_pci_host_proc_t slc90e66_proc
+ static unsigned int init_chipset_slc90e66(struct pci_dev *, const char *);
+ static void init_hwif_slc90e66(ide_hwif_t *);
+-static void init_dma_slc90e66(ide_hwif_t *, unsigned long);
+ static ide_pci_device_t slc90e66_chipsets[] __devinitdata = {
+       {       /* 0 */
+@@ -39,7 +38,6 @@ static ide_pci_device_t slc90e66_chipset
+               .init_chipset   = init_chipset_slc90e66,
+               .init_iops      = NULL,
+               .init_hwif      = init_hwif_slc90e66,
+-              .init_dma       = init_dma_slc90e66,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .enablebits     = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+--- linux-2.6.0-test6/drivers/ide/pci/via82cxxx.c      2003-08-08 22:55:11.000000000 -0700
++++ 25/drivers/ide/pci/via82cxxx.c     2003-10-05 00:33:24.000000000 -0700
+@@ -1,6 +1,6 @@
+ /*
+  *
+- * Version 3.37
++ * Version 3.38
+  *
+  * VIA IDE driver for Linux. Supported southbridges:
+  *
+@@ -96,7 +96,6 @@ static struct via_isa_bridge {
+ };
+ static struct via_isa_bridge *via_config;
+-static unsigned char via_enabled;
+ static unsigned int via_80w;
+ static unsigned int via_clock;
+ static char *via_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100", "UDMA133" };
+@@ -146,7 +145,7 @@ static int via_get_info(char *buffer, ch
+       via_print("----------VIA BusMastering IDE Configuration"
+               "----------------");
+-      via_print("Driver Version:                     3.37");
++      via_print("Driver Version:                     3.38");
+       via_print("South Bridge:                       VIA %s",
+               via_config->name);
+@@ -370,9 +369,6 @@ static int via_set_drive(ide_drive_t *dr
+ static void via82cxxx_tune_drive(ide_drive_t *drive, u8 pio)
+ {
+-      if (!((via_enabled >> HWIF(drive)->channel) & 1))
+-              return;
+-
+       if (pio == 255) {
+               via_set_drive(drive,
+                       ide_find_best_mode(drive, XFER_PIO | XFER_EPIO));
+@@ -506,7 +502,6 @@ static unsigned int __init init_chipset_
+        */
+       pci_read_config_byte(dev, VIA_IDE_ENABLE, &v);
+-      via_enabled = ((v & 1) ? 2 : 0) | ((v & 2) ? 1 : 0);
+       /*
+        * Set up FIFO sizes and thresholds.
+@@ -523,9 +518,9 @@ static unsigned int __init init_chipset_
+       /* Fix FIFO split between channels */
+       if (via_config->flags & VIA_SET_FIFO) {
+               t &= (t & 0x9f);
+-              switch (via_enabled) {
+-                      case 1: t |= 0x00; break;       /* 16 on primary */
+-                      case 2: t |= 0x60; break;       /* 16 on secondary */
++              switch (v & 3) {
++                      case 2: t |= 0x00; break;       /* 16 on primary */
++                      case 1: t |= 0x60; break;       /* 16 on secondary */
+                       case 3: t |= 0x20; break;       /* 8 pri 8 sec */
+               }
+       }
+@@ -603,8 +598,8 @@ static void __init init_hwif_via82cxxx(i
+       hwif->mwdma_mask = 0x07;
+       hwif->swdma_mask = 0x07;
+-      if (!(hwif->udma_four))
+-              hwif->udma_four = ((via_enabled & via_80w) >> hwif->channel) & 1;
++      if (!hwif->udma_four)
++              hwif->udma_four = (via_80w >> hwif->channel) & 1;
+       hwif->ide_dma_check = &via82cxxx_ide_dma_check;
+       if (!noautodma)
+               hwif->autodma = 1;
+@@ -612,20 +607,6 @@ static void __init init_hwif_via82cxxx(i
+       hwif->drives[1].autodma = hwif->autodma;
+ }
+-/**
+- *    init_dma_via82cxxx      -       set up for IDE DMA
+- *    @hwif: IDE interface
+- *    @dmabase: DMA base address
+- *
+- *    We allow the BM-DMA driver to only work on enabled interfaces.
+- */
+-
+-static void __init init_dma_via82cxxx(ide_hwif_t *hwif, unsigned long dmabase)
+-{
+-      if ((via_enabled >> hwif->channel) & 1)
+-              ide_setup_dma(hwif, dmabase, 8);
+-}
+-
+ extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+ static int __devinit via_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+--- linux-2.6.0-test6/drivers/ide/pci/via82cxxx.h      2003-06-14 12:18:24.000000000 -0700
++++ 25/drivers/ide/pci/via82cxxx.h     2003-10-05 00:33:24.000000000 -0700
+@@ -27,7 +27,6 @@ static ide_pci_host_proc_t via_procs[] _
+ static unsigned int init_chipset_via82cxxx(struct pci_dev *, const char *);
+ static void init_hwif_via82cxxx(ide_hwif_t *);
+-static void init_dma_via82cxxx(ide_hwif_t *, unsigned long);
+ static ide_pci_device_t via82cxxx_chipsets[] __devinitdata = {
+       {       /* 0 */
+@@ -35,9 +34,7 @@ static ide_pci_device_t via82cxxx_chipse
+               .device         = PCI_DEVICE_ID_VIA_82C576_1,
+               .name           = "VP_IDE",
+               .init_chipset   = init_chipset_via82cxxx,
+-              .init_iops      = NULL,
+               .init_hwif      = init_hwif_via82cxxx,
+-              .init_dma       = init_dma_via82cxxx,
+               .channels       = 2,
+               .autodma        = NOAUTODMA,
+               .enablebits     = {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
+@@ -48,9 +45,7 @@ static ide_pci_device_t via82cxxx_chipse
+               .device         = PCI_DEVICE_ID_VIA_82C586_1,
+               .name           = "VP_IDE",
+               .init_chipset   = init_chipset_via82cxxx,
+-              .init_iops      = NULL,
+               .init_hwif      = init_hwif_via82cxxx,
+-              .init_dma       = init_dma_via82cxxx,
+               .channels       = 2,
+               .autodma        = NOAUTODMA,
+               .enablebits     = {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
+--- linux-2.6.0-test6/drivers/input/input.c    2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/input/input.c   2003-10-05 00:34:14.000000000 -0700
+@@ -447,9 +447,10 @@ void input_register_device(struct input_
+       list_add_tail(&dev->node, &input_dev_list);
+       list_for_each_entry(handler, &input_handler_list, node)
+-              if ((id = input_match_device(handler->id_table, dev)))
+-                      if ((handle = handler->connect(handler, dev, id)))
+-                              input_link_handle(handle);
++              if (!handler->blacklist || !input_match_device(handler->blacklist, dev))
++                      if ((id = input_match_device(handler->id_table, dev)))
++                              if ((handle = handler->connect(handler, dev, id)))
++                                      input_link_handle(handle);
+ #ifdef CONFIG_HOTPLUG
+       input_call_hotplug("add", dev);
+@@ -507,9 +508,10 @@ void input_register_handler(struct input
+       list_add_tail(&handler->node, &input_handler_list);
+       
+       list_for_each_entry(dev, &input_dev_list, node)
+-              if ((id = input_match_device(handler->id_table, dev)))
+-                      if ((handle = handler->connect(handler, dev, id)))
+-                              input_link_handle(handle);
++              if (!handler->blacklist || !input_match_device(handler->blacklist, dev))
++                      if ((id = input_match_device(handler->id_table, dev)))
++                              if ((handle = handler->connect(handler, dev, id)))
++                                      input_link_handle(handle);
+ #ifdef CONFIG_PROC_FS
+       input_devices_state++;
+--- linux-2.6.0-test6/drivers/input/joydev.c   2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/input/joydev.c  2003-10-05 00:34:14.000000000 -0700
+@@ -380,10 +380,6 @@ static struct input_handle *joydev_conne
+       struct joydev *joydev;
+       int i, j, t, minor;
+-      /* Avoid tablets */
+-        if (test_bit(EV_KEY, dev->evbit) && test_bit(BTN_TOUCH, dev->keybit))
+-              return NULL;
+-
+       for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++);
+       if (minor == JOYDEV_MINORS) {
+               printk(KERN_ERR "joydev: no more free joydev devices\n");
+@@ -464,6 +460,15 @@ static void joydev_disconnect(struct inp
+               joydev_free(joydev);
+ }
++static struct input_device_id joydev_blacklist[] = {
++      {
++              .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
++              .evbit = { BIT(EV_KEY) },
++              .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) },
++      },      /* Avoid itouchpads, touchscreens and tablets */
++      { },    /* Terminating entry */
++};
++
+ static struct input_device_id joydev_ids[] = {
+       {
+               .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
+@@ -493,6 +498,7 @@ static struct input_handler joydev_handl
+       .minor =        JOYDEV_MINOR_BASE,
+       .name =         "joydev",
+       .id_table =     joydev_ids,
++      .blacklist =    joydev_blacklist,
+ };
+ static int __init joydev_init(void)
+--- linux-2.6.0-test6/drivers/input/joystick/analog.c  2003-06-16 22:32:21.000000000 -0700
++++ 25/drivers/input/joystick/analog.c 2003-10-05 00:33:24.000000000 -0700
+@@ -159,7 +159,7 @@ static unsigned int get_time_pit(void)
+ #define DELTA(x,y)    ((y)-(x))
+ #define TIME_NAME     "TSC"
+ #elif __alpha__
+-#define GET_TIME(x)   do { x = get_cycles(x); } while (0)
++#define GET_TIME(x)   do { x = get_cycles(); } while (0)
+ #define DELTA(x,y)    ((y)-(x))
+ #define TIME_NAME     "PCC"
+ #else
+--- linux-2.6.0-test6/drivers/input/keyboard/atkbd.c   2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/input/keyboard/atkbd.c  2003-10-05 00:36:37.000000000 -0700
+@@ -369,10 +369,11 @@ static int atkbd_command(struct atkbd *a
+ static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+ {
+       struct atkbd *atkbd = dev->private;
+-      struct { int p; u8 v; } period[] =      
+-              { {30, 0x00}, {25, 0x02}, {20, 0x04}, {15, 0x08}, {10, 0x0c}, {7, 0x10}, {5, 0x14}, {0, 0x14} };
+-      struct { int d; u8 v; } delay[] =
+-              { {1000, 0x60}, {750, 0x40}, {500, 0x20}, {250, 0x00}, {0, 0x00} };
++      const short period[32] =
++              { 33,  37,  42,  46,  50,  54,  58,  63,  67,  75,  83,  92, 100, 109, 116, 125,
++               133, 149, 167, 182, 200, 217, 232, 250, 270, 303, 333, 370, 400, 435, 470, 500 };
++      const short delay[4] =
++              { 250, 500, 750, 1000 };
+       char param[2];
+       int i, j;
+@@ -406,11 +407,11 @@ static int atkbd_event(struct input_dev 
+                       if (atkbd_softrepeat) return 0;
+                       i = j = 0;
+-                      while (period[i].p > dev->rep[REP_PERIOD]) i++;
+-                      while (delay[j].d > dev->rep[REP_DELAY]) j++;
+-                      dev->rep[REP_PERIOD] = period[i].p;
+-                      dev->rep[REP_DELAY] = delay[j].d;
+-                      param[0] = period[i].v | delay[j].v;
++                      while (i < 32 && period[i] < dev->rep[REP_PERIOD]) i++;
++                      while (j < 4 && delay[j] < dev->rep[REP_DELAY]) j++;
++                      dev->rep[REP_PERIOD] = period[i];
++                      dev->rep[REP_DELAY] = delay[j];
++                      param[0] = i | (j << 5);
+                       atkbd_command(atkbd, param, ATKBD_CMD_SETREP);
+                       return 0;
+@@ -576,6 +577,7 @@ static void atkbd_disconnect(struct seri
+       struct atkbd *atkbd = serio->private;
+       input_unregister_device(&atkbd->dev);
+       serio_close(serio);
++      serio->private = NULL;
+       kfree(atkbd);
+ }
+@@ -634,6 +636,7 @@ static void atkbd_connect(struct serio *
+       serio->private = atkbd;
+       if (serio_open(serio, dev)) {
++              serio->private = NULL;
+               kfree(atkbd);
+               return;
+       }
+@@ -642,6 +645,7 @@ static void atkbd_connect(struct serio *
+               if (atkbd_probe(atkbd)) {
+                       serio_close(serio);
++                      serio->private = NULL;
+                       kfree(atkbd);
+                       return;
+               }
+--- linux-2.6.0-test6/drivers/input/keyboard/Kconfig   2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/input/keyboard/Kconfig  2003-10-05 00:33:24.000000000 -0700
+@@ -12,10 +12,11 @@ config INPUT_KEYBOARD
+         If unsure, say Y.
+ config KEYBOARD_ATKBD
+-      tristate "AT keyboard support" if EMBEDDED || !X86 
++      tristate "AT keyboard support" if !PC
+       default y
+       depends on INPUT && INPUT_KEYBOARD
+-      select SERIO_I8042
++      select SERIO
++      select SERIO_I8042 if PC
+       help
+         Say Y here if you want to use a standard AT or PS/2 keyboard. Usually
+         you'll need this, unless you have a different type keyboard (USB, ADB
+--- linux-2.6.0-test6/drivers/input/mouse/Kconfig      2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/input/mouse/Kconfig     2003-10-05 00:33:24.000000000 -0700
+@@ -15,7 +15,8 @@ config MOUSE_PS2
+       tristate "PS/2 mouse"
+       default y
+       depends on INPUT && INPUT_MOUSE
+-      select SERIO_I8042
++      select SERIO
++      select SERIO_I8042 if PC
+       ---help---
+         Say Y here if you have a PS/2 mouse connected to your system. This
+         includes the standard 2 or 3-button PS/2 mouse, as well as PS/2
+--- linux-2.6.0-test6/drivers/input/mouse/logips2pp.c  2003-06-22 12:04:44.000000000 -0700
++++ 25/drivers/input/mouse/logips2pp.c 2003-10-05 00:34:15.000000000 -0700
+@@ -10,6 +10,7 @@
+  */
+ #include <linux/input.h>
++#include <linux/serio.h>
+ #include "psmouse.h"
+ #include "logips2pp.h"
+--- linux-2.6.0-test6/drivers/input/mouse/psmouse-base.c       2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/input/mouse/psmouse-base.c      2003-10-05 00:34:15.000000000 -0700
+@@ -141,7 +141,8 @@ static irqreturn_t psmouse_interrupt(str
+               goto out;
+       }
+-      if (psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) {
++      if (psmouse->state == PSMOUSE_ACTIVATED && 
++          psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) {
+               printk(KERN_WARNING "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n",
+                      psmouse->name, psmouse->phys, psmouse->pktcnt);
+               psmouse->pktcnt = 0;
+@@ -276,24 +277,18 @@ static int psmouse_extensions(struct psm
+               return PSMOUSE_PS2;
+ /*
+- * Try Synaptics TouchPad magic ID
++ * Try Synaptics TouchPad
+  */
+-
+-       param[0] = 0;
+-       psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
+-       psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
+-       psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
+-       psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
+-       psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
+-
+-       if (param[1] == 0x47) {
++      if (synaptics_detect(psmouse) == 0) {
+               psmouse->vendor = "Synaptics";
+               psmouse->name = "TouchPad";
+-              if (!synaptics_init(psmouse))
++
++#if CONFIG_MOUSE_PS2_SYNAPTICS
++              if (synaptics_init(psmouse) == 0)
+                       return PSMOUSE_SYNAPTICS;
+-              else
+-                      return PSMOUSE_PS2;
+-       }
++#endif
++              return PSMOUSE_PS2;
++      }
+ /*
+  * Try Genius NetMouse magic init.
+@@ -519,7 +514,18 @@ static void psmouse_disconnect(struct se
+       struct psmouse *psmouse = serio->private;
+       psmouse->state = PSMOUSE_IGNORE;
+-      synaptics_disconnect(psmouse);
++      
++      if (psmouse->ptport) {
++              if (psmouse->ptport->deactivate)
++                      psmouse->ptport->deactivate(psmouse);
++              __serio_unregister_port(&psmouse->ptport->serio); /* we have serio_sem */
++              kfree(psmouse->ptport);
++              psmouse->ptport = NULL;
++      }
++              
++      if (psmouse->disconnect)
++              psmouse->disconnect(psmouse);
++      
+       input_unregister_device(&psmouse->dev);
+       serio_close(serio);
+       kfree(psmouse);
+@@ -532,20 +538,10 @@ static void psmouse_disconnect(struct se
+ static int psmouse_pm_callback(struct pm_dev *dev, pm_request_t request, void *data)
+ {
+       struct psmouse *psmouse = dev->data;
+-      struct serio_dev *ser_dev = psmouse->serio->dev;
+-
+-      synaptics_disconnect(psmouse);
+-
+-      /* We need to reopen the serio port to reinitialize the i8042 controller */
+-      serio_close(psmouse->serio);
+-      serio_open(psmouse->serio, ser_dev);
+-
+-      /* Probe and re-initialize the mouse */
+-      psmouse_probe(psmouse);
+-      psmouse_initialize(psmouse);
+-      synaptics_pt_init(psmouse);
+-      psmouse_activate(psmouse);
++      psmouse->state = PSMOUSE_IGNORE;
++      serio_reconnect(psmouse->serio);
++      
+       return 0;
+ }
+@@ -553,7 +549,6 @@ static int psmouse_pm_callback(struct pm
+  * psmouse_connect() is a callback from the serio module when
+  * an unhandled serio port is found.
+  */
+-
+ static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
+ {
+       struct psmouse *psmouse;
+@@ -578,7 +573,6 @@ static void psmouse_connect(struct serio
+       psmouse->dev.private = psmouse;
+       serio->private = psmouse;
+-
+       if (serio_open(serio, dev)) {
+               kfree(psmouse);
+               return;
+@@ -590,10 +584,12 @@ static void psmouse_connect(struct serio
+               return;
+       }
+       
+-      pmdev = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, psmouse_pm_callback);
+-      if (pmdev) {
+-              psmouse->dev.pm_dev = pmdev;
+-              pmdev->data = psmouse;
++      if (serio->type != SERIO_PS_PSTHRU) {
++              pmdev = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, psmouse_pm_callback);
++              if (pmdev) {
++                      psmouse->dev.pm_dev = pmdev;
++                      pmdev->data = psmouse;
++              }
+       }
+       sprintf(psmouse->devname, "%s %s %s",
+@@ -614,14 +610,70 @@ static void psmouse_connect(struct serio
+       psmouse_initialize(psmouse);
+-      synaptics_pt_init(psmouse);
++      if (psmouse->ptport) {
++              printk(KERN_INFO "serio: %s port at %s\n", psmouse->ptport->serio.name, psmouse->phys);
++              __serio_register_port(&psmouse->ptport->serio); /* we have serio_sem */
++              if (psmouse->ptport->activate)
++                      psmouse->ptport->activate(psmouse);
++      }
++      
++      psmouse_activate(psmouse);
++}
++
++static int psmouse_reconnect(struct serio *serio)
++{
++      struct psmouse *psmouse = serio->private;
++      struct serio_dev *dev = serio->dev;
++      int old_type = psmouse->type;
++      
++      if (!dev) {
++              printk(KERN_DEBUG "psmouse: reconnect request, but serio is disconnected, ignoring...\n");
++              return -1;
++      }
++      
++      /* We need to reopen the serio port to reinitialize the i8042 controller */
++      serio_close(serio);
++      if (serio_open(serio, dev)) {
++              /* do a disconnect here as serio_open leaves dev as NULL so disconnect 
++               * will not be called automatically later
++               */
++              psmouse_disconnect(serio);
++              return -1;
++      }
++      
++      psmouse->state = PSMOUSE_NEW_DEVICE;
++      psmouse->type = psmouse->acking = psmouse->cmdcnt = psmouse->pktcnt = 0;
++      if (psmouse->reconnect) {
++             if (psmouse->reconnect(psmouse))
++                      return -1;
++      } else if (psmouse_probe(psmouse) != old_type)
++              return -1;
++      
++      /* ok, the device type (and capabilities) match the old one,
++       * we can continue using it, complete intialization
++       */ 
++      psmouse->type = old_type;
++      psmouse_initialize(psmouse);
++
++      if (psmouse->ptport) {
++                      if (psmouse_reconnect(&psmouse->ptport->serio)) {
++                      __serio_unregister_port(&psmouse->ptport->serio);
++                      __serio_register_port(&psmouse->ptport->serio);
++                      if (psmouse->ptport->activate)
++                              psmouse->ptport->activate(psmouse);
++              }
++      }
++      
+       psmouse_activate(psmouse);
++      return 0;
+ }
++
+ static struct serio_dev psmouse_dev = {
+       .interrupt =    psmouse_interrupt,
+       .connect =      psmouse_connect,
++      .reconnect =    psmouse_reconnect,
+       .disconnect =   psmouse_disconnect,
+       .cleanup =      psmouse_cleanup,
+ };
+--- linux-2.6.0-test6/drivers/input/mouse/psmouse.h    2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/input/mouse/psmouse.h   2003-10-05 00:34:15.000000000 -0700
+@@ -22,10 +22,20 @@
+ #define PSMOUSE_ACTIVATED     1
+ #define PSMOUSE_IGNORE                2
++struct psmouse;
++
++struct psmouse_ptport {
++      struct serio serio;
++
++      void (*activate)(struct psmouse *parent);
++      void (*deactivate)(struct psmouse *parent);
++};
++
+ struct psmouse {
+       void *private;
+       struct input_dev dev;
+       struct serio *serio;
++      struct psmouse_ptport *ptport;
+       char *vendor;
+       char *name;
+       unsigned char cmdbuf[8];
+@@ -41,6 +51,9 @@ struct psmouse {
+       char error;
+       char devname[64];
+       char phys[32];
++      
++      int (*reconnect)(struct psmouse *psmouse);
++      void (*disconnect)(struct psmouse *psmouse);
+ };
+ #define PSMOUSE_PS2           1
+--- linux-2.6.0-test6/drivers/input/mouse/synaptics.c  2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/input/mouse/synaptics.c 2003-10-05 00:34:15.000000000 -0700
+@@ -2,7 +2,8 @@
+  * Synaptics TouchPad PS/2 mouse driver
+  *
+  *   2003 Dmitry Torokhov <dtor@mail.ru>
+- *     Added support for pass-through port
++ *     Added support for pass-through port. Special thanks to Peter Berg Larsen
++ *     for explaining various Synaptics quirks.
+  *
+  *   2003 Peter Osterlund <petero2@telia.com>
+  *     Ported to 2.5 input device infrastructure.
+@@ -194,9 +195,7 @@ static void print_ident(struct synaptics
+ static int synaptics_query_hardware(struct psmouse *psmouse)
+ {
+-      struct synaptics_data *priv = psmouse->private;
+       int retries = 0;
+-      int mode;
+       while ((retries++ < 3) && synaptics_reset(psmouse))
+               printk(KERN_ERR "synaptics reset failed\n");
+@@ -207,8 +206,15 @@ static int synaptics_query_hardware(stru
+               return -1;
+       if (synaptics_capability(psmouse))
+               return -1;
++      
++      return 0;
++}
+-      mode = SYN_BIT_ABSOLUTE_MODE | SYN_BIT_HIGH_RATE;
++static int synaptics_set_mode(struct psmouse *psmouse, int mode)
++{
++      struct synaptics_data *priv = psmouse->private;
++
++      mode |= SYN_BIT_ABSOLUTE_MODE | SYN_BIT_HIGH_RATE;
+       if (SYN_ID_MAJOR(priv->identity) >= 4)
+               mode |= SYN_BIT_DISABLE_GESTURE;
+       if (SYN_CAP_EXTENDED(priv->capabilities))
+@@ -265,49 +271,38 @@ static void synaptics_pass_pt_packet(str
+       }
+ }
+-int synaptics_pt_init(struct psmouse *psmouse)
++static void synaptics_pt_activate(struct psmouse *psmouse)
+ {
+-      struct synaptics_data *priv = psmouse->private;
+-      struct serio *port;
+-      struct psmouse *child;
++      struct psmouse *child = psmouse->ptport->serio.private;
++      
++      /* adjust the touchpad to child's choice of protocol */
++      if (child && child->type >= PSMOUSE_GENPS) {
++              if (synaptics_set_mode(psmouse, SYN_BIT_FOUR_BYTE_CLIENT))
++                      printk(KERN_INFO "synaptics: failed to enable 4-byte guest protocol\n");
++      }
++}
+-      if (psmouse->type != PSMOUSE_SYNAPTICS)
+-              return -1;
+-      if (!SYN_CAP_EXTENDED(priv->capabilities))
+-              return -1;
+-      if (!SYN_CAP_PASS_THROUGH(priv->capabilities))
+-              return -1;
++static void synaptics_pt_create(struct psmouse *psmouse)
++{
++      struct psmouse_ptport *port;
+-      priv->ptport = port = kmalloc(sizeof(struct serio), GFP_KERNEL);
++      psmouse->ptport = port = kmalloc(sizeof(struct psmouse_ptport), GFP_KERNEL);
+       if (!port) {
+-              printk(KERN_ERR "synaptics: not enough memory to allocate serio port\n");
+-              return -1;
++              printk(KERN_ERR "synaptics: not enough memory to allocate pass-through port\n");
++              return;
+       }
+-      memset(port, 0, sizeof(struct serio));
+-      port->type = SERIO_PS_PSTHRU;
+-      port->name = "Synaptics pass-through";
+-      port->phys = "synaptics-pt/serio0";
+-      port->write = synaptics_pt_write;
+-      port->open = synaptics_pt_open;
+-      port->close = synaptics_pt_close;
+-      port->driver = psmouse;
++      memset(port, 0, sizeof(struct psmouse_ptport));
+-      printk(KERN_INFO "serio: %s port at %s\n", port->name, psmouse->phys);
+-      serio_register_slave_port(port);
++      port->serio.type = SERIO_PS_PSTHRU;
++      port->serio.name = "Synaptics pass-through";
++      port->serio.phys = "synaptics-pt/serio0";
++      port->serio.write = synaptics_pt_write;
++      port->serio.open = synaptics_pt_open;
++      port->serio.close = synaptics_pt_close;
++      port->serio.driver = psmouse;
+-      /* adjust the touchpad to child's choice of protocol */
+-      child = port->private;
+-      if (child && child->type >= PSMOUSE_GENPS) {
+-              if (synaptics_mode_cmd(psmouse, (SYN_BIT_ABSOLUTE_MODE |
+-                                               SYN_BIT_HIGH_RATE |
+-                                               SYN_BIT_DISABLE_GESTURE |
+-                                               SYN_BIT_FOUR_BYTE_CLIENT |
+-                                               SYN_BIT_W_MODE)))
+-                      printk(KERN_INFO "synaptics: failed to enable 4-byte guest protocol\n");
+-      }
+-
+-      return 0;
++      port->activate = synaptics_pt_activate;
+ }
+ /*****************************************************************************
+@@ -371,27 +366,82 @@ static void set_input_params(struct inpu
+       clear_bit(REL_Y, dev->relbit);
+ }
++static void synaptics_disconnect(struct psmouse *psmouse)
++{
++      synaptics_mode_cmd(psmouse, 0);
++      kfree(psmouse->private);
++}
++
++static int synaptics_reconnect(struct psmouse *psmouse)
++{
++      struct synaptics_data *priv = psmouse->private;
++      struct synaptics_data old_priv = *priv;
++
++      if (synaptics_detect(psmouse))
++              return -1;
++
++      if (synaptics_query_hardware(psmouse)) {
++              printk(KERN_ERR "Unable to query Synaptics hardware.\n");
++              return -1;
++      }
++      
++      if (old_priv.identity != priv->identity ||
++          old_priv.model_id != priv->model_id ||
++          old_priv.capabilities != priv->capabilities ||
++          old_priv.ext_cap != priv->ext_cap)
++              return -1;
++      
++      if (synaptics_set_mode(psmouse, 0)) {
++              printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
++              return -1;
++      }
++
++      return 0;
++}
++
++int synaptics_detect(struct psmouse *psmouse)
++{
++      unsigned char param[4];
++      
++      param[0] = 0;
++      
++      psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
++      psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
++      psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
++      psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
++      psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
++      
++      return param[1] == 0x47 ? 0 : -1;
++}
++
+ int synaptics_init(struct psmouse *psmouse)
+ {
+       struct synaptics_data *priv;
+-#ifndef CONFIG_MOUSE_PS2_SYNAPTICS
+-      return -1;
+-#endif
+-
+       psmouse->private = priv = kmalloc(sizeof(struct synaptics_data), GFP_KERNEL);
+       if (!priv)
+               return -1;
+       memset(priv, 0, sizeof(struct synaptics_data));
+       if (synaptics_query_hardware(psmouse)) {
+-              printk(KERN_ERR "Unable to query/initialize Synaptics hardware.\n");
++              printk(KERN_ERR "Unable to query Synaptics hardware.\n");
++              goto init_fail;
++      }
++      
++      if (synaptics_set_mode(psmouse, 0)) {
++              printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
+               goto init_fail;
+       }
++      if (SYN_CAP_EXTENDED(priv->capabilities) && SYN_CAP_PASS_THROUGH(priv->capabilities))
++                      synaptics_pt_create(psmouse);
++      
+       print_ident(priv);
+       set_input_params(&psmouse->dev, priv);
++      psmouse->disconnect = synaptics_disconnect;
++      psmouse->reconnect = synaptics_reconnect;
++      
+       return 0;
+  init_fail:
+@@ -399,36 +449,13 @@ int synaptics_init(struct psmouse *psmou
+       return -1;
+ }
+-void synaptics_disconnect(struct psmouse *psmouse)
+-{
+-      struct synaptics_data *priv = psmouse->private;
+-
+-      if (psmouse->type == PSMOUSE_SYNAPTICS && priv) {
+-              synaptics_mode_cmd(psmouse, 0);
+-              if (priv->ptport) {
+-                      serio_unregister_slave_port(priv->ptport);
+-                      kfree(priv->ptport);
+-              }
+-              kfree(priv);
+-      }
+-}
+-
+ /*****************************************************************************
+  *    Functions to interpret the absolute mode packets
+  ****************************************************************************/
+ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw)
+ {
+-      hw->up    = 0;
+-      hw->down  = 0;
+-      hw->b0    = 0;
+-      hw->b1    = 0;
+-      hw->b2    = 0;
+-      hw->b3    = 0;
+-      hw->b4    = 0;
+-      hw->b5    = 0;
+-      hw->b6    = 0;
+-      hw->b7    = 0;
++      memset(hw, 0, sizeof(struct synaptics_hw_state));
+       if (SYN_MODEL_NEWABS(priv->model_id)) {
+               hw->x = (((buf[3] & 0x10) << 8) |
+@@ -570,64 +597,47 @@ static void synaptics_process_packet(str
+       input_sync(dev);
+ }
++static int synaptics_validate_byte(struct psmouse *psmouse)
++{
++      static unsigned char newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 };
++      static unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 };
++      static unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 };
++      static unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 };
++      struct synaptics_data *priv = psmouse->private;
++      int idx = psmouse->pktcnt - 1;
++
++      if (SYN_MODEL_NEWABS(priv->model_id))
++              return (psmouse->packet[idx] & newabs_mask[idx]) == newabs_rslt[idx];
++      else
++              return (psmouse->packet[idx] & oldabs_mask[idx]) == oldabs_rslt[idx];
++}
++
+ void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
+ {
+       struct input_dev *dev = &psmouse->dev;
+       struct synaptics_data *priv = psmouse->private;
+-      unsigned char data = psmouse->packet[psmouse->pktcnt - 1];
+-      int newabs = SYN_MODEL_NEWABS(priv->model_id);
+       input_regs(dev, regs);
+-      switch (psmouse->pktcnt) {
+-      case 1:
+-              if (newabs ? ((data & 0xC8) != 0x80) : ((data & 0xC0) != 0xC0)) {
+-                      printk(KERN_WARNING "Synaptics driver lost sync at 1st byte\n");
+-                      goto bad_sync;
+-              }
+-              break;
+-      case 2:
+-              if (!newabs && ((data & 0x60) != 0x00)) {
+-                      printk(KERN_WARNING "Synaptics driver lost sync at 2nd byte\n");
+-                      goto bad_sync;
+-              }
+-              break;
+-      case 4:
+-              if (newabs ? ((data & 0xC8) != 0xC0) : ((data & 0xC0) != 0x80)) {
+-                      printk(KERN_WARNING "Synaptics driver lost sync at 4th byte\n");
+-                      goto bad_sync;
+-              }
+-              break;
+-      case 5:
+-              if (!newabs && ((data & 0x60) != 0x00)) {
+-                      printk(KERN_WARNING "Synaptics driver lost sync at 5th byte\n");
+-                      goto bad_sync;
+-              }
+-              break;
+-      default:
+-              if (psmouse->pktcnt < 6)
+-                      break;              /* Wait for full packet */
+-
++      if (psmouse->pktcnt >= 6) { /* Full packet received */
+               if (priv->out_of_sync) {
+                       priv->out_of_sync = 0;
+                       printk(KERN_NOTICE "Synaptics driver resynced.\n");
+               }
+-              if (priv->ptport && synaptics_is_pt_packet(psmouse->packet))
+-                      synaptics_pass_pt_packet(priv->ptport, psmouse->packet);
++              if (psmouse->ptport && psmouse->ptport->serio.dev && synaptics_is_pt_packet(psmouse->packet))
++                      synaptics_pass_pt_packet(&psmouse->ptport->serio, psmouse->packet);
+               else
+                       synaptics_process_packet(psmouse);
+-
+               psmouse->pktcnt = 0;
+-              break;
+-      }
+-      return;
+- bad_sync:
+-      priv->out_of_sync++;
+-      psmouse->pktcnt = 0;
+-      if (psmouse_resetafter > 0 && priv->out_of_sync == psmouse_resetafter) {
+-              psmouse->state = PSMOUSE_IGNORE;
+-              serio_rescan(psmouse->serio);
++      } else if (psmouse->pktcnt && !synaptics_validate_byte(psmouse)) {
++              printk(KERN_WARNING "Synaptics driver lost sync at byte %d\n", psmouse->pktcnt);
++              psmouse->pktcnt = 0;
++              if (++priv->out_of_sync == psmouse_resetafter) {
++                      psmouse->state = PSMOUSE_IGNORE;
++                      printk(KERN_NOTICE "synaptics: issuing reconnect request\n");
++                      serio_reconnect(psmouse->serio);
++              }
+       }
+ }
+--- linux-2.6.0-test6/drivers/input/mouse/synaptics.h  2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/input/mouse/synaptics.h 2003-10-05 00:34:15.000000000 -0700
+@@ -9,11 +9,9 @@
+ #ifndef _SYNAPTICS_H
+ #define _SYNAPTICS_H
+-
+ extern void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs);
++extern int synaptics_detect(struct psmouse *psmouse);
+ extern int synaptics_init(struct psmouse *psmouse);
+-extern int synaptics_pt_init(struct psmouse *psmouse);
+-extern void synaptics_disconnect(struct psmouse *psmouse);
+ /* synaptics queries */
+ #define SYN_QUE_IDENTIFY              0x00
+@@ -105,8 +103,6 @@ struct synaptics_data {
+       /* Data for normal processing */
+       unsigned int out_of_sync;               /* # of packets out of sync */
+       int old_w;                              /* Previous w value */
+-      
+-      struct serio *ptport;                   /* pass-through port */
+ };
+ #endif /* _SYNAPTICS_H */
+--- linux-2.6.0-test6/drivers/input/serio/serio.c      2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/input/serio/serio.c     2003-10-05 00:34:15.000000000 -0700
+@@ -49,14 +49,15 @@ MODULE_LICENSE("GPL");
+ EXPORT_SYMBOL(serio_interrupt);
+ EXPORT_SYMBOL(serio_register_port);
+-EXPORT_SYMBOL(serio_register_slave_port);
++EXPORT_SYMBOL(__serio_register_port);
+ EXPORT_SYMBOL(serio_unregister_port);
+-EXPORT_SYMBOL(serio_unregister_slave_port);
++EXPORT_SYMBOL(__serio_unregister_port);
+ EXPORT_SYMBOL(serio_register_device);
+ EXPORT_SYMBOL(serio_unregister_device);
+ EXPORT_SYMBOL(serio_open);
+ EXPORT_SYMBOL(serio_close);
+ EXPORT_SYMBOL(serio_rescan);
++EXPORT_SYMBOL(serio_reconnect);
+ struct serio_event {
+       int type;
+@@ -83,10 +84,20 @@ static void serio_find_dev(struct serio 
+ }
+ #define SERIO_RESCAN  1
++#define SERIO_RECONNECT       2
+ static DECLARE_WAIT_QUEUE_HEAD(serio_wait);
+ static DECLARE_COMPLETION(serio_exited);
++static void serio_invalidate_pending_events(struct serio *serio)
++{
++      struct serio_event *event;
++      
++      list_for_each_entry(event, &serio_event_list, node)
++              if (event->serio == serio)
++                      event->serio = NULL;
++}
++
+ void serio_handle_events(void)
+ {
+       struct list_head *node, *next;
+@@ -95,17 +106,27 @@ void serio_handle_events(void)
+       list_for_each_safe(node, next, &serio_event_list) {
+               event = container_of(node, struct serio_event, node);   
++              down(&serio_sem);
++              if (event->serio == NULL)
++                      goto event_done;
++              
+               switch (event->type) {
++                      case SERIO_RECONNECT :
++                              if (event->serio->dev && event->serio->dev->reconnect)
++                                      if (event->serio->dev->reconnect(event->serio) == 0)
++                                              break;
++                              /* reconnect failed - fall through to rescan */
++                              
+                       case SERIO_RESCAN :
+-                              down(&serio_sem);
+                               if (event->serio->dev && event->serio->dev->disconnect)
+                                       event->serio->dev->disconnect(event->serio);
+                               serio_find_dev(event->serio);
+-                              up(&serio_sem);
+                               break;
+                       default:
+                               break;
+               }
++event_done:
++              up(&serio_sem);
+               list_del_init(node);
+               kfree(event);
+       }
+@@ -130,18 +151,27 @@ static int serio_thread(void *nothing)
+       complete_and_exit(&serio_exited, 0);
+ }
+-void serio_rescan(struct serio *serio)
++static void serio_queue_event(struct serio *serio, int event_type)
+ {
+       struct serio_event *event;
+-      if (!(event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC)))
+-              return;
++      if ((event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) {
++              event->type = event_type;
++              event->serio = serio;
+-      event->type = SERIO_RESCAN;
+-      event->serio = serio;
++              list_add_tail(&event->node, &serio_event_list);
++              wake_up(&serio_wait);
++      }
++}
+-      list_add_tail(&event->node, &serio_event_list);
+-      wake_up(&serio_wait);
++void serio_rescan(struct serio *serio)
++{
++      serio_queue_event(serio, SERIO_RESCAN);
++}
++
++void serio_reconnect(struct serio *serio)
++{
++      serio_queue_event(serio, SERIO_RECONNECT);
+ }
+ irqreturn_t serio_interrupt(struct serio *serio,
+@@ -163,17 +193,16 @@ irqreturn_t serio_interrupt(struct serio
+ void serio_register_port(struct serio *serio)
+ {
+       down(&serio_sem);
+-      list_add_tail(&serio->node, &serio_list);
+-      serio_find_dev(serio);
++      __serio_register_port(serio);
+       up(&serio_sem);
+ }
+ /*
+- * Same as serio_register_port but does not try to acquire serio_sem.
+- * Should be used when registering a serio from other input device's
++ * Should only be called directly if serio_sem has already been taken,
++ * for example when unregistering a serio from other input device's 
+  * connect() function.
+  */
+-void serio_register_slave_port(struct serio *serio)
++void __serio_register_port(struct serio *serio)
+ {
+       list_add_tail(&serio->node, &serio_list);
+       serio_find_dev(serio);
+@@ -182,19 +211,18 @@ void serio_register_slave_port(struct se
+ void serio_unregister_port(struct serio *serio)
+ {
+       down(&serio_sem);
+-      list_del_init(&serio->node);
+-      if (serio->dev && serio->dev->disconnect)
+-              serio->dev->disconnect(serio);
++      __serio_unregister_port(serio);
+       up(&serio_sem);
+ }
+ /*
+- * Same as serio_unregister_port but does not try to acquire serio_sem.
+- * Should be used when unregistering a serio from other input device's
++ * Should only be called directly if serio_sem has already been taken,
++ * for example when unregistering a serio from other input device's 
+  * disconnect() function.
+  */
+-void serio_unregister_slave_port(struct serio *serio)
++void __serio_unregister_port(struct serio *serio)
+ {
++      serio_invalidate_pending_events(serio);
+       list_del_init(&serio->node);
+       if (serio->dev && serio->dev->disconnect)
+               serio->dev->disconnect(serio);
+--- linux-2.6.0-test6/drivers/isdn/hardware/eicon/debuglib.h   2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/isdn/hardware/eicon/debuglib.h  2003-10-05 00:33:24.000000000 -0700
+@@ -103,28 +103,28 @@
+ #define DL_TO_KERNEL    0x40000000
+ #ifdef DIVA_NO_DEBUGLIB
+-#define myDbgPrint_LOG(x,...) do { } while(0);
+-#define myDbgPrint_FTL(x,...) do { } while(0);
+-#define myDbgPrint_ERR(x,...) do { } while(0);
+-#define myDbgPrint_TRC(x,...) do { } while(0);
+-#define myDbgPrint_MXLOG(x,...) do { } while(0);
+-#define myDbgPrint_EVL(x,...) do { } while(0);
+-#define myDbgPrint_REG(x,...) do { } while(0);
+-#define myDbgPrint_MEM(x,...) do { } while(0);
+-#define myDbgPrint_SPL(x,...) do { } while(0);
+-#define myDbgPrint_IRP(x,...) do { } while(0);
+-#define myDbgPrint_TIM(x,...) do { } while(0);
+-#define myDbgPrint_BLK(x,...) do { } while(0);
+-#define myDbgPrint_TAPI(x,...) do { } while(0);
+-#define myDbgPrint_NDIS(x,...) do { } while(0);
+-#define myDbgPrint_CONN(x,...) do { } while(0);
+-#define myDbgPrint_STAT(x,...) do { } while(0);
+-#define myDbgPrint_SEND(x,...) do { } while(0);
+-#define myDbgPrint_RECV(x,...) do { } while(0);
+-#define myDbgPrint_PRV0(x,...) do { } while(0);
+-#define myDbgPrint_PRV1(x,...) do { } while(0);
+-#define myDbgPrint_PRV2(x,...) do { } while(0);
+-#define myDbgPrint_PRV3(x,...) do { } while(0);
++#define myDbgPrint_LOG(x...) do { } while(0);
++#define myDbgPrint_FTL(x...) do { } while(0);
++#define myDbgPrint_ERR(x...) do { } while(0);
++#define myDbgPrint_TRC(x...) do { } while(0);
++#define myDbgPrint_MXLOG(x...) do { } while(0);
++#define myDbgPrint_EVL(x...) do { } while(0);
++#define myDbgPrint_REG(x...) do { } while(0);
++#define myDbgPrint_MEM(x...) do { } while(0);
++#define myDbgPrint_SPL(x...) do { } while(0);
++#define myDbgPrint_IRP(x...) do { } while(0);
++#define myDbgPrint_TIM(x...) do { } while(0);
++#define myDbgPrint_BLK(x...) do { } while(0);
++#define myDbgPrint_TAPI(x...) do { } while(0);
++#define myDbgPrint_NDIS(x...) do { } while(0);
++#define myDbgPrint_CONN(x...) do { } while(0);
++#define myDbgPrint_STAT(x...) do { } while(0);
++#define myDbgPrint_SEND(x...) do { } while(0);
++#define myDbgPrint_RECV(x...) do { } while(0);
++#define myDbgPrint_PRV0(x...) do { } while(0);
++#define myDbgPrint_PRV1(x...) do { } while(0);
++#define myDbgPrint_PRV2(x...) do { } while(0);
++#define myDbgPrint_PRV3(x...) do { } while(0);
+ #define DBG_TEST(func,args) do { } while(0);
+ #define DBG_EVL_ID(args) do { } while(0);
+--- linux-2.6.0-test6/drivers/isdn/hardware/eicon/divamnt.c    2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/isdn/hardware/eicon/divamnt.c   2003-10-05 00:33:24.000000000 -0700
+@@ -1,4 +1,4 @@
+-/* $Id: 2.6.0-test6-mm4.patch,v 1.1.4.1 2003/10/10 09:31:08 ericm Exp $
++/* $Id: 2.6.0-test6-mm4.patch,v 1.1.4.1 2003/10/10 09:31:08 ericm Exp $
+  *
+  * Driver for Eicon DIVA Server ISDN cards.
+  * Maint module
+@@ -24,10 +24,9 @@
+ #include "platform.h"
+ #include "di_defs.h"
+ #include "divasync.h"
+-#include "di_defs.h"
+ #include "debug_if.h"
+-static char *main_revision = "$Revision: 1.1.4.1 $";
++static char *main_revision = "$Revision: 1.1.4.1 $";
+ static int major;
+--- linux-2.6.0-test6/drivers/isdn/hardware/eicon/divasmain.c  2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/isdn/hardware/eicon/divasmain.c 2003-10-05 00:33:24.000000000 -0700
+@@ -1,4 +1,4 @@
+-/* $Id: 2.6.0-test6-mm4.patch,v 1.1.4.1 2003/10/10 09:31:08 ericm Exp $
++/* $Id: 2.6.0-test6-mm4.patch,v 1.1.4.1 2003/10/10 09:31:08 ericm Exp $
+  *
+  * Low level driver for Eicon DIVA Server ISDN cards.
+  *
+@@ -9,13 +9,11 @@
+  * of the GNU General Public License, incorporated herein by reference.
+  */
+-#define __KERNEL_SYSCALLS__
+ #include <linux/config.h>
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/kernel.h>
+ #include <linux/sched.h>
+-#include <linux/unistd.h>
+ #include <linux/devfs_fs_kernel.h>
+ #include <asm/uaccess.h>
+ #include <asm/io.h>
+@@ -43,7 +41,7 @@
+ #include "diva_dma.h"
+ #include "diva_pci.h"
+-static char *main_revision = "$Revision: 1.1.4.1 $";
++static char *main_revision = "$Revision: 1.1.4.1 $";
+ static int major;
+--- linux-2.6.0-test6/drivers/isdn/hardware/eicon/dqueue.c     2003-06-14 12:18:22.000000000 -0700
++++ 25/drivers/isdn/hardware/eicon/dqueue.c    2003-10-05 00:33:24.000000000 -0700
+@@ -1,10 +1,10 @@
+-/* $Id: 2.6.0-test6-mm4.patch,v 1.1.4.1 2003/10/10 09:31:08 ericm Exp $
++/* $Id: 2.6.0-test6-mm4.patch,v 1.1.4.1 2003/10/10 09:31:08 ericm Exp $
+  *
+  * Driver for Eicon DIVA Server ISDN cards.
+  * User Mode IDI Interface
+  *
+- * Copyright 2000,2001 by Armin Schindler (mac@melware.de)
+- * Copyright 2000,2001 Cytronics & Melware (info@melware.de)
++ * Copyright 2000-2003 by Armin Schindler (mac@melware.de)
++ * Copyright 2000-2003 Cytronics & Melware (info@melware.de)
+  *
+  * This software may be used and distributed according to the terms
+  * of the GNU General Public License, incorporated herein by reference.
+--- linux-2.6.0-test6/drivers/isdn/hardware/eicon/mntfunc.c    2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/isdn/hardware/eicon/mntfunc.c   2003-10-05 00:33:24.000000000 -0700
+@@ -1,4 +1,4 @@
+-/* $Id: 2.6.0-test6-mm4.patch,v 1.1.4.1 2003/10/10 09:31:08 ericm Exp $
++/* $Id: 2.6.0-test6-mm4.patch,v 1.1.4.1 2003/10/10 09:31:08 ericm Exp $
+  *
+  * Driver for Eicon DIVA Server ISDN cards.
+  * Maint module
+@@ -14,7 +14,6 @@
+ #include "platform.h"
+ #include "di_defs.h"
+ #include "divasync.h"
+-#include "di_defs.h"
+ #include "debug_if.h"
+ extern char *DRIVERRELEASE_MNT;
+--- linux-2.6.0-test6/drivers/isdn/hardware/eicon/os_capi.h    2003-06-14 12:18:25.000000000 -0700
++++ 25/drivers/isdn/hardware/eicon/os_capi.h   2003-10-05 00:33:24.000000000 -0700
+@@ -1,10 +1,10 @@
+-/* $Id: 2.6.0-test6-mm4.patch,v 1.1.4.1 2003/10/10 09:31:08 ericm Exp $
++/* $Id: 2.6.0-test6-mm4.patch,v 1.1.4.1 2003/10/10 09:31:08 ericm Exp $
+  *
+  * ISDN interface module for Eicon active cards DIVA.
+  * CAPI Interface OS include files 
+  * 
+- * Copyright 2000-2002 by Armin Schindler (mac@melware.de) 
+- * Copyright 2000-2002 Cytronics & Melware (info@melware.de)
++ * Copyright 2000-2003 by Armin Schindler (mac@melware.de) 
++ * Copyright 2000-2003 Cytronics & Melware (info@melware.de)
+  * 
+  * This software may be used and distributed according to the terms
+  * of the GNU General Public License, incorporated herein by reference.
+--- linux-2.6.0-test6/drivers/isdn/hardware/eicon/platform.h   2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/isdn/hardware/eicon/platform.h  2003-10-05 00:33:24.000000000 -0700
+@@ -1,4 +1,4 @@
+-/* $Id: 2.6.0-test6-mm4.patch,v 1.1.4.1 2003/10/10 09:31:08 ericm Exp $
++/* $Id: 2.6.0-test6-mm4.patch,v 1.1.4.1 2003/10/10 09:31:08 ericm Exp $
+  *
+  * platform.h
+  * 
+@@ -19,7 +19,6 @@
+ #endif
+ #include <linux/config.h>
+-#include <linux/version.h>
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/kernel.h>
+--- linux-2.6.0-test6/drivers/isdn/i4l/isdn_common.c   2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/isdn/i4l/isdn_common.c  2003-10-05 00:33:24.000000000 -0700
+@@ -2229,8 +2229,10 @@ static int __init isdn_init(void)
+       isdn_info_update();
+       return 0;
+-/* err_tty_modem:*/
++#ifdef CONFIG_ISDN_PPP
++ err_tty_modem:
+       isdn_tty_exit();
++#endif
+  err_cleanup_devfs:
+       isdn_cleanup_devfs();
+       unregister_chrdev(ISDN_MAJOR, "isdn");
+--- linux-2.6.0-test6/drivers/mca/mca-legacy.c 2003-08-22 19:23:40.000000000 -0700
++++ 25/drivers/mca/mca-legacy.c        2003-10-05 00:33:24.000000000 -0700
+@@ -28,7 +28,7 @@
+ #include <linux/module.h>
+ #include <linux/device.h>
+-#include <linux/mca.h>
++#include <linux/mca-legacy.h>
+ #include <asm/io.h>
+ /* NOTE: This structure is stack allocated */
+--- linux-2.6.0-test6/drivers/mca/mca-proc.c   2003-08-22 19:23:40.000000000 -0700
++++ 25/drivers/mca/mca-proc.c  2003-10-05 00:33:24.000000000 -0700
+@@ -120,12 +120,13 @@ static int mca_default_procfn(char* buf,
+       len += sprintf(buf+len, "Id: %02x%02x\n",
+               mca_dev->pos[1], mca_dev->pos[0]);
+       len += sprintf(buf+len, "Enabled: %s\nPOS: ",
+-              mca_isenabled(slot) ? "Yes" : "No");
++              mca_device_status(mca_dev) == MCA_ADAPTER_NORMAL ?
++                      "Yes" : "No");
+       for(i=0; i<8; i++) {
+               len += sprintf(buf+len, "%02x ", mca_dev->pos[i]);
+       }
+       len += sprintf(buf+len, "\nDriver Installed: %s",
+-              mca_is_adapter_used(slot) ? "Yes" : "No");
++              mca_device_claimed(mca_dev) ? "Yes" : "No");
+       buf[len++] = '\n';
+       buf[len] = 0;
+@@ -189,6 +190,7 @@ void __init mca_do_proc_init(void)
+       /* Initialize /proc/mca entries for existing adapters */
+       for(i = 0; i < MCA_NUMADAPTERS; i++) {
++              enum MCA_AdapterStatus status;
+               mca_dev = mca_find_device_by_slot(i);
+               if(!mca_dev)
+                       continue;
+@@ -200,7 +202,10 @@ void __init mca_do_proc_init(void)
+               else if(i == MCA_INTEGSCSI) sprintf(mca_dev->procname,"scsi");
+               else if(i == MCA_MOTHERBOARD) sprintf(mca_dev->procname,"planar");
+-              if(!mca_isadapter(i)) continue;
++              status = mca_device_status(mca_dev);
++              if (status != MCA_ADAPTER_NORMAL &&
++                  status != MCA_ADAPTER_DISABLED)
++                      continue;
+               node = create_proc_read_entry(mca_dev->procname, 0, proc_mca,
+                                             mca_read_proc, (void *)mca_dev);
+--- linux-2.6.0-test6/drivers/md/dm.c  2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/md/dm.c 2003-10-05 00:34:01.000000000 -0700
+@@ -160,20 +160,16 @@ static void __exit dm_exit(void)
+ /*
+  * Block device functions
+  */
+-static int dm_blk_open(struct inode *inode, struct file *file)
++static int dm_blk_open(struct block_device *bdev, struct file *file)
+ {
+-      struct mapped_device *md;
+-
+-      md = inode->i_bdev->bd_disk->private_data;
++      struct mapped_device *md = bdev->bd_disk->private_data;
+       dm_get(md);
+       return 0;
+ }
+-static int dm_blk_close(struct inode *inode, struct file *file)
++static int dm_blk_close(struct gendisk *disk)
+ {
+-      struct mapped_device *md;
+-
+-      md = inode->i_bdev->bd_disk->private_data;
++      struct mapped_device *md = disk->private_data;
+       dm_put(md);
+       return 0;
+ }
+--- linux-2.6.0-test6/drivers/md/md.c  2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/md/md.c 2003-10-05 00:34:01.000000000 -0700
+@@ -2360,11 +2360,10 @@ static int set_disk_faulty(mddev_t *mdde
+       return 1;
+ }
+-static int md_ioctl(struct inode *inode, struct file *file,
++static int md_ioctl(struct block_device *bdev, struct file *file,
+                       unsigned int cmd, unsigned long arg)
+ {
+       char b[BDEVNAME_SIZE];
+-      unsigned int minor = iminor(inode);
+       int err = 0;
+       struct hd_geometry *loc = (struct hd_geometry *) arg;
+       mddev_t *mddev = NULL;
+@@ -2372,11 +2371,6 @@ static int md_ioctl(struct inode *inode,
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
+-      if (minor >= MAX_MD_DEVS) {
+-              MD_BUG();
+-              return -EINVAL;
+-      }
+-
+       /*
+        * Commands dealing with the RAID driver but not any
+        * particular array:
+@@ -2405,7 +2399,7 @@ static int md_ioctl(struct inode *inode,
+        * Commands creating/starting a new array:
+        */
+-      mddev = inode->i_bdev->bd_inode->u.generic_ip;
++      mddev = bdev->bd_inode->u.generic_ip;
+       if (!mddev) {
+               BUG();
+@@ -2527,7 +2521,7 @@ static int md_ioctl(struct inode *inode,
+                                               (short *) &loc->cylinders);
+                       if (err)
+                               goto abort_unlock;
+-                      err = put_user (get_start_sect(inode->i_bdev),
++                      err = put_user (get_start_sect(bdev),
+                                               (long *) &loc->start);
+                       goto done_unlock;
+       }
+@@ -2605,12 +2599,12 @@ abort:
+       return err;
+ }
+-static int md_open(struct inode *inode, struct file *file)
++static int md_open(struct block_device *bdev, struct file *file)
+ {
+       /*
+        * Succeed if we can find or allocate a mddev structure.
+        */
+-      mddev_t *mddev = mddev_find(iminor(inode));
++      mddev_t *mddev = mddev_find(MINOR(bdev->bd_dev));
+       int err = -ENOMEM;
+       if (!mddev)
+@@ -2621,16 +2615,16 @@ static int md_open(struct inode *inode, 
+       err = 0;
+       mddev_unlock(mddev);
+-      inode->i_bdev->bd_inode->u.generic_ip = mddev_get(mddev);
++      bdev->bd_inode->u.generic_ip = mddev_get(mddev);
+  put:
+       mddev_put(mddev);
+  out:
+       return err;
+ }
+-static int md_release(struct inode *inode, struct file * file)
++static int md_release(struct gendisk *disk)
+ {
+-      mddev_t *mddev = inode->i_bdev->bd_inode->u.generic_ip;
++      mddev_t *mddev = disk->private_data;
+       if (!mddev)
+               BUG();
+--- linux-2.6.0-test6/drivers/media/common/saa7146_i2c.c       2003-08-08 22:55:12.000000000 -0700
++++ 25/drivers/media/common/saa7146_i2c.c      2003-10-05 00:33:24.000000000 -0700
+@@ -1,3 +1,4 @@
++#include <linux/version.h>
+ #include <media/saa7146_vv.h>
+ /* helper function */
+--- linux-2.6.0-test6/drivers/media/dvb/dvb-core/dvbdev.h      2003-07-27 12:14:39.000000000 -0700
++++ 25/drivers/media/dvb/dvb-core/dvbdev.h     2003-10-05 00:33:24.000000000 -0700
+@@ -28,7 +28,6 @@
+ #include <linux/poll.h>
+ #include <linux/fs.h>
+ #include <linux/list.h>
+-#include <linux/version.h>
+ #include <linux/devfs_fs_kernel.h>
+ #define DVB_MAJOR 250
+--- linux-2.6.0-test6/drivers/media/dvb/dvb-core/dvb_functions.c       2003-07-27 12:14:39.000000000 -0700
++++ 25/drivers/media/dvb/dvb-core/dvb_functions.c      2003-10-05 00:33:24.000000000 -0700
+@@ -1,4 +1,3 @@
+-#include <linux/version.h>
+ #include <linux/errno.h>
+ #include <linux/fs.h>
+ #include <linux/string.h>
+--- linux-2.6.0-test6/drivers/media/dvb/dvb-core/dvb_functions.h       2003-07-27 12:14:39.000000000 -0700
++++ 25/drivers/media/dvb/dvb-core/dvb_functions.h      2003-10-05 00:33:24.000000000 -0700
+@@ -1,8 +1,6 @@
+ #ifndef __DVB_FUNCTIONS_H__
+ #define __DVB_FUNCTIONS_H__
+-#include <linux/version.h>
+-
+ /**
+  *  a sleeping delay function, waits i ms
+  *
+--- linux-2.6.0-test6/drivers/media/dvb/ttpci/av7110.c 2003-07-27 12:14:39.000000000 -0700
++++ 25/drivers/media/dvb/ttpci/av7110.c        2003-10-05 00:33:24.000000000 -0700
+@@ -55,10 +55,8 @@
+ #include <linux/ptrace.h>
+ #include <linux/ioport.h>
+ #include <linux/in.h>
+-#include <linux/slab.h>
+ #include <linux/string.h>
+ #include <linux/pci.h>
+-#include <linux/init.h>
+ #include <linux/vmalloc.h>
+ #include <linux/netdevice.h>
+ #include <linux/inetdevice.h>
+@@ -4745,12 +4743,19 @@ static struct saa7146_extension av7110_e
+ static int __init av7110_init(void) 
+ {
+-      if (saa7146_register_extension(&av7110_extension))
+-              return -ENODEV;
++      int retval;
++      retval = saa7146_register_extension(&av7110_extension);
++      if (retval)
++              goto failed_saa7146_register;
+       
+-      av7110_ir_init();
+-
++      retval = av7110_ir_init();
++      if (retval)
++              goto failed_av7110_ir_init;
+       return 0;
++failed_av7110_ir_init:
++      saa7146_unregister_extension(&av7110_extension);
++failed_saa7146_register:
++      return retval;
+ }
+--- linux-2.6.0-test6/drivers/media/dvb/ttpci/budget.c 2003-07-27 12:14:39.000000000 -0700
++++ 25/drivers/media/dvb/ttpci/budget.c        2003-10-05 00:33:24.000000000 -0700
+@@ -228,10 +228,7 @@ static struct saa7146_extension budget_e
+ static int __init budget_init(void) 
+ {
+-      if (saa7146_register_extension(&budget_extension))
+-              return -ENODEV;
+-      
+-      return 0;
++      return saa7146_register_extension(&budget_extension);
+ }
+--- linux-2.6.0-test6/drivers/media/dvb/ttpci/budget-ci.c      2003-07-27 12:14:39.000000000 -0700
++++ 25/drivers/media/dvb/ttpci/budget-ci.c     2003-10-05 00:33:24.000000000 -0700
+@@ -384,10 +384,7 @@ static struct saa7146_extension budget_e
+ static int __init budget_ci_init(void) 
+ {
+-      if (saa7146_register_extension(&budget_extension))
+-              return -ENODEV;
+-      
+-      return 0;
++      return saa7146_register_extension(&budget_extension);
+ }
+--- linux-2.6.0-test6/drivers/media/dvb/ttpci/budget-patch.c   2003-08-08 22:55:12.000000000 -0700
++++ 25/drivers/media/dvb/ttpci/budget-patch.c  2003-10-05 00:33:24.000000000 -0700
+@@ -247,10 +247,7 @@ static int budget_patch_detach (struct s
+ static int __init budget_patch_init(void) 
+ {
+-        if (saa7146_register_extension(&budget_extension))
+-                return -ENODEV;
+-        
+-        return 0;
++      return saa7146_register_extension(&budget_extension);
+ }
+--- linux-2.6.0-test6/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c        2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c       2003-10-05 00:33:24.000000000 -0700
+@@ -9,6 +9,7 @@
+  *    published by the Free Software Foundation; either version 2 of
+  *    the License, or (at your option) any later version.
+  */
++#include <linux/version.h>
+ #include <linux/init.h>
+ #include <linux/slab.h>
+ #include <linux/wait.h>
+@@ -27,7 +28,6 @@
+ #include <linux/dvb/frontend.h>
+ #include <linux/dvb/dmx.h>
+ #include <linux/pci.h>
+-#include <linux/usb.h>
+ #include "dvb_functions.h"
+@@ -1055,7 +1055,8 @@ static ssize_t stc_read(struct file *fil
+       if (tc < 0)
+               return 0;
+-      copy_to_user(buf, stc_firmware + *offset, tc);
++      if (copy_to_user(buf, stc_firmware + *offset, tc))
++              return -EFAULT;
+       *offset += tc;
+--- linux-2.6.0-test6/drivers/media/dvb/ttusb-dec/ttusb_dec.c  2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/media/dvb/ttusb-dec/ttusb_dec.c 2003-10-05 00:33:24.000000000 -0700
+@@ -19,6 +19,7 @@
+  *
+  */
++#include <linux/version.h>
+ #include <linux/module.h>
+ #include <linux/pci.h>
+ #include <linux/slab.h>
+--- linux-2.6.0-test6/drivers/media/radio/radio-gemtek-pci.c   2003-06-14 12:17:57.000000000 -0700
++++ 25/drivers/media/radio/radio-gemtek-pci.c  2003-10-05 00:33:24.000000000 -0700
+@@ -37,7 +37,6 @@
+  ***************************************************************************
+  */
+-#include <linux/version.h>
+ #include <linux/config.h>
+ #include <linux/types.h>
+ #include <linux/list.h>
+--- linux-2.6.0-test6/drivers/media/video/adv7170.c    2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/media/video/adv7170.c   2003-10-05 00:33:24.000000000 -0700
+@@ -28,8 +28,6 @@
+  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+  */
+-#include <linux/version.h>
+-
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/delay.h>
+@@ -49,7 +47,6 @@
+ #include <linux/types.h>
+ #include <linux/videodev.h>
+-#include <linux/version.h>
+ #include <asm/uaccess.h>
+ MODULE_DESCRIPTION("Analog Devices ADV7170 video encoder driver");
+--- linux-2.6.0-test6/drivers/media/video/adv7175.c    2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/media/video/adv7175.c   2003-10-05 00:33:24.000000000 -0700
+@@ -24,8 +24,6 @@
+  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+  */
+-#include <linux/version.h>
+-
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/delay.h>
+@@ -45,7 +43,6 @@
+ #include <linux/types.h>
+ #include <linux/videodev.h>
+-#include <linux/version.h>
+ #include <asm/uaccess.h>
+ MODULE_DESCRIPTION("Analog Devices ADV7175 video encoder driver");
+--- linux-2.6.0-test6/drivers/media/video/bt819.c      2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/media/video/bt819.c     2003-10-05 00:33:24.000000000 -0700
+@@ -28,8 +28,6 @@
+  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+  */
+-#include <linux/version.h>
+-
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/delay.h>
+@@ -49,7 +47,6 @@
+ #include <linux/types.h>
+ #include <linux/videodev.h>
+-#include <linux/version.h>
+ #include <asm/uaccess.h>
+ MODULE_DESCRIPTION("Brooktree-819 video decoder driver");
+--- linux-2.6.0-test6/drivers/media/video/bt856.c      2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/media/video/bt856.c     2003-10-05 00:33:24.000000000 -0700
+@@ -28,8 +28,6 @@
+  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+  */
+-#include <linux/version.h>
+-
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/delay.h>
+@@ -49,7 +47,6 @@
+ #include <linux/types.h>
+ #include <linux/videodev.h>
+-#include <linux/version.h>
+ #include <asm/uaccess.h>
+ MODULE_DESCRIPTION("Brooktree-856A video encoder driver");
+--- linux-2.6.0-test6/drivers/media/video/bttvp.h      2003-08-22 19:23:40.000000000 -0700
++++ 25/drivers/media/video/bttvp.h     2003-10-05 00:33:24.000000000 -0700
+@@ -25,6 +25,7 @@
+ #define _BTTVP_H_
++#include <linux/version.h>
+ #define BTTV_VERSION_CODE KERNEL_VERSION(0,9,11)
+ #include <linux/types.h>
+--- linux-2.6.0-test6/drivers/media/video/bw-qcam.c    2003-08-08 22:55:12.000000000 -0700
++++ 25/drivers/media/video/bw-qcam.c   2003-10-05 00:33:24.000000000 -0700
+@@ -72,7 +72,6 @@ OTHER DEALINGS IN THE SOFTWARE.
+ #include <linux/mm.h>
+ #include <linux/parport.h>
+ #include <linux/sched.h>
+-#include <linux/version.h>
+ #include <linux/videodev.h>
+ #include <asm/semaphore.h>
+ #include <asm/uaccess.h>
+--- linux-2.6.0-test6/drivers/media/video/cpia.c       2003-08-08 22:55:12.000000000 -0700
++++ 25/drivers/media/video/cpia.c      2003-10-05 00:33:24.000000000 -0700
+@@ -29,7 +29,6 @@
+ #include <linux/config.h>
+ #include <linux/module.h>
+-#include <linux/version.h>
+ #include <linux/init.h>
+ #include <linux/fs.h>
+ #include <linux/vmalloc.h>
+--- linux-2.6.0-test6/drivers/media/video/cpia_pp.c    2003-06-14 12:17:56.000000000 -0700
++++ 25/drivers/media/video/cpia_pp.c   2003-10-05 00:33:24.000000000 -0700
+@@ -26,7 +26,6 @@
+ /* #define _CPIA_DEBUG_  1 */  
+ #include <linux/config.h>
+-#include <linux/version.h>
+ #include <linux/module.h>
+ #include <linux/init.h>
+--- linux-2.6.0-test6/drivers/media/video/c-qcam.c     2003-08-08 22:55:12.000000000 -0700
++++ 25/drivers/media/video/c-qcam.c    2003-10-05 00:33:24.000000000 -0700
+@@ -33,7 +33,6 @@
+ #include <linux/mm.h>
+ #include <linux/parport.h>
+ #include <linux/sched.h>
+-#include <linux/version.h>
+ #include <linux/videodev.h>
+ #include <asm/semaphore.h>
+ #include <asm/uaccess.h>
+--- linux-2.6.0-test6/drivers/media/video/meye.h       2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/media/video/meye.h      2003-10-05 00:33:24.000000000 -0700
+@@ -36,8 +36,6 @@
+ #include <linux/config.h>
+ #include <linux/types.h>
+ #include <linux/pci.h>
+-#include <linux/sonypi.h>
+-#include <linux/meye.h>
+ /****************************************************************************/
+ /* Motion JPEG chip registers                                               */
+--- linux-2.6.0-test6/drivers/media/video/planb.c      2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/media/video/planb.c     2003-10-05 00:33:24.000000000 -0700
+@@ -27,7 +27,6 @@
+ /* $Id: 2.6.0-test6-mm4.patch,v 1.1.4.1 2003/10/10 09:31:08 ericm Exp $ */
+-#include <linux/version.h>
+ #include <linux/init.h>
+ #include <linux/errno.h>
+ #include <linux/module.h>
+--- linux-2.6.0-test6/drivers/media/video/pms.c        2003-08-08 22:55:12.000000000 -0700
++++ 25/drivers/media/video/pms.c       2003-10-05 00:33:24.000000000 -0700
+@@ -30,7 +30,6 @@
+ #include <asm/io.h>
+ #include <linux/sched.h>
+ #include <linux/videodev.h>
+-#include <linux/version.h>
+ #include <asm/uaccess.h>
+--- linux-2.6.0-test6/drivers/media/video/saa7110.c    2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/media/video/saa7110.c   2003-10-05 00:33:24.000000000 -0700
+@@ -25,8 +25,6 @@
+  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+  */
+-#include <linux/version.h>
+-
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/types.h>
+--- linux-2.6.0-test6/drivers/media/video/saa7111.c    2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/media/video/saa7111.c   2003-10-05 00:33:24.000000000 -0700
+@@ -24,8 +24,6 @@
+  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+  */
+-#include <linux/version.h>
+-
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/delay.h>
+@@ -45,7 +43,6 @@
+ #include <linux/types.h>
+ #include <linux/videodev.h>
+-#include <linux/version.h>
+ #include <asm/uaccess.h>
+ MODULE_DESCRIPTION("Philips SAA7111 video decoder driver");
+--- linux-2.6.0-test6/drivers/media/video/saa7114.c    2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/media/video/saa7114.c   2003-10-05 00:33:24.000000000 -0700
+@@ -28,8 +28,6 @@
+  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+  */
+-#include <linux/version.h>
+-
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/delay.h>
+@@ -51,7 +49,6 @@
+ #include <linux/types.h>
+ #include <linux/videodev.h>
+-#include <linux/version.h>
+ #include <asm/uaccess.h>
+ MODULE_DESCRIPTION("Philips SAA7114H video decoder driver");
+--- linux-2.6.0-test6/drivers/media/video/saa7134/saa7134.h    2003-08-08 22:55:12.000000000 -0700
++++ 25/drivers/media/video/saa7134/saa7134.h   2003-10-05 00:33:24.000000000 -0700
+@@ -18,6 +18,7 @@
+  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+  */
++#include <linux/version.h>
+ #include <linux/pci.h>
+ #include <linux/i2c.h>
+ #include <linux/videodev.h>
+--- linux-2.6.0-test6/drivers/media/video/saa7185.c    2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/media/video/saa7185.c   2003-10-05 00:33:24.000000000 -0700
+@@ -24,8 +24,6 @@
+  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+  */
+-#include <linux/version.h>
+-
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/delay.h>
+@@ -45,7 +43,6 @@
+ #include <linux/types.h>
+ #include <linux/videodev.h>
+-#include <linux/version.h>
+ #include <asm/uaccess.h>
+ MODULE_DESCRIPTION("Philips SAA7185 video encoder driver");
+--- linux-2.6.0-test6/drivers/media/video/stradis.c    2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/media/video/stradis.c   2003-10-05 00:33:24.000000000 -0700
+@@ -20,7 +20,6 @@
+  */
+ #include <linux/module.h>
+-#include <linux/version.h>
+ #include <linux/delay.h>
+ #include <linux/errno.h>
+ #include <linux/fs.h>
+--- linux-2.6.0-test6/drivers/media/video/tuner-3036.c 2003-08-08 22:55:12.000000000 -0700
++++ 25/drivers/media/video/tuner-3036.c        2003-10-05 00:33:24.000000000 -0700
+@@ -21,7 +21,6 @@
+ #include <linux/delay.h>
+ #include <linux/errno.h>
+ #include <linux/slab.h>
+-#include <linux/version.h>
+ #include <linux/init.h>
+ #include <linux/i2c.h>
+--- linux-2.6.0-test6/drivers/media/video/v4l2-common.c        2003-06-14 12:18:34.000000000 -0700
++++ 25/drivers/media/video/v4l2-common.c       2003-10-05 00:33:24.000000000 -0700
+@@ -45,7 +45,6 @@
+  */
+ #include <linux/config.h>
+-#include <linux/version.h>
+ #include <linux/module.h>
+ #include <linux/types.h>
+ #include <linux/kernel.h>
+--- linux-2.6.0-test6/drivers/media/video/videocodec.c 2003-08-22 19:23:40.000000000 -0700
++++ 25/drivers/media/video/videocodec.c        2003-10-05 00:33:24.000000000 -0700
+@@ -29,7 +29,6 @@
+ #define VIDEOCODEC_VERSION "v0.2"
+-#include <linux/version.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/init.h>
+--- linux-2.6.0-test6/drivers/media/video/videodev.c   2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/media/video/videodev.c  2003-10-05 00:33:24.000000000 -0700
+@@ -15,7 +15,6 @@
+  *            - Added procfs support
+  */
+-#include <linux/version.h>
+ #include <linux/module.h>
+ #include <linux/types.h>
+ #include <linux/kernel.h>
+@@ -27,7 +26,6 @@
+ #include <linux/init.h>
+ #include <linux/kmod.h>
+ #include <linux/slab.h>
+-#include <linux/types.h>
+ #include <linux/devfs_fs_kernel.h>
+ #include <asm/uaccess.h>
+ #include <asm/system.h>
+@@ -52,7 +50,7 @@ static ssize_t show_dev(struct class_dev
+ {
+       struct video_device *vfd = container_of(cd, struct video_device, class_dev);
+       dev_t dev = MKDEV(VIDEO_MAJOR, vfd->minor);
+-      return sprintf(buf,"%04x\n",old_encode_dev(dev));
++      return print_dev_t(buf,dev);
+ }
+ static CLASS_DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+--- linux-2.6.0-test6/drivers/media/video/vpx3220.c    2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/media/video/vpx3220.c   2003-10-05 00:33:24.000000000 -0700
+@@ -18,7 +18,6 @@
+  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+  */
+-#include <linux/version.h>
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/delay.h>
+--- linux-2.6.0-test6/drivers/media/video/zoran_card.c 2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/media/video/zoran_card.c        2003-10-05 00:33:24.000000000 -0700
+@@ -28,7 +28,6 @@
+  */
+ #include <linux/config.h>
+-#include <linux/version.h>
+ #include <linux/types.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+--- linux-2.6.0-test6/drivers/media/video/zoran_device.c       2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/media/video/zoran_device.c      2003-10-05 00:33:24.000000000 -0700
+@@ -28,7 +28,6 @@
+  */
+ #include <linux/config.h>
+-#include <linux/version.h>
+ #include <linux/types.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+--- linux-2.6.0-test6/drivers/media/video/zoran_procfs.c       2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/media/video/zoran_procfs.c      2003-10-05 00:33:24.000000000 -0700
+@@ -28,7 +28,6 @@
+  */
+ #include <linux/config.h>
+-#include <linux/version.h>
+ #include <linux/types.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+--- linux-2.6.0-test6/drivers/media/video/zr36120.c    2003-08-08 22:55:12.000000000 -0700
++++ 25/drivers/media/video/zr36120.c   2003-10-05 00:33:24.000000000 -0700
+@@ -36,7 +36,6 @@
+ #include <linux/sched.h>
+ #include <linux/video_decoder.h>
+-#include <linux/version.h>
+ #include <asm/uaccess.h>
+ #include "tuner.h"
+--- linux-2.6.0-test6/drivers/media/video/zr36120_i2c.c        2003-06-14 12:18:52.000000000 -0700
++++ 25/drivers/media/video/zr36120_i2c.c       2003-10-05 00:33:24.000000000 -0700
+@@ -22,7 +22,6 @@
+ #include <linux/delay.h>
+ #include <asm/io.h>
+-#include <linux/version.h>
+ #include <linux/video_decoder.h>
+ #include <asm/uaccess.h>
+--- linux-2.6.0-test6/drivers/message/i2o/i2o_block.c  2003-08-08 22:55:12.000000000 -0700
++++ 25/drivers/message/i2o/i2o_block.c 2003-10-05 00:34:01.000000000 -0700
+@@ -885,10 +885,10 @@ static void i2o_block_biosparam(
+  *    Issue device specific ioctl calls.
+  */
+-static int i2ob_ioctl(struct inode *inode, struct file *file,
++static int i2ob_ioctl(struct block_device *bdev, struct file *file,
+                    unsigned int cmd, unsigned long arg)
+ {
+-      struct gendisk *disk = inode->i_bdev->bd_disk;
++      struct gendisk *disk = bdev->bd_disk;
+       struct i2ob_device *dev = disk->private_data;
+       /* Anyone capable of this syscall can do *real bad* things */
+@@ -901,7 +901,7 @@ static int i2ob_ioctl(struct inode *inod
+                       struct hd_geometry g;
+                       i2o_block_biosparam(get_capacity(disk), 
+                                       &g.cylinders, &g.heads, &g.sectors);
+-                      g.start = get_start_sect(inode->i_bdev);
++                      g.start = get_start_sect(bdev);
+                       return copy_to_user((void *)arg,&g, sizeof(g))?-EFAULT:0;
+               }
+               
+@@ -927,9 +927,8 @@ static int i2ob_ioctl(struct inode *inod
+  *    Close the block device down
+  */
+  
+-static int i2ob_release(struct inode *inode, struct file *file)
++static int i2ob_release(struct gendisk *disk)
+ {
+-      struct gendisk *disk = inode->i_bdev->bd_disk;
+       struct i2ob_device *dev = disk->private_data;
+       /*
+@@ -999,9 +998,9 @@ static int i2ob_release(struct inode *in
+  *    Open the block device.
+  */
+  
+-static int i2ob_open(struct inode *inode, struct file *file)
++static int i2ob_open(struct block_device *bdev, struct file *file)
+ {
+-      struct gendisk *disk = inode->i_bdev->bd_disk;
++      struct gendisk *disk = bdev->bd_disk;
+       struct i2ob_device *dev = disk->private_data;
+       if(!dev->i2odev)        
+--- linux-2.6.0-test6/drivers/mtd/chips/cfi_cmdset_0020.c      2003-06-14 12:18:06.000000000 -0700
++++ 25/drivers/mtd/chips/cfi_cmdset_0020.c     2003-10-05 00:33:24.000000000 -0700
+@@ -17,6 +17,7 @@
+  *    - added a writev function
+  */
++#include <linux/version.h>
+ #include <linux/module.h>
+ #include <linux/types.h>
+ #include <linux/kernel.h>
+@@ -26,7 +27,6 @@
+ #include <asm/byteorder.h>
+ #include <linux/errno.h>
+-#include <linux/init.h>
+ #include <linux/slab.h>
+ #include <linux/delay.h>
+ #include <linux/interrupt.h>
+@@ -208,6 +208,7 @@ static struct mtd_info *cfi_staa_setup(s
+       if (!mtd->eraseregions) { 
+               printk(KERN_ERR "Failed to allocate memory for MTD erase region info\n");
+               kfree(cfi->cmdset_priv);
++              kfree(mtd);
+               return NULL;
+       }
+       
+@@ -232,6 +233,7 @@ static struct mtd_info *cfi_staa_setup(s
+                       printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize);
+                       kfree(mtd->eraseregions);
+                       kfree(cfi->cmdset_priv);
++                      kfree(mtd);
+                       return NULL;
+               }
+--- linux-2.6.0-test6/drivers/mtd/chips/gen_probe.c    2003-07-02 14:53:14.000000000 -0700
++++ 25/drivers/mtd/chips/gen_probe.c   2003-10-05 00:33:24.000000000 -0700
+@@ -11,7 +11,6 @@
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/map.h>
+ #include <linux/mtd/cfi.h>
+-#include <linux/mtd/mtd.h>
+ #include <linux/mtd/gen_probe.h>
+ static struct mtd_info *check_cmd_set(struct map_info *, int);
+--- linux-2.6.0-test6/drivers/mtd/chips/map_rom.c      2003-06-14 12:18:24.000000000 -0700
++++ 25/drivers/mtd/chips/map_rom.c     2003-10-05 00:33:24.000000000 -0700
+@@ -4,7 +4,6 @@
+  * $Id: 2.6.0-test6-mm4.patch,v 1.1.4.1 2003/10/10 09:31:08 ericm Exp $
+  */
+-#include <linux/version.h>
+ #include <linux/module.h>
+ #include <linux/types.h>
+ #include <linux/kernel.h>
+--- linux-2.6.0-test6/drivers/mtd/chips/sharp.c        2003-08-22 19:23:41.000000000 -0700
++++ 25/drivers/mtd/chips/sharp.c       2003-10-05 00:33:24.000000000 -0700
+@@ -22,7 +22,6 @@
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+-#include <linux/version.h>
+ #include <linux/types.h>
+ #include <linux/sched.h>
+ #include <linux/errno.h>
+--- linux-2.6.0-test6/drivers/mtd/devices/lart.c       2003-06-14 12:18:08.000000000 -0700
++++ 25/drivers/mtd/devices/lart.c      2003-10-05 00:33:24.000000000 -0700
+@@ -42,7 +42,6 @@
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/types.h>
+-#include <linux/version.h>
+ #include <linux/errno.h>
+ #include <linux/mtd/mtd.h>
+ #ifdef HAVE_PARTITIONS
+--- linux-2.6.0-test6/drivers/mtd/devices/pmc551.c     2003-06-14 12:18:29.000000000 -0700
++++ 25/drivers/mtd/devices/pmc551.c    2003-10-05 00:33:24.000000000 -0700
+@@ -82,6 +82,7 @@
+  *       * Comb the init routine.  It's still a bit cludgy on a few things.
+  */
++#include <linux/version.h>
+ #include <linux/config.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+--- linux-2.6.0-test6/drivers/mtd/maps/integrator-flash.c      2003-06-14 12:18:29.000000000 -0700
++++ 25/drivers/mtd/maps/integrator-flash.c     2003-10-05 00:33:24.000000000 -0700
+@@ -31,223 +31,181 @@
+ #include <linux/kernel.h>
+ #include <linux/slab.h>
+ #include <linux/ioport.h>
++#include <linux/device.h>
+ #include <linux/init.h>
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/map.h>
+ #include <linux/mtd/partitions.h>
++#include <asm/mach/flash.h>
+ #include <asm/hardware.h>
+ #include <asm/io.h>
+ #include <asm/system.h>
+-// board specific stuff - sorry, it should be in arch/arm/mach-*.
+-#ifdef CONFIG_ARCH_INTEGRATOR
+-
+-#define FLASH_BASE    INTEGRATOR_FLASH_BASE
+-#define FLASH_SIZE    INTEGRATOR_FLASH_SIZE
+-
+-#define FLASH_PART_SIZE 0x400000
+-
+-#define SC_CTRLC      (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLC_OFFSET)
+-#define SC_CTRLS      (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLS_OFFSET)
+-#define EBI_CSR1      (IO_ADDRESS(INTEGRATOR_EBI_BASE) + INTEGRATOR_EBI_CSR1_OFFSET)
+-#define EBI_LOCK      (IO_ADDRESS(INTEGRATOR_EBI_BASE) + INTEGRATOR_EBI_LOCK_OFFSET)
+-
+-/*
+- * Initialise the flash access systems:
+- *  - Disable VPP
+- *  - Assert WP
+- *  - Set write enable bit in EBI reg
+- */
+-static void armflash_flash_init(void)
+-{
+-      unsigned int tmp;
+-
+-      __raw_writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, SC_CTRLC);
+-
+-      tmp = __raw_readl(EBI_CSR1) | INTEGRATOR_EBI_WRITE_ENABLE;
+-      __raw_writel(tmp, EBI_CSR1);
+-
+-      if (!(__raw_readl(EBI_CSR1) & INTEGRATOR_EBI_WRITE_ENABLE)) {
+-              __raw_writel(0xa05f, EBI_LOCK);
+-              __raw_writel(tmp, EBI_CSR1);
+-              __raw_writel(0, EBI_LOCK);
+-      }
+-}
+-
+-/*
+- * Shutdown the flash access systems:
+- *  - Disable VPP
+- *  - Assert WP
+- *  - Clear write enable bit in EBI reg
+- */
+-static void armflash_flash_exit(void)
+-{
+-      unsigned int tmp;
+-
+-      __raw_writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, SC_CTRLC);
+-
+-      /*
+-       * Clear the write enable bit in system controller EBI register.
+-       */
+-      tmp = __raw_readl(EBI_CSR1) & ~INTEGRATOR_EBI_WRITE_ENABLE;
+-      __raw_writel(tmp, EBI_CSR1);
+-
+-      if (__raw_readl(EBI_CSR1) & INTEGRATOR_EBI_WRITE_ENABLE) {
+-              __raw_writel(0xa05f, EBI_LOCK);
+-              __raw_writel(tmp, EBI_CSR1);
+-              __raw_writel(0, EBI_LOCK);
+-      }
+-}
+-
+-static void armflash_flash_wp(int on)
+-{
+-      unsigned int reg;
+-
+-      if (on)
+-              reg = SC_CTRLC;
+-      else
+-              reg = SC_CTRLS;
+-
+-      __raw_writel(INTEGRATOR_SC_CTRL_nFLWP, reg);
+-}
+-
+-static void armflash_set_vpp(struct map_info *map, int on)
+-{
+-      unsigned int reg;
+-
+-      if (on)
+-              reg = SC_CTRLS;
+-      else
+-              reg = SC_CTRLC;
+-
+-      __raw_writel(INTEGRATOR_SC_CTRL_nFLVPPEN, reg);
+-}
+-#endif
+-
+ #ifdef CONFIG_ARCH_P720T
+-
+ #define FLASH_BASE            (0x04000000)
+ #define FLASH_SIZE            (64*1024*1024)
++#endif
+-#define FLASH_PART_SIZE       (4*1024*1024)
+-#define FLASH_BLOCK_SIZE      (128*1024)
++struct armflash_info {
++      struct flash_platform_data *plat;
++      struct resource         *res;
++      struct mtd_partition    *parts;
++      struct mtd_info         *mtd;
++      struct map_info         map;
++};
+-static void armflash_flash_init(void)
++static void armflash_set_vpp(struct map_info *map, int on)
+ {
+-}
++      struct armflash_info *info = container_of(map, struct armflash_info, map);
+-static void armflash_flash_exit(void)
+-{
++      if (info->plat && info->plat->set_vpp)
++              info->plat->set_vpp(on);
+ }
+-static void armflash_flash_wp(int on)
+-{
+-}
++static const char *probes[] = { "RedBoot", "afs", NULL };
+-static void armflash_set_vpp(struct map_info *map, int on)
++static int armflash_probe(struct device *_dev)
+ {
+-}
+-#endif
++      struct platform_device *dev = to_platform_device(_dev);
++      struct flash_platform_data *plat = dev->dev.platform_data;
++      struct resource *res = dev->resource;
++      unsigned int size = res->end - res->start + 1;
++      struct armflash_info *info;
++      int err;
++      void *base;
++      info = kmalloc(sizeof(struct armflash_info), GFP_KERNEL);
++      if (!info) {
++              err = -ENOMEM;
++              goto out;
++      }
+-static struct map_info armflash_map =
+-{
+-      .name =         "AFS",
+-      .set_vpp =      armflash_set_vpp,
+-      .phys =         FLASH_BASE,
+-};
++      memset(info, 0, sizeof(struct armflash_info));
+-static struct mtd_info *mtd;
+-static struct mtd_partition *parts;
+-static const char *probes[] = { "RedBoot", "afs", NULL };
++      info->plat = plat;
++      if (plat && plat->init) {
++              err = plat->init();
++              if (err)
++                      goto no_resource;
++      }
+-static int __init armflash_cfi_init(void *base, u_int size)
+-{
+-      int ret;
++      info->res = request_mem_region(res->start, size, "armflash");
++      if (!info->res) {
++              err = -EBUSY;
++              goto no_resource;
++      }
+-      armflash_flash_init();
+-      armflash_flash_wp(1);
++      base = ioremap(res->start, size);
++      if (!base) {
++              err = -ENOMEM;
++              goto no_mem;
++      }
+       /*
+        * look for CFI based flash parts fitted to this board
+        */
+-      armflash_map.size       = size;
+-      armflash_map.buswidth   = 4;
+-      armflash_map.virt = (unsigned long) base;
++      info->map.size          = size;
++      info->map.buswidth      = plat->width;
++      info->map.phys          = res->start;
++      info->map.virt          = (unsigned long) base;
++      info->map.name          = dev->dev.bus_id;
++      info->map.set_vpp       = armflash_set_vpp;
+-      simple_map_init(&armflash_map);
++      simple_map_init(&info->map);
+       /*
+        * Also, the CFI layer automatically works out what size
+        * of chips we have, and does the necessary identification
+        * for us automatically.
+        */
+-      mtd = do_map_probe("cfi_probe", &armflash_map);
+-      if (!mtd)
+-              return -ENXIO;
+-
+-      mtd->owner = THIS_MODULE;
+-
+-      ret = parse_mtd_partitions(mtd, probes, &parts, (void *)0);
+-      if (ret > 0) {
+-              ret = add_mtd_partitions(mtd, parts, ret);
+-              if (ret)
+-                      printk(KERN_ERR "mtd partition registration "
+-                              "failed: %d\n", ret);
++      info->mtd = do_map_probe(plat->map_name, &info->map);
++      if (!info->mtd) {
++              err = -ENXIO;
++              goto no_device;
+       }
++      info->mtd->owner = THIS_MODULE;
++
++      err = parse_mtd_partitions(info->mtd, probes, &info->parts, 0);
++      if (err > 0) {
++              err = add_mtd_partitions(info->mtd, info->parts, err);
++              if (err)
++                      printk(KERN_ERR
++                             "mtd partition registration failed: %d\n", err);
++      }
++
++      if (err == 0)
++              dev_set_drvdata(&dev->dev, info);
++
+       /*
+        * If we got an error, free all resources.
+        */
+-      if (ret < 0) {
+-              del_mtd_partitions(mtd);
+-              map_destroy(mtd);
+-      }
++      if (err < 0) {
++              if (info->mtd) {
++                      del_mtd_partitions(info->mtd);
++                      map_destroy(info->mtd);
++              }
++              if (info->parts)
++                      kfree(info->parts);
+-      return ret;
+-}
+-
+-static void armflash_cfi_exit(void)
+-{
+-      if (mtd) {
+-              del_mtd_partitions(mtd);
+-              map_destroy(mtd);
++ no_device:
++              iounmap(base);
++ no_mem:
++              release_mem_region(res->start, size);
++ no_resource:
++              if (plat && plat->exit)
++                      plat->exit();
++              kfree(info);
+       }
+-      if (parts)
+-              kfree(parts);
++ out:
++      return err;
+ }
+-static int __init armflash_init(void)
++static int armflash_remove(struct device *_dev)
+ {
+-      int err = -EBUSY;
+-      void *base;
++      struct platform_device *dev = to_platform_device(_dev);
++      struct armflash_info *info = dev_get_drvdata(&dev->dev);
+-      if (request_mem_region(FLASH_BASE, FLASH_SIZE, "flash") == NULL)
+-              goto out;
++      dev_set_drvdata(&dev->dev, NULL);
+-      base = ioremap(FLASH_BASE, FLASH_SIZE);
+-      err = -ENOMEM;
+-      if (base == NULL)
+-              goto release;
++      if (info) {
++              if (info->mtd) {
++                      del_mtd_partitions(info->mtd);
++                      map_destroy(info->mtd);
++              }
++              if (info->parts)
++                      kfree(info->parts);
+-      err = armflash_cfi_init(base, FLASH_SIZE);
+-      if (err) {
+-              iounmap(base);
+-release:
+-              release_mem_region(FLASH_BASE, FLASH_SIZE);
++              iounmap((void *)info->map.virt);
++              release_resource(info->res);
++              kfree(info->res);
++
++              if (info->plat && info->plat->exit)
++                      info->plat->exit();
++
++              kfree(info);
+       }
+-out:
+-      return err;
++
++      return 0;
++}
++
++static struct device_driver armflash_driver = {
++      .name           = "armflash",
++      .bus            = &platform_bus_type,
++      .probe          = armflash_probe,
++      .remove         = armflash_remove,
++};
++
++static int __init armflash_init(void)
++{
++      return driver_register(&armflash_driver);
+ }
+ static void __exit armflash_exit(void)
+ {
+-      armflash_cfi_exit();
+-      iounmap((void *)armflash_map.virt);
+-      release_mem_region(FLASH_BASE, FLASH_SIZE);
+-      armflash_flash_exit();
++      driver_unregister(&armflash_driver);
+ }
+ module_init(armflash_init);
+--- linux-2.6.0-test6/drivers/mtd/maps/sun_uflash.c    2003-06-14 12:18:25.000000000 -0700
++++ 25/drivers/mtd/maps/sun_uflash.c   2003-10-05 00:33:24.000000000 -0700
+@@ -12,7 +12,6 @@
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+-#include <linux/version.h>
+ #include <linux/fs.h>
+ #include <linux/errno.h>
+ #include <linux/init.h>
+--- linux-2.6.0-test6/drivers/mtd/mtd_blkdevs.c        2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/mtd/mtd_blkdevs.c       2003-10-05 00:34:01.000000000 -0700
+@@ -141,14 +141,12 @@ static void mtd_blktrans_request(struct 
+ }
+-int blktrans_open(struct inode *i, struct file *f)
++static int blktrans_open(struct block_device *bdev, struct file *f)
+ {
+-      struct mtd_blktrans_dev *dev;
+-      struct mtd_blktrans_ops *tr;
++      struct mtd_blktrans_dev *dev = bdev->bd_disk->private_data;
++      struct mtd_blktrans_ops *tr = dev->tr;
+       int ret = -ENODEV;
+-      dev = i->i_bdev->bd_disk->private_data;
+-      tr = dev->tr;
+       if (!try_module_get(dev->mtd->owner))
+               goto out;
+@@ -172,15 +170,12 @@ int blktrans_open(struct inode *i, struc
+       return ret;
+ }
+-int blktrans_release(struct inode *i, struct file *f)
++static int blktrans_release(struct gendisk *disk)
+ {
+-      struct mtd_blktrans_dev *dev;
+-      struct mtd_blktrans_ops *tr;
++      struct mtd_blktrans_dev *dev = disk->private_data;
++      struct mtd_blktrans_ops *tr = dev->tr;
+       int ret = 0;
+-      dev = i->i_bdev->bd_disk->private_data;
+-      tr = dev->tr;
+-
+       if (tr->release)
+               ret = tr->release(dev);
+@@ -194,10 +189,10 @@ int blktrans_release(struct inode *i, st
+ }
+-static int blktrans_ioctl(struct inode *inode, struct file *file, 
++static int blktrans_ioctl(struct block_device *bdev, struct file *file, 
+                             unsigned int cmd, unsigned long arg)
+ {
+-      struct mtd_blktrans_dev *dev = inode->i_bdev->bd_disk->private_data;
++      struct mtd_blktrans_dev *dev = bdev->bd_disk->private_data;
+       struct mtd_blktrans_ops *tr = dev->tr;
+       switch (cmd) {
+@@ -217,7 +212,7 @@ static int blktrans_ioctl(struct inode *
+                       if (ret)
+                               return ret;
+-                      g.start = get_start_sect(inode->i_bdev);
++                      g.start = get_start_sect(bdev);
+                       if (copy_to_user((void *)arg, &g, sizeof(g)))
+                               return -EFAULT;
+                       return 0;
+--- linux-2.6.0-test6/drivers/mtd/mtdcore.c    2003-06-14 12:18:20.000000000 -0700
++++ 25/drivers/mtd/mtdcore.c   2003-10-05 00:33:24.000000000 -0700
+@@ -6,6 +6,7 @@
+  *
+  */
++#include <linux/version.h>
+ #include <linux/config.h>
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+--- linux-2.6.0-test6/drivers/mtd/nand/autcpu12.c      2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/mtd/nand/autcpu12.c     2003-10-05 00:33:24.000000000 -0700
+@@ -27,6 +27,7 @@
+  *    10-06-2002 TG   128K card support added
+  */
++#include <linux/version.h>
+ #include <linux/slab.h>
+ #include <linux/init.h>
+ #include <linux/module.h>
+--- linux-2.6.0-test6/drivers/net/3c523.c      2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/net/3c523.c     2003-10-05 00:33:24.000000000 -0700
+@@ -102,7 +102,7 @@
+ #include <linux/slab.h>
+ #include <linux/interrupt.h>
+ #include <linux/delay.h>
+-#include <linux/mca.h>
++#include <linux/mca-legacy.h>
+ #include <linux/ethtool.h>
+ #include <asm/uaccess.h>
+--- linux-2.6.0-test6/drivers/net/3c527.c      2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/net/3c527.c     2003-10-05 00:33:24.000000000 -0700
+@@ -92,7 +92,7 @@ DRV_NAME ".c:v" DRV_VERSION " " DRV_RELD
+ #include <linux/types.h>
+ #include <linux/fcntl.h>
+ #include <linux/interrupt.h>
+-#include <linux/mca.h>
++#include <linux/mca-legacy.h>
+ #include <linux/ioport.h>
+ #include <linux/in.h>
+ #include <linux/skbuff.h>
+--- linux-2.6.0-test6/drivers/net/3c59x.c      2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/net/3c59x.c     2003-10-05 00:33:46.000000000 -0700
+@@ -1063,6 +1063,22 @@ static int __devinit vortex_init_one (st
+       return rc;
+ }
++#ifdef CONFIG_NET_POLL_CONTROLLER
++static void vortex_rx_poll(struct net_device *dev)
++{
++      disable_irq(dev->irq);
++      vortex_interrupt(dev->irq, (void *)dev, 0);
++      enable_irq(dev->irq);
++}
++
++static void boomerang_rx_poll(struct net_device *dev)
++{
++      disable_irq(dev->irq);
++      boomerang_interrupt(dev->irq, (void *)dev, 0);
++      enable_irq(dev->irq);
++}
++#endif
++
+ /*
+  * Start up the PCI/EISA device which is described by *gendev.
+  * Return 0 on success.
+@@ -1450,6 +1466,13 @@ static int __devinit vortex_probe1(struc
+       dev->set_multicast_list = set_rx_mode;
+       dev->tx_timeout = vortex_tx_timeout;
+       dev->watchdog_timeo = (watchdog * HZ) / 1000;
++#ifdef CONFIG_NET_POLL_CONTROLLER
++      if (vp->full_bus_master_tx)
++              dev->poll_controller = boomerang_rx_poll;
++      else
++              dev->poll_controller = vortex_rx_poll;
++#endif
++
+       if (pdev) {
+               vp->pm_state_valid = 1;
+               pci_save_state(VORTEX_PCI(vp), vp->power_state);
+--- linux-2.6.0-test6/drivers/net/8139too.c    2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/net/8139too.c   2003-10-05 00:34:34.000000000 -0700
+@@ -248,6 +248,7 @@ static struct pci_device_id rtl8139_pci_
+       {0x14ea, 0xab06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+       {0x14ea, 0xab07, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+       {0x11db, 0x1234, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
++      {0x1432, 0x9130, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ #ifdef CONFIG_SH_SECUREEDGE5410
+       /* Bogus 8139 silicon reports 8129 without external PROM :-( */
+--- linux-2.6.0-test6/drivers/net/arcnet/com20020.c    2003-08-22 19:23:41.000000000 -0700
++++ 25/drivers/net/arcnet/com20020.c   2003-10-05 00:33:24.000000000 -0700
+@@ -180,10 +180,6 @@ int com20020_found(struct net_device *de
+       if (!dev->dev_addr[0])
+               dev->dev_addr[0] = inb(ioaddr + 8);     /* FIXME: do this some other way! */
+-      /* reserve the I/O region */
+-      if (!request_region(ioaddr, ARCNET_TOTAL_SIZE, "arcnet (COM20020)"))
+-              return -EBUSY;
+-
+       SET_SUBADR(SUB_SETUP1);
+       outb(lp->setup, _XREG);
+@@ -207,7 +203,6 @@ int com20020_found(struct net_device *de
+       if (request_irq(dev->irq, &arcnet_interrupt, shared,
+                       "arcnet (COM20020)", dev)) {
+               BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", dev->irq);
+-              release_region(ioaddr, ARCNET_TOTAL_SIZE);
+               return -ENODEV;
+       }
+@@ -227,7 +222,6 @@ int com20020_found(struct net_device *de
+              clockrates[3 - ((lp->setup2 & 0xF0) >> 4) + ((lp->setup & 0x0F) >> 1)]);
+       if (!dev->init && register_netdev(dev)) {
+-              release_region(ioaddr, ARCNET_TOTAL_SIZE);
+               free_irq(dev->irq, dev);
+               return -EIO;
+       }
+@@ -342,7 +336,6 @@ void com20020_remove(struct net_device *
+ {
+       unregister_netdev(dev);
+       free_irq(dev->irq, dev);
+-      release_region(dev->base_addr, ARCNET_TOTAL_SIZE);
+       kfree(dev->priv);
+       free_netdev(dev);
+ }
+--- linux-2.6.0-test6/drivers/net/arcnet/com20020-isa.c        2003-08-08 22:55:12.000000000 -0700
++++ 25/drivers/net/arcnet/com20020-isa.c       2003-10-05 00:33:24.000000000 -0700
+@@ -53,6 +53,7 @@ static int __init com20020isa_probe(stru
+       int ioaddr;
+       unsigned long airqmask;
+       struct arcnet_local *lp = dev->priv;
++      int err;
+       BUGLVL(D_NORMAL) printk(VERSION);
+@@ -62,17 +63,20 @@ static int __init com20020isa_probe(stru
+                      "must specify the base address!\n");
+               return -ENODEV;
+       }
+-      if (check_region(ioaddr, ARCNET_TOTAL_SIZE)) {
++      if (!request_region(ioaddr, ARCNET_TOTAL_SIZE, "arcnet (COM20020)")) {
+               BUGMSG(D_NORMAL, "IO region %xh-%xh already allocated.\n",
+                      ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1);
+               return -ENXIO;
+       }
+       if (ASTATUS() == 0xFF) {
+               BUGMSG(D_NORMAL, "IO address %x empty\n", ioaddr);
+-              return -ENODEV;
++              err = -ENODEV;
++              goto out;
++      }
++      if (com20020_check(dev)) {
++              err = -ENODEV;
++              goto out;
+       }
+-      if (com20020_check(dev))
+-              return -ENODEV;
+       if (!dev->irq) {
+               /* if we do this, we're sure to get an IRQ since the
+@@ -96,13 +100,21 @@ static int __init com20020isa_probe(stru
+                       dev->irq = probe_irq_off(airqmask);
+                       if (dev->irq <= 0) {
+                               BUGMSG(D_NORMAL, "Autoprobe IRQ failed.\n");
+-                              return -ENODEV;
++                              err = -ENODEV;
++                              goto out;
+                       }
+               }
+       }
+       lp->card_name = "ISA COM20020";
+-      return com20020_found(dev, 0);
++      if ((err = com20020_found(dev, 0)) != 0)
++              goto out;
++
++      return 0;
++
++out:
++      release_region(ioaddr, ARCNET_TOTAL_SIZE);
++      return err;
+ }
+@@ -170,6 +182,7 @@ int init_module(void)
+ void cleanup_module(void)
+ {
+       com20020_remove(my_dev);
++      release_region(my_dev->base_addr, ARCNET_TOTAL_SIZE);
+ }
+ #else
+--- linux-2.6.0-test6/drivers/net/arcnet/com20020-pci.c        2003-08-22 19:23:41.000000000 -0700
++++ 25/drivers/net/arcnet/com20020-pci.c       2003-10-05 00:33:24.000000000 -0700
+@@ -115,20 +115,20 @@ static int __devinit com20020pci_probe(s
+               BUGMSG(D_NORMAL, "IO address %Xh was reported by PCI BIOS, "
+                      "but seems empty!\n", ioaddr);
+               err = -EIO;
+-              goto out_priv;
++              goto out_port;
+       }
+       if (com20020_check(dev)) {
+               err = -EIO;
+-              goto out_priv;
++              goto out_port;
+       }
+-      release_region(ioaddr, ARCNET_TOTAL_SIZE);
+-
+       if ((err = com20020_found(dev, SA_SHIRQ)) != 0)
+-              goto out_priv;
++              goto out_port;
+       return 0;
++out_port:
++      release_region(ioaddr, ARCNET_TOTAL_SIZE);
+ out_priv:
+       kfree(dev->priv);
+ out_dev:
+@@ -138,7 +138,9 @@ out_dev:
+ static void __devexit com20020pci_remove(struct pci_dev *pdev)
+ {
+-      com20020_remove(pci_get_drvdata(pdev));
++      struct net_device *dev = pci_get_drvdata(pdev);
++      com20020_remove(dev);
++      release_region(dev->base_addr, ARCNET_TOTAL_SIZE);
+ }
+ static struct pci_device_id com20020pci_id_table[] = {
+--- linux-2.6.0-test6/drivers/net/at1700.c     2003-06-14 12:18:07.000000000 -0700
++++ 25/drivers/net/at1700.c    2003-10-05 00:33:24.000000000 -0700
+@@ -43,7 +43,7 @@
+ #include <linux/errno.h>
+ #include <linux/netdevice.h>
+ #include <linux/etherdevice.h>
+-#include <linux/mca.h>
++#include <linux/mca-legacy.h>
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+ #include <linux/types.h>
+--- linux-2.6.0-test6/drivers/net/e100/e100_main.c     2003-09-27 18:57:45.000000000 -0700
++++ 25/drivers/net/e100/e100_main.c    2003-10-05 00:33:46.000000000 -0700
+@@ -539,6 +539,15 @@ e100_trigger_SWI(struct e100_private *bd
+       readw(&(bdp->scb->scb_status)); /* flushes last write, read-safe */
+ }
++#ifdef CONFIG_NET_POLL_CONTROLLER
++static void e100_rx_poll(struct net_device *dev)
++{
++      disable_irq(dev->irq);
++      e100intr(dev->irq, (void *)dev, 0);
++      enable_irq(dev->irq);
++}
++#endif
++
+ static int __devinit
+ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
+ {
+@@ -631,7 +640,9 @@ e100_found1(struct pci_dev *pcid, const 
+       dev->set_multicast_list = &e100_set_multi;
+       dev->set_mac_address = &e100_set_mac;
+       dev->do_ioctl = &e100_ioctl;
+-
++#ifdef CONFIG_NET_POLL_CONTROLLER
++      dev->poll_controller = e100_rx_poll;
++#endif
+       if (bdp->flags & USE_IPCB)
+       dev->features = NETIF_F_SG | NETIF_F_IP_CSUM |
+                       NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+--- linux-2.6.0-test6/drivers/net/eepro100.c   2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/net/eepro100.c  2003-10-05 00:33:47.000000000 -0700
+@@ -543,6 +543,7 @@ static void speedo_refill_rx_buffers(str
+ static int speedo_rx(struct net_device *dev);
+ static void speedo_tx_buffer_gc(struct net_device *dev);
+ static irqreturn_t speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
++static void poll_speedo (struct net_device *dev);
+ static int speedo_close(struct net_device *dev);
+ static struct net_device_stats *speedo_get_stats(struct net_device *dev);
+ static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+@@ -885,6 +886,9 @@ static int __devinit speedo_found1(struc
+       dev->get_stats = &speedo_get_stats;
+       dev->set_multicast_list = &set_rx_mode;
+       dev->do_ioctl = &speedo_ioctl;
++#ifdef CONFIG_NET_POLL_CONTROLLER
++      dev->poll_controller = &poll_speedo;
++#endif
+       if (register_netdevice(dev))
+               goto err_free_unlock;
+@@ -1675,6 +1679,22 @@ static irqreturn_t speedo_interrupt(int 
+       return IRQ_RETVAL(handled);
+ }
++#ifdef CONFIG_NET_POLL_CONTROLLER
++
++/*
++ * Polling 'interrupt' - used by things like netconsole to send skbs
++ * without having to re-enable interrupts. It's not called while
++ * the interrupt routine is executing.
++ */
++
++static void poll_speedo (struct net_device *dev)
++{
++      disable_irq(dev->irq);
++      speedo_interrupt (dev->irq, dev, NULL);
++      enable_irq(dev->irq);
++}
++#endif
++
+ static inline struct RxFD *speedo_rx_alloc(struct net_device *dev, int entry)
+ {
+       struct speedo_private *sp = (struct speedo_private *)dev->priv;
+--- linux-2.6.0-test6/drivers/net/eexpress.c   2003-08-22 19:23:41.000000000 -0700
++++ 25/drivers/net/eexpress.c  2003-10-05 00:33:24.000000000 -0700
+@@ -113,7 +113,6 @@
+ #include <linux/etherdevice.h>
+ #include <linux/skbuff.h>
+ #include <linux/slab.h>
+-#include <linux/mca.h>
+ #include <linux/mca-legacy.h>
+ #include <linux/spinlock.h>
+--- linux-2.6.0-test6/drivers/net/ibmlana.c    2003-09-27 18:57:45.000000000 -0700
++++ 25/drivers/net/ibmlana.c   2003-10-05 00:33:24.000000000 -0700
+@@ -82,7 +82,7 @@ History:
+ #include <linux/interrupt.h>
+ #include <linux/delay.h>
+ #include <linux/time.h>
+-#include <linux/mca.h>
++#include <linux/mca-legacy.h>
+ #include <linux/module.h>
+ #include <linux/netdevice.h>
+ #include <linux/etherdevice.h>
+--- linux-2.6.0-test6/drivers/net/irda/act200l.c       2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/net/irda/act200l.c      2003-10-05 00:33:24.000000000 -0700
+@@ -84,12 +84,12 @@ static int  act200l_change_speed(struct 
+ #define ACT200L_OSCL    0x04 /* oscillator in low power, medium accuracy mode */
+ static struct dongle_reg dongle = {
+-      Q_NULL,
+-      IRDA_ACT200L_DONGLE,
+-      act200l_open,
+-      act200l_close,
+-      act200l_reset,
+-      act200l_change_speed,
++      .type = IRDA_ACT200L_DONGLE,
++      .open = act200l_open,
++      .close = act200l_close,
++      .reset = act200l_reset,
++      .change_speed = act200l_change_speed,
++      .owner = THIS_MODULE,
+ };
+ int __init act200l_init(void)
+@@ -112,8 +112,6 @@ static void act200l_open(dongle_t *self,
+       /* Set the speeds we can accept */
+       qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
+       qos->min_turn_time.bits = 0x03;
+-
+-      MOD_INC_USE_COUNT;
+ }
+ static void act200l_close(dongle_t *self)
+@@ -122,8 +120,6 @@ static void act200l_close(dongle_t *self
+       /* Power off the dongle */
+       self->set_dtr_rts(self->dev, FALSE, FALSE);
+-
+-      MOD_DEC_USE_COUNT;
+ }
+ /*
+--- linux-2.6.0-test6/drivers/net/irda/actisys.c       2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/net/irda/actisys.c      2003-10-05 00:33:24.000000000 -0700
+@@ -64,21 +64,21 @@ static __u32 baud_rates[] = { 9600, 1920
+ #define MAX_SPEEDS 5
+ static struct dongle_reg dongle = {
+-      Q_NULL,
+-      IRDA_ACTISYS_DONGLE,
+-      actisys_open,
+-      actisys_close,
+-      actisys_reset,
+-      actisys_change_speed,
++      .type = IRDA_ACTISYS_DONGLE,
++      .open = actisys_open,
++      .close = actisys_close,
++      .reset = actisys_reset,
++      .change_speed = actisys_change_speed,
++      .owner = THIS_MODULE,
+ };
+ static struct dongle_reg dongle_plus = {
+-      Q_NULL,
+-      IRDA_ACTISYS_PLUS_DONGLE,
+-      actisys_open,
+-      actisys_close,
+-      actisys_reset,
+-      actisys_change_speed,
++      .type = IRDA_ACTISYS_PLUS_DONGLE,
++      .open = actisys_open,
++      .close = actisys_close,
++      .reset = actisys_reset,
++      .change_speed = actisys_change_speed,
++      .owner = THIS_MODULE,
+ };
+ /*
+@@ -128,16 +128,12 @@ static void actisys_open(dongle_t *self,
+               qos->baud_rate.bits &= ~IR_38400;
+       
+       qos->min_turn_time.bits = 0x7f; /* Needs 0.01 ms */
+-
+-      MOD_INC_USE_COUNT;
+ }
+ static void actisys_close(dongle_t *self)
+ {
+       /* Power off the dongle */
+       self->set_dtr_rts(self->dev, FALSE, FALSE);
+-
+-      MOD_DEC_USE_COUNT;
+ }
+ /*
+--- linux-2.6.0-test6/drivers/net/irda/ali-ircc.c      2003-09-27 18:57:45.000000000 -0700
++++ 25/drivers/net/irda/ali-ircc.c     2003-10-05 00:33:24.000000000 -0700
+@@ -254,7 +254,7 @@ static int ali_ircc_open(int i, chipio_t
+       if ((ali_ircc_setup(info)) == -1)
+               return -1;
+               
+-      dev = alloc_netdev(sizeof(*self), "irda%d", irda_device_setup);
++      dev = alloc_irdadev(sizeof(*self));
+       if (dev == NULL) {
+               ERROR("%s(), can't allocate memory for control block!\n", __FUNCTION__);
+               return -ENOMEM;
+--- linux-2.6.0-test6/drivers/net/irda/donauboe.c      2003-09-27 18:57:45.000000000 -0700
++++ 25/drivers/net/irda/donauboe.c     2003-10-05 00:33:24.000000000 -0700
+@@ -1598,8 +1598,7 @@ toshoboe_open (struct pci_dev *pci_dev, 
+   if ((err=pci_enable_device(pci_dev)))
+     return err;
+-  dev = alloc_netdev(sizeof (struct toshoboe_cb), "irda%d",
+-                   irda_device_setup);
++  dev = alloc_irdadev(sizeof (struct toshoboe_cb));
+   if (dev == NULL)
+     {
+       printk (KERN_ERR DRIVER_NAME ": can't allocate memory for "
+--- linux-2.6.0-test6/drivers/net/irda/ep7211_ir.c     2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/net/irda/ep7211_ir.c    2003-10-05 00:33:24.000000000 -0700
+@@ -24,12 +24,12 @@ static int  ep7211_ir_change_speed(struc
+ static int  ep7211_ir_reset(struct irda_task *task);
+ static struct dongle_reg dongle = {
+-      Q_NULL,
+-      IRDA_EP7211_IR,
+-      ep7211_ir_open,
+-      ep7211_ir_close,
+-      ep7211_ir_reset,
+-      ep7211_ir_change_speed,
++      .type = IRDA_EP7211_IR,
++      .open = ep7211_ir_open,
++      .close = ep7211_ir_close,
++      .reset = ep7211_ir_reset,
++      .change_speed = ep7211_ir_change_speed,
++      .owner = THIS_MODULE,
+ };
+ static void ep7211_ir_open(dongle_t *self, struct qos_info *qos)
+@@ -47,8 +47,6 @@ static void ep7211_ir_open(dongle_t *sel
+               UART (interrupt #14). */
+       restore_flags(flags);
+-
+-      MOD_INC_USE_COUNT;
+ }
+ static void ep7211_ir_close(dongle_t *self)
+@@ -66,8 +64,6 @@ static void ep7211_ir_close(dongle_t *se
+               reset them back to their original state. */
+       restore_flags(flags);
+-
+-      MOD_DEC_USE_COUNT;
+ }
+ /*
+--- linux-2.6.0-test6/drivers/net/irda/esi.c   2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/net/irda/esi.c  2003-10-05 00:33:24.000000000 -0700
+@@ -44,12 +44,12 @@ static int  esi_change_speed(struct irda
+ static int  esi_reset(struct irda_task *task);
+ static struct dongle_reg dongle = {
+-      Q_NULL,
+-      IRDA_ESI_DONGLE,
+-      esi_open,
+-      esi_close,
+-      esi_reset,
+-      esi_change_speed,
++      .type = IRDA_ESI_DONGLE,
++      .open = esi_open,
++      .close = esi_close,
++      .reset = esi_reset,
++      .change_speed = esi_change_speed,
++      .owner = THIS_MODULE,
+ };
+ int __init esi_init(void)
+@@ -66,16 +66,12 @@ static void esi_open(dongle_t *self, str
+ {
+       qos->baud_rate.bits &= IR_9600|IR_19200|IR_115200;
+       qos->min_turn_time.bits = 0x01; /* Needs at least 10 ms */
+-
+-      MOD_INC_USE_COUNT;
+ }
+ static void esi_close(dongle_t *dongle)
+ {             
+       /* Power off dongle */
+       dongle->set_dtr_rts(dongle->dev, FALSE, FALSE);
+-
+-      MOD_DEC_USE_COUNT;
+ }
+ /*
+--- linux-2.6.0-test6/drivers/net/irda/girbil.c        2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/net/irda/girbil.c       2003-10-05 00:33:24.000000000 -0700
+@@ -63,12 +63,12 @@ static int  girbil_change_speed(struct i
+ #define GIRBIL_LOAD    0x51 /* Load the new baud rate value */
+ static struct dongle_reg dongle = {
+-      Q_NULL,
+-      IRDA_GIRBIL_DONGLE,
+-      girbil_open,
+-      girbil_close,
+-      girbil_reset,
+-      girbil_change_speed,
++      .type = IRDA_GIRBIL_DONGLE,
++      .open = girbil_open,
++      .close = girbil_close,
++      .reset = girbil_reset,
++      .change_speed = girbil_change_speed,
++      .owner = THIS_MODULE,
+ };
+ int __init girbil_init(void)
+@@ -85,16 +85,12 @@ static void girbil_open(dongle_t *self, 
+ {
+       qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
+       qos->min_turn_time.bits = 0x03;
+-
+-      MOD_INC_USE_COUNT;
+ }
+ static void girbil_close(dongle_t *self)
+ {
+       /* Power off dongle */
+       self->set_dtr_rts(self->dev, FALSE, FALSE);
+-
+-      MOD_DEC_USE_COUNT;
+ }
+ /*
+--- linux-2.6.0-test6/drivers/net/irda/irda-usb.c      2003-09-27 18:57:45.000000000 -0700
++++ 25/drivers/net/irda/irda-usb.c     2003-10-05 00:33:24.000000000 -0700
+@@ -1176,7 +1176,7 @@ static inline int irda_usb_open(struct i
+       memset(self->speed_buff, 0, IRDA_USB_SPEED_MTU);
+       /* Create a network device for us */
+-      netdev = alloc_netdev(0, "irda%d",  irda_device_setup);
++      netdev = alloc_irdadev(0);
+       if (!netdev) {
+               ERROR("%s(), alloc_net_dev() failed!\n", __FUNCTION__);
+               return -ENOMEM;
+--- linux-2.6.0-test6/drivers/net/irda/irport.c        2003-06-14 12:18:25.000000000 -0700
++++ 25/drivers/net/irda/irport.c       2003-10-05 00:33:24.000000000 -0700
+@@ -78,7 +78,6 @@ static inline void irport_write_wakeup(s
+ static inline int  irport_write(int iobase, int fifo_size, __u8 *buf, int len);
+ static inline void irport_receive(struct irport_cb *self);
+-static int  irport_net_init(struct net_device *dev);
+ static int  irport_net_ioctl(struct net_device *dev, struct ifreq *rq, 
+                            int cmd);
+ static inline int  irport_is_receiving(struct irport_cb *self);
+@@ -136,30 +135,27 @@ irport_open(int i, unsigned int iobase, 
+ {
+       struct net_device *dev;
+       struct irport_cb *self;
+-      void *ret;
+-      int err;
+       IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
+       /* Lock the port that we need */
+-      ret = request_region(iobase, IO_EXTENT, driver_name);
+-      if (!ret) {
++      if (!request_region(iobase, IO_EXTENT, driver_name)) {
+               IRDA_DEBUG(0, "%s(), can't get iobase of 0x%03x\n",
+                          __FUNCTION__, iobase);
+-              return NULL;
++              goto err_out1;
+       }
+       /*
+        *  Allocate new instance of the driver
+        */
+-      self = kmalloc(sizeof(struct irport_cb), GFP_KERNEL);
+-      if (!self) {
++      dev = alloc_irdadev(sizeof(struct irport_cb));
++      if (!dev) {
+               ERROR("%s(), can't allocate memory for "
+-                    "control block!\n", __FUNCTION__);
+-              release_region(iobase, IO_EXTENT);
+-              return NULL;
++                    "irda device!\n", __FUNCTION__);
++              goto err_out2;
+       }
+-      memset(self, 0, sizeof(struct irport_cb));
++
++      self = dev->priv;
+       spin_lock_init(&self->lock);
+       /* Need to store self somewhere */
+@@ -189,8 +185,11 @@ irport_open(int i, unsigned int iobase, 
+       self->rx_buff.truesize = IRDA_SKB_MAX_MTU;
+       self->rx_buff.skb = __dev_alloc_skb(self->rx_buff.truesize,
+                                           GFP_KERNEL);
+-      if (self->rx_buff.skb == NULL)
+-              return NULL;
++      if (self->rx_buff.skb == NULL) {
++              ERROR("%s(), can't allocate memory for "
++                    "receive buffer!\n", __FUNCTION__);
++              goto err_out3;
++      }
+       skb_reserve(self->rx_buff.skb, 1);
+       self->rx_buff.head = self->rx_buff.skb->data;
+       /* No need to memset the buffer, unless you are really pedantic */
+@@ -208,30 +207,23 @@ irport_open(int i, unsigned int iobase, 
+               self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize, 
+                                                     GFP_KERNEL);
+               if (self->tx_buff.head == NULL) {
+-                      kfree_skb(self->rx_buff.skb);
+-                      self->rx_buff.skb = NULL;
+-                      self->rx_buff.head = NULL;
+-                      return NULL;
++                      ERROR("%s(), can't allocate memory for "
++                            "transmit buffer!\n", __FUNCTION__);
++                      goto err_out4;
+               }
+               memset(self->tx_buff.head, 0, self->tx_buff.truesize);
+       }       
+       self->tx_buff.data = self->tx_buff.head;
+-      if (!(dev = dev_alloc("irda%d", &err))) {
+-              ERROR("%s(), dev_alloc() failed!\n", __FUNCTION__);
+-              return NULL;
+-      }
+       self->netdev = dev;
+       /* Keep track of module usage */
+       SET_MODULE_OWNER(dev);
+       /* May be overridden by piggyback drivers */
+-      dev->priv = (void *) self;
+       self->interrupt    = irport_interrupt;
+       self->change_speed = irport_change_speed;
+       /* Override the network functions we need to use */
+-      dev->init            = irport_net_init;
+       dev->hard_start_xmit = irport_hard_xmit;
+       dev->tx_timeout      = irport_timeout;
+       dev->watchdog_timeo  = HZ;  /* Allow time enough for speed change */
+@@ -244,17 +236,25 @@ irport_open(int i, unsigned int iobase, 
+       dev->base_addr = iobase;
+       dev->irq = irq;
+-      rtnl_lock();
+-      err = register_netdevice(dev);
+-      rtnl_unlock();
+-      if (err) {
++      if (register_netdev(dev)) {
+               ERROR("%s(), register_netdev() failed!\n", __FUNCTION__);
+-              return NULL;
++              goto err_out5;
+       }
+       MESSAGE("IrDA: Registered device %s (irport io=0x%X irq=%d)\n",
+               dev->name, iobase, irq);
+       return self;
++ err_out5:
++      kfree(self->tx_buff.head);
++ err_out4:
++      kfree_skb(self->rx_buff.skb);
++ err_out3:
++      free_netdev(dev);
++      dev_self[i] = NULL;
++ err_out2:
++      release_region(iobase, IO_EXTENT);
++ err_out1:
++      return NULL;
+ }
+ int irport_close(struct irport_cb *self)
+@@ -267,8 +267,7 @@ int irport_close(struct irport_cb *self)
+       self->dongle = NULL;
+       
+       /* Remove netdevice */
+-      if (self->netdev)
+-              unregister_netdev(self->netdev);
++      unregister_netdev(self->netdev);
+       /* Release the IO-port that this driver is using */
+       IRDA_DEBUG(0 , "%s(), Releasing Region %03x\n", 
+@@ -284,7 +283,7 @@ int irport_close(struct irport_cb *self)
+       
+       /* Remove ourselves */
+       dev_self[self->index] = NULL;
+-      kfree(self);
++      free_netdev(self->netdev);
+       
+       return 0;
+ }
+@@ -886,16 +885,6 @@ irqreturn_t irport_interrupt(int irq, vo
+       return IRQ_RETVAL(handled);
+ }
+-static int irport_net_init(struct net_device *dev)
+-{
+-      /* Set up to be a normal IrDA network device driver */
+-      irda_device_setup(dev);
+-
+-      /* Insert overrides below this line! */
+-
+-      return 0;
+-}
+-
+ /*
+  * Function irport_net_open (dev)
+  *
+--- linux-2.6.0-test6/drivers/net/irda/litelink.c      2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/net/irda/litelink.c     2003-10-05 00:33:24.000000000 -0700
+@@ -48,12 +48,12 @@ static int  litelink_reset(struct irda_t
+ static __u32 baud_rates[] = { 115200, 57600, 38400, 19200, 9600 };
+ static struct dongle_reg dongle = {
+-      Q_NULL,
+-      IRDA_LITELINK_DONGLE,
+-      litelink_open,
+-      litelink_close,
+-      litelink_reset,
+-      litelink_change_speed,
++      .type = IRDA_LITELINK_DONGLE,
++      .open = litelink_open,
++      .close = litelink_close,
++      .reset = litelink_reset,
++      .change_speed = litelink_change_speed,
++      .owner = THIS_MODULE,
+ };
+ int __init litelink_init(void)
+@@ -70,16 +70,12 @@ static void litelink_open(dongle_t *self
+ {
+       qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
+       qos->min_turn_time.bits = 0x7f; /* Needs 0.01 ms */
+-
+-      MOD_INC_USE_COUNT;
+ }
+ static void litelink_close(dongle_t *self)
+ {
+       /* Power off dongle */
+       self->set_dtr_rts(self->dev, FALSE, FALSE);
+-
+-      MOD_DEC_USE_COUNT;
+ }
+ /*
+--- linux-2.6.0-test6/drivers/net/irda/ma600.c 2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/net/irda/ma600.c        2003-10-05 00:33:24.000000000 -0700
+@@ -74,12 +74,12 @@ static int  ma600_reset(struct irda_task
+ #define MA600_2400    0x08
+ static struct dongle_reg dongle = {
+-      Q_NULL,
+-      IRDA_MA600_DONGLE,
+-      ma600_open,
+-      ma600_close,
+-      ma600_reset,
+-      ma600_change_speed,
++      .type = IRDA_MA600_DONGLE,
++      .open = ma600_open,
++      .close = ma600_close,
++      .reset = ma600_reset,
++      .change_speed = ma600_change_speed,
++      .owner = THIS_MODULE,
+ };
+ int __init ma600_init(void)
+@@ -115,8 +115,6 @@ static void ma600_open(dongle_t *self, s
+       self->set_dtr_rts(self->dev, TRUE, TRUE);
+       // should wait 1 second
+-
+-      MOD_INC_USE_COUNT;
+ }
+ static void ma600_close(dongle_t *self)
+@@ -125,8 +123,6 @@ static void ma600_close(dongle_t *self)
+       /* Power off dongle */
+       self->set_dtr_rts(self->dev, FALSE, FALSE);
+-
+-      MOD_DEC_USE_COUNT;
+ }
+ static __u8 get_control_byte(__u32 speed)
+--- linux-2.6.0-test6/drivers/net/irda/mcp2120.c       2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/net/irda/mcp2120.c      2003-10-05 00:33:24.000000000 -0700
+@@ -40,12 +40,12 @@ static int  mcp2120_change_speed(struct 
+ #define MCP2120_COMMIT  0x11
+ static struct dongle_reg dongle = {
+-      Q_NULL,
+-      IRDA_MCP2120_DONGLE,
+-      mcp2120_open,
+-      mcp2120_close,
+-      mcp2120_reset,
+-      mcp2120_change_speed,
++      .type = IRDA_MCP2120_DONGLE,
++      .open = mcp2120_open,
++      .close = mcp2120_close,
++      .reset = mcp2120_reset,
++      .change_speed = mcp2120_change_speed,
++      .owner = THIS_MODULE,
+ };
+ int __init mcp2120_init(void)
+@@ -62,8 +62,6 @@ static void mcp2120_open(dongle_t *self,
+ {
+       qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
+       qos->min_turn_time.bits = 0x01;
+-
+-      MOD_INC_USE_COUNT;
+ }
+ static void mcp2120_close(dongle_t *self)
+@@ -72,8 +70,6 @@ static void mcp2120_close(dongle_t *self
+         /* reset and inhibit mcp2120 */
+       self->set_dtr_rts(self->dev, TRUE, TRUE);
+       //self->set_dtr_rts(self->dev, FALSE, FALSE);
+-
+-      MOD_DEC_USE_COUNT;
+ }
+ /*
+--- linux-2.6.0-test6/drivers/net/irda/nsc-ircc.c      2003-09-27 18:57:45.000000000 -0700
++++ 25/drivers/net/irda/nsc-ircc.c     2003-10-05 00:33:24.000000000 -0700
+@@ -260,8 +260,7 @@ static int __init nsc_ircc_open(int i, c
+       MESSAGE("%s, driver loaded (Dag Brattli)\n", driver_name);
+-      dev = alloc_netdev(sizeof(struct nsc_ircc_cb), "irda%d",
+-                         irda_device_setup);
++      dev = alloc_irdadev(sizeof(struct nsc_ircc_cb));
+       if (dev == NULL) {
+               ERROR("%s(), can't allocate memory for "
+                      "control block!\n", __FUNCTION__);
+--- linux-2.6.0-test6/drivers/net/irda/old_belkin.c    2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/net/irda/old_belkin.c   2003-10-05 00:33:24.000000000 -0700
+@@ -74,12 +74,12 @@ static int  old_belkin_reset(struct irda
+ /* static __u32 baud_rates[] = { 9600 }; */
+ static struct dongle_reg dongle = {
+-      Q_NULL,
+-      IRDA_OLD_BELKIN_DONGLE,
+-      old_belkin_open,
+-      old_belkin_close,
+-      old_belkin_reset,
+-      old_belkin_change_speed,
++      .type = IRDA_OLD_BELKIN_DONGLE,
++      .open = old_belkin_open,
++      .close = old_belkin_close,
++      .reset = old_belkin_reset,
++      .change_speed = old_belkin_change_speed,
++      .owner = THIS_MODULE,
+ };
+ int __init old_belkin_init(void)
+@@ -98,16 +98,12 @@ static void old_belkin_open(dongle_t *se
+       qos->baud_rate.bits &= IR_9600;
+       /* Needs at least 10 ms (totally wild guess, can do probably better) */
+       qos->min_turn_time.bits = 0x01;
+-
+-      MOD_INC_USE_COUNT;
+ }
+ static void old_belkin_close(dongle_t *self)
+ {
+       /* Power off dongle */
+       self->set_dtr_rts(self->dev, FALSE, FALSE);
+-
+-      MOD_DEC_USE_COUNT;
+ }
+ /*
+--- linux-2.6.0-test6/drivers/net/irda/sir_dev.c       2003-07-10 18:50:31.000000000 -0700
++++ 25/drivers/net/irda/sir_dev.c      2003-10-05 00:33:24.000000000 -0700
+@@ -538,28 +538,6 @@ out:
+ /* ----------------------------------------------------------------------------- */
+-static int sirdev_init(struct net_device *ndev)
+-{
+-      struct sir_dev *dev = ndev->priv;
+-
+-      SET_MODULE_OWNER(ndev);
+-
+-      /* Set up to be a normal IrDA network device driver */
+-      irda_device_setup(ndev);
+-
+-      dev->flags = IFF_SIR | IFF_PIO;
+-
+-      /* Override the network functions we need to use */
+-      ndev->hard_start_xmit = sirdev_hard_xmit;
+-      ndev->open = sirdev_open;
+-      ndev->stop = sirdev_close;
+-      ndev->get_stats = sirdev_get_stats;
+-      ndev->do_ioctl = sirdev_ioctl;
+-
+-      return 0;
+-}
+-
+-
+ struct sir_dev * sirdev_get_instance(const struct sir_driver *drv, const char *name)
+ {
+       struct net_device *ndev;
+@@ -577,12 +555,12 @@ struct sir_dev * sirdev_get_instance(con
+       /*
+        *  Allocate new instance of the device
+        */
+-      dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+-      if (dev == NULL) {
++      ndev = alloc_irdadev(sizeof(*dev));
++      if (ndev == NULL) {
+               ERROR("%s - Can't allocate memory for IrDA control block!\n", __FUNCTION__);
+               goto out;
+       }
+-      memset(dev, 0, sizeof(*dev));
++      dev = ndev->priv;
+       irda_init_max_qos_capabilies(&dev->qos);
+       dev->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
+@@ -591,11 +569,6 @@ struct sir_dev * sirdev_get_instance(con
+       strncpy(dev->hwname, name, sizeof(dev->hwname)-1);
+-      ndev = kmalloc(sizeof(*ndev), GFP_KERNEL);
+-      if (ndev == NULL)
+-              goto out_freedev;
+-      memset(ndev, 0, sizeof(*ndev));
+-
+       atomic_set(&dev->enable_rx, 0);
+       dev->tx_skb = NULL;
+@@ -609,10 +582,17 @@ struct sir_dev * sirdev_get_instance(con
+       dev->drv = drv;
+       dev->netdev = ndev;
+-      ndev->priv = (void *) dev;
+-      ndev->init = sirdev_init;
++      SET_MODULE_OWNER(ndev);
++
++      dev->flags = IFF_SIR | IFF_PIO;
++
++      /* Override the network functions we need to use */
++      ndev->hard_start_xmit = sirdev_hard_xmit;
++      ndev->open = sirdev_open;
++      ndev->stop = sirdev_close;
++      ndev->get_stats = sirdev_get_stats;
++      ndev->do_ioctl = sirdev_ioctl;
+-      strcpy(ndev->name, "irda%d");
+       if (register_netdev(ndev)) {
+               ERROR("%s(), register_netdev() failed!\n", __FUNCTION__);
+               goto out_freenetdev;
+@@ -621,9 +601,7 @@ struct sir_dev * sirdev_get_instance(con
+       return dev;
+ out_freenetdev:
+-      kfree(ndev);
+-out_freedev:
+-      kfree(dev);
++      free_netdev(ndev);
+ out:
+       return NULL;
+ }
+@@ -653,10 +631,9 @@ int sirdev_put_instance(struct sir_dev *
+       up(&dev->fsm.sem);
+       /* Remove netdevice */
+-      if (dev->netdev)
+-              unregister_netdev(dev->netdev);
++      unregister_netdev(dev->netdev);
+-      kfree(dev);
++      free_netdev(dev->netdev);
+       return 0;
+ }
+--- linux-2.6.0-test6/drivers/net/irda/smsc-ircc2.c    2003-06-14 12:18:24.000000000 -0700
++++ 25/drivers/net/irda/smsc-ircc2.c   2003-10-05 00:33:24.000000000 -0700
+@@ -140,10 +140,8 @@ static const char *driver_name = "smsc-i
+ static int smsc_ircc_open(unsigned int firbase, unsigned int sirbase, u8 dma, u8 irq);
+ static int smsc_ircc_present(unsigned int fir_base, unsigned int sir_base);
+-static int smsc_ircc_setup_io(struct smsc_ircc_cb *self, unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq);
+-static int smsc_ircc_setup_buffers(struct smsc_ircc_cb *self);
++static void smsc_ircc_setup_io(struct smsc_ircc_cb *self, unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq);
+ static void smsc_ircc_setup_qos(struct smsc_ircc_cb *self);
+-static int smsc_ircc_setup_netdev(struct smsc_ircc_cb *self);
+ static void smsc_ircc_init_chip(struct smsc_ircc_cb *self);
+ static int __exit smsc_ircc_close(struct smsc_ircc_cb *self);
+ static int  smsc_ircc_dma_receive(struct smsc_ircc_cb *self, int iobase); 
+@@ -163,7 +161,6 @@ static void smsc_ircc_sir_stop(struct sm
+ #endif
+ static void smsc_ircc_sir_write_wakeup(struct smsc_ircc_cb *self);
+ static int  smsc_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len);
+-static int  smsc_ircc_net_init(struct net_device *dev);
+ static int  smsc_ircc_net_open(struct net_device *dev);
+ static int  smsc_ircc_net_close(struct net_device *dev);
+ static int  smsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+@@ -366,38 +363,81 @@ int __init smsc_ircc_init(void)
+ static int __init smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq)
+ {
+       struct smsc_ircc_cb *self;
++      struct net_device *dev;
+       int err;
+       
+       IRDA_DEBUG(1, "%s\n", __FUNCTION__);
+-      err= smsc_ircc_present(fir_base, sir_base);
+-      if(err) return -ENODEV;
++      err = smsc_ircc_present(fir_base, sir_base);
++      if(err) 
++              goto err_out;
+               
+-      if (dev_count>DIM(dev_self)) {
++      err = -ENOMEM;
++      if (dev_count > DIM(dev_self)) {
+               WARNING("%s(), too many devices!\n", __FUNCTION__);
+-              return -ENOMEM;
++              goto err_out1;
+       }
+       /*
+        *  Allocate new instance of the driver
+        */
+-      self = kmalloc(sizeof(struct smsc_ircc_cb), GFP_KERNEL);
+-      if (self == NULL) {
+-              ERROR("%s, Can't allocate memory for control block!\n",
+-                      driver_name);
+-              return -ENOMEM;
++      dev = alloc_irdadev(sizeof(struct smsc_ircc_cb));
++      if (!dev) {
++              WARNING("%s() can't allocate net device\n", __FUNCTION__);
++              goto err_out1;
+       }
+-      memset(self, 0, sizeof(struct smsc_ircc_cb));
++
++      SET_MODULE_OWNER(dev);
++
++      dev->hard_start_xmit = smsc_ircc_hard_xmit_sir;
++#if SMSC_IRCC2_C_NET_TIMEOUT
++      dev->tx_timeout      = smsc_ircc_timeout;
++      dev->watchdog_timeo  = HZ*2;  /* Allow enough time for speed change */
++#endif
++      dev->open            = smsc_ircc_net_open;
++      dev->stop            = smsc_ircc_net_close;
++      dev->do_ioctl        = smsc_ircc_net_ioctl;
++      dev->get_stats       = smsc_ircc_net_get_stats;
++      
++      self = dev->priv;
++      self->netdev = dev;
++
++      /* Make ifconfig display some details */
++      dev->base_addr = self->io.fir_base = fir_base;
++      dev->irq = self->io.irq = irq;
+       /* Need to store self somewhere */
+       dev_self[dev_count++] = self;
+       spin_lock_init(&self->lock);
+-      err = smsc_ircc_setup_buffers(self);
+-      if(err) return err;
++      self->rx_buff.truesize = SMSC_IRCC2_RX_BUFF_TRUESIZE; 
++      self->tx_buff.truesize = SMSC_IRCC2_TX_BUFF_TRUESIZE;
++
++      self->rx_buff.head = (u8 *) kmalloc(self->rx_buff.truesize,
++                                            GFP_KERNEL|GFP_DMA);
++      if (self->rx_buff.head == NULL) {
++              ERROR("%s, Can't allocate memory for receive buffer!\n",
++                      driver_name);
++              goto err_out2;
++      }
++
++      self->tx_buff.head = (u8 *) kmalloc(self->tx_buff.truesize, 
++                                            GFP_KERNEL|GFP_DMA);
++      if (self->tx_buff.head == NULL) {
++              ERROR("%s, Can't allocate memory for transmit buffer!\n",
++                      driver_name);
++              goto err_out3;
++      }
++
++      memset(self->rx_buff.head, 0, self->rx_buff.truesize);
++      memset(self->tx_buff.head, 0, self->tx_buff.truesize);
++
++      self->rx_buff.in_frame = FALSE;
++      self->rx_buff.state = OUTSIDE_FRAME;
++      self->tx_buff.data = self->tx_buff.head;
++      self->rx_buff.data = self->rx_buff.head;
+          
+-      err= smsc_ircc_setup_io(self, fir_base, sir_base, dma, irq);
+-      if(err) return err;
++      smsc_ircc_setup_io(self, fir_base, sir_base, dma, irq);
+       smsc_ircc_setup_qos(self);
+@@ -405,17 +445,38 @@ static int __init smsc_ircc_open(unsigne
+               
+       smsc_ircc_init_chip(self);
+       
+-      if(ircc_transceiver > 0 && ircc_transceiver < SMSC_IRCC2_C_NUMBER_OF_TRANSCEIVERS) self->transceiver = ircc_transceiver;
+-      else smsc_ircc_probe_transceiver(self);
++      if(ircc_transceiver > 0  && 
++         ircc_transceiver < SMSC_IRCC2_C_NUMBER_OF_TRANSCEIVERS)
++              self->transceiver = ircc_transceiver;
++      else
++              smsc_ircc_probe_transceiver(self);
+-      err = smsc_ircc_setup_netdev(self);
+-      if(err) return err;
++      err = register_netdev(self->netdev);
++      if(err) {
++              ERROR("%s, Network device registration failed!\n",
++                    driver_name);
++              goto err_out4;
++      }
+       self->pmdev = pm_register(PM_SYS_DEV, PM_SYS_IRDA, smsc_ircc_pmproc);
+       if (self->pmdev)
+               self->pmdev->data = self;
++      MESSAGE("IrDA: Registered device %s\n", dev->name);
++
+       return 0;
++ err_out4:
++      kfree(self->tx_buff.head);
++ err_out3:
++      kfree(self->rx_buff.head);
++ err_out2:
++      free_netdev(self->netdev);
++      dev_self[--dev_count] = NULL;
++ err_out1:
++      release_region(fir_base, SMSC_IRCC2_FIR_CHIP_IO_EXTENT);
++      release_region(sir_base, SMSC_IRCC2_SIR_CHIP_IO_EXTENT);
++ err_out:
++      return err;
+ }
+ /*
+@@ -428,18 +489,19 @@ static int smsc_ircc_present(unsigned in
+ {
+       unsigned char low, high, chip, config, dma, irq, version;
+-      if (check_region(fir_base, SMSC_IRCC2_FIR_CHIP_IO_EXTENT) < 0) {
++      if (!request_region(fir_base, SMSC_IRCC2_FIR_CHIP_IO_EXTENT,
++                          driver_name)) {
+               WARNING("%s: can't get fir_base of 0x%03x\n",
+                       __FUNCTION__, fir_base);
+-              return -ENODEV;
++              goto out1;
+       }
+-#if POSSIBLE_USED_BY_SERIAL_DRIVER
+-      if (check_region(sir_base, SMSC_IRCC2_SIR_CHIP_IO_EXTENT) < 0) {
++
++      if (!request_region(sir_base, SMSC_IRCC2_SIR_CHIP_IO_EXTENT,
++                          driver_name)) {
+               WARNING("%s: can't get sir_base of 0x%03x\n",
+                       __FUNCTION__, sir_base);
+-              return -ENODEV;
++              goto out2;
+       }
+-#endif
+       register_bank(fir_base, 3);
+@@ -454,54 +516,19 @@ static int smsc_ircc_present(unsigned in
+       if (high != 0x10 || low != 0xb8 || (chip != 0xf1 && chip != 0xf2)) { 
+               WARNING("%s(), addr 0x%04x - no device found!\n",
+                       __FUNCTION__, fir_base);
+-              return -ENODEV;
++              goto out3;
+       }
+       MESSAGE("SMsC IrDA Controller found\n IrCC version %d.%d, "
+               "firport 0x%03x, sirport 0x%03x dma=%d, irq=%d\n",
+               chip & 0x0f, version, fir_base, sir_base, dma, irq);
+       return 0;
+-}
+-
+-/*
+- * Function smsc_ircc_setup_buffers(self)
+- *
+- *    Setup RX/TX buffers
+- *
+- */
+-static int smsc_ircc_setup_buffers(struct smsc_ircc_cb *self)
+-{
+-      self->rx_buff.truesize = SMSC_IRCC2_RX_BUFF_TRUESIZE; 
+-      self->tx_buff.truesize = SMSC_IRCC2_TX_BUFF_TRUESIZE;
+-
+-      self->rx_buff.head = (u8 *) kmalloc(self->rx_buff.truesize,
+-                                            GFP_KERNEL|GFP_DMA);
+-      if (self->rx_buff.head == NULL) {
+-              ERROR("%s, Can't allocate memory for receive buffer!\n",
+-                      driver_name);
+-              kfree(self);
+-              return -ENOMEM;
+-      }
+-
+-      self->tx_buff.head = (u8 *) kmalloc(self->tx_buff.truesize, 
+-                                            GFP_KERNEL|GFP_DMA);
+-      if (self->tx_buff.head == NULL) {
+-              ERROR("%s, Can't allocate memory for transmit buffer!\n",
+-                      driver_name);
+-              kfree(self->rx_buff.head);
+-              kfree(self);
+-              return -ENOMEM;
+-      }
+-
+-      memset(self->rx_buff.head, 0, self->rx_buff.truesize);
+-      memset(self->tx_buff.head, 0, self->tx_buff.truesize);
+-
+-      self->rx_buff.in_frame = FALSE;
+-      self->rx_buff.state = OUTSIDE_FRAME;
+-      self->tx_buff.data = self->tx_buff.head;
+-      self->rx_buff.data = self->rx_buff.head;
+-
+-      return 0;
++ out3:
++      release_region(fir_base, SMSC_IRCC2_FIR_CHIP_IO_EXTENT);
++ out2:
++      release_region(fir_base, SMSC_IRCC2_FIR_CHIP_IO_EXTENT);
++ out1:
++      return -ENODEV;
+ }
+ /*
+@@ -510,10 +537,11 @@ static int smsc_ircc_setup_buffers(struc
+  *    Setup I/O
+  *
+  */
+-static int smsc_ircc_setup_io(struct smsc_ircc_cb *self, unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq)
++static void smsc_ircc_setup_io(struct smsc_ircc_cb *self, 
++                             unsigned int fir_base, unsigned int sir_base, 
++                             u8 dma, u8 irq)
+ {
+       unsigned char config, chip_dma, chip_irq;
+-      void *ret;
+       register_bank(fir_base, 3);
+       config  = inb(fir_base+IRCC_INTERFACE);
+@@ -545,27 +573,6 @@ static int smsc_ircc_setup_io(struct sms
+       else
+               self->io.dma = chip_dma;
+-      ret = request_region(self->io.fir_base, self->io.fir_ext, driver_name);
+-      if (!ret) { 
+-              WARNING("%s(), can't get iobase of 0x%03x\n",
+-                      __FUNCTION__, self->io.fir_base);
+-              kfree(self->tx_buff.head);
+-              kfree(self->rx_buff.head);
+-              kfree(self);
+-              return -ENODEV;
+-      }
+-      ret = request_region(self->io.sir_base, self->io.sir_ext, driver_name);
+-      if (!ret) { 
+-              WARNING("%s(), can't get iobase of 0x%03x\n",
+-                      __FUNCTION__, self->io.sir_base);
+-              release_region(self->io.fir_base, self->io.fir_ext);
+-              kfree(self->tx_buff.head);
+-              kfree(self->rx_buff.head);
+-              kfree(self);
+-              return -ENODEV;
+-      }
+-
+-      return 0;
+ }
+ /*
+@@ -635,59 +642,6 @@ static void smsc_ircc_init_chip(struct s
+ }
+ /*
+- * Function smsc_ircc_setup_netdev(self)
+- *
+- *    Alloc and setup network device
+- *
+- */
+-static int smsc_ircc_setup_netdev(struct smsc_ircc_cb *self)
+-{
+-      struct net_device *dev;
+-      int err;
+-      /* Alloc netdev */
+-
+-      if (!(dev = dev_alloc("irda%d", &err))) {
+-              ERROR("%s(), dev_alloc() failed!\n", __FUNCTION__);
+-              kfree(self->tx_buff.head);
+-              kfree(self->rx_buff.head);
+-              kfree(self);
+-              return -ENOMEM;
+-      }
+-
+-      dev->priv = (void *) self;
+-      self->netdev = dev;
+-
+-      dev->init            = smsc_ircc_net_init;
+-      dev->hard_start_xmit = smsc_ircc_hard_xmit_sir;
+-      #if SMSC_IRCC2_C_NET_TIMEOUT
+-      dev->tx_timeout      = smsc_ircc_timeout;
+-      dev->watchdog_timeo  = HZ*2;  /* Allow enough time for speed change */
+-      #endif
+-      dev->open            = smsc_ircc_net_open;
+-      dev->stop            = smsc_ircc_net_close;
+-      dev->do_ioctl        = smsc_ircc_net_ioctl;
+-      dev->get_stats       = smsc_ircc_net_get_stats;
+-      
+-      /* Make ifconfig display some details */
+-      dev->base_addr = self->io.fir_base;
+-      dev->irq = self->io.irq;
+-
+-      rtnl_lock();
+-      err = register_netdevice(dev);
+-      rtnl_unlock();
+-      if (err) {
+-              ERROR("%s(), register_netdev() failed!\n", __FUNCTION__);
+-              kfree(self->tx_buff.head);
+-              kfree(self->rx_buff.head);
+-              kfree(self);
+-              return -ENODEV;
+-      }
+-      MESSAGE("IrDA: Registered device %s\n", dev->name);
+-
+-      return 0;
+-}
+-
+-/*
+  * Function smsc_ircc_net_ioctl (dev, rq, cmd)
+  *
+  *    Process IOCTL commands for this device
+@@ -1571,18 +1525,6 @@ static int ircc_is_receiving(struct smsc
+ }
+ #endif /* unused */
+-static int smsc_ircc_net_init(struct net_device *dev)
+-{
+-      /* Keep track of module usage */
+-      SET_MODULE_OWNER(dev);
+-
+-      /* Set up to be a normal IrDA network device driver */
+-      irda_device_setup(dev);
+-
+-      /* Insert overrides below this line! */
+-
+-      return 0;
+-}
+ /*
+  * Function smsc_ircc_net_open (dev)
+@@ -1745,11 +1687,7 @@ static int __exit smsc_ircc_close(struct
+               pm_unregister(self->pmdev);
+       /* Remove netdevice */
+-      if (self->netdev) {
+-              rtnl_lock();
+-              unregister_netdevice(self->netdev);
+-              rtnl_unlock();
+-      }
++      unregister_netdev(self->netdev);
+       /* Make sure the irq handler is not exectuting */
+       spin_lock_irqsave(&self->lock, flags);
+@@ -1784,7 +1722,7 @@ static int __exit smsc_ircc_close(struct
+       if (self->rx_buff.head)
+               kfree(self->rx_buff.head);
+-      kfree(self);
++      free_netdev(self->netdev);
+       return 0;
+ }
+@@ -2269,32 +2207,36 @@ static const smsc_chip_t * __init smsc_i
+ static int __init smsc_superio_fdc(unsigned short cfg_base)
+ {
+-      if (check_region(cfg_base, 2) < 0) {
++      int ret = -1;
++
++      if (!request_region(cfg_base, 2, driver_name)) {
+               WARNING("%s: can't get cfg_base of 0x%03x\n",
+                       __FUNCTION__, cfg_base);
+-              return -1;
+-      }
++      } else {
++              if (!smsc_superio_flat(fdc_chips_flat,cfg_base,"FDC")
++                  ||!smsc_superio_paged(fdc_chips_paged,cfg_base,"FDC"))
++                      ret =  0;
+-      if (!smsc_superio_flat(fdc_chips_flat,cfg_base,"FDC")||!smsc_superio_paged(fdc_chips_paged,cfg_base,"FDC"))
+-              return 0;
++              release_region(cfg_base, 2);
++      }
+-      return -1;
++      return ret;
+ }
+ static int __init smsc_superio_lpc(unsigned short cfg_base)
+ {
+-#if 0
+-      if (check_region(cfg_base, 2) < 0) {
+-              IRDA_DEBUG(0, __FUNCTION__ ": can't get cfg_base of 0x%03x\n",
+-                         cfg_base);
+-              return -1;
+-      }
+-#endif
+-
+-      if (!smsc_superio_flat(lpc_chips_flat,cfg_base,"LPC")||!smsc_superio_paged(lpc_chips_paged,cfg_base,"LPC"))
+-              return 0;
++      int ret = -1;
+-      return -1;
++      if (!request_region(cfg_base, 2, driver_name)) {
++              WARNING("%s: can't get cfg_base of 0x%03x\n",
++                      __FUNCTION__, cfg_base);
++      } else {
++              if (!smsc_superio_flat(lpc_chips_flat,cfg_base,"LPC")
++                  ||!smsc_superio_paged(lpc_chips_paged,cfg_base,"LPC"))
++                      ret = 0;
++              release_region(cfg_base, 2);
++      }
++      return ret;
+ }
+ /************************************************
+--- linux-2.6.0-test6/drivers/net/irda/tekram.c        2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/net/irda/tekram.c       2003-10-05 00:33:24.000000000 -0700
+@@ -44,12 +44,12 @@ static int  tekram_reset(struct irda_tas
+ #define TEKRAM_PW     0x10 /* Pulse select bit */
+ static struct dongle_reg dongle = {
+-      Q_NULL,
+-      IRDA_TEKRAM_DONGLE,
+-      tekram_open,
+-      tekram_close,
+-      tekram_reset,
+-      tekram_change_speed,
++      .type = IRDA_TEKRAM_DONGLE,
++      .open  = tekram_open,
++      .close = tekram_close,
++      .reset = tekram_reset,
++      .change_speed = tekram_change_speed,
++      .owner = THIS_MODULE,
+ };
+ int __init tekram_init(void)
+@@ -69,8 +69,6 @@ static void tekram_open(dongle_t *self, 
+       qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
+       qos->min_turn_time.bits = 0x01; /* Needs at least 10 ms */      
+       irda_qos_bits_to_value(qos);
+-
+-      MOD_INC_USE_COUNT;
+ }
+ static void tekram_close(dongle_t *self)
+@@ -84,8 +82,6 @@ static void tekram_close(dongle_t *self)
+               irda_task_delete(self->reset_task);
+       if (self->speed_task)
+               irda_task_delete(self->speed_task);
+-
+-      MOD_DEC_USE_COUNT;
+ }
+ /*
+--- linux-2.6.0-test6/drivers/net/irda/via-ircc.c      2003-09-27 18:57:45.000000000 -0700
++++ 25/drivers/net/irda/via-ircc.c     2003-10-05 00:33:24.000000000 -0700
+@@ -335,8 +335,7 @@ static __devinit int via_ircc_open(int i
+               return -1;
+       /* Allocate new instance of the driver */
+-      dev = alloc_netdev(sizeof(struct via_ircc_cb), "irda%d",
+-                         irda_device_setup);
++      dev = alloc_irdadev(sizeof(struct via_ircc_cb));
+       if (dev == NULL) 
+               return -ENOMEM;
+--- linux-2.6.0-test6/drivers/net/irda/vlsi_ir.c       2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/net/irda/vlsi_ir.c      2003-10-05 00:33:24.000000000 -0700
+@@ -1859,15 +1859,6 @@ static void __devexit vlsi_irda_remove(s
+  * otherwise we might get cheated by pci-pm.
+  */
+-static int vlsi_irda_save_state(struct pci_dev *pdev, u32 state)
+-{
+-      if (state < 1 || state > 3 ) {
+-              ERROR("%s - %s: invalid pm state request: %u\n",
+-                      __FUNCTION__, PCIDEV_NAME(pdev), state);
+-              return -1;
+-      }
+-      return 0;
+-}
+ static int vlsi_irda_suspend(struct pci_dev *pdev, u32 state)
+ {
+@@ -1970,7 +1961,6 @@ static struct pci_driver vlsi_irda_drive
+       .probe          = vlsi_irda_probe,
+       .remove         = __devexit_p(vlsi_irda_remove),
+ #ifdef CONFIG_PM
+-      .save_state     = vlsi_irda_save_state,
+       .suspend        = vlsi_irda_suspend,
+       .resume         = vlsi_irda_resume,
+ #endif
+--- linux-2.6.0-test6/drivers/net/irda/w83977af_ir.c   2003-09-27 18:57:45.000000000 -0700
++++ 25/drivers/net/irda/w83977af_ir.c  2003-10-05 00:33:24.000000000 -0700
+@@ -170,8 +170,7 @@ int w83977af_open(int i, unsigned int io
+       /*
+        *  Allocate new instance of the driver
+        */
+-      dev = alloc_netdev(sizeof(struct w83977af_ir), "irda%d",
+-                         irda_device_setup);
++      dev = alloc_irdadev(sizeof(struct w83977af_ir));
+       if (dev == NULL) {
+               printk( KERN_ERR "IrDA: Can't allocate memory for "
+                       "IrDA control block!\n");
+--- linux-2.6.0-test6/drivers/net/Kconfig      2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/net/Kconfig     2003-10-05 00:33:46.000000000 -0700
+@@ -8,32 +8,18 @@ config NETDEVICES
+       bool "Network device support"
+       ---help---
+         You can say N here if you don't intend to connect your Linux box to
+-        any other computer at all or if all your connections will be over a
+-        telephone line with a modem either via UUCP (UUCP is a protocol to
+-        forward mail and news between unix hosts over telephone lines; read
+-        the UUCP-HOWTO, available from
+-        <http://www.tldp.org/docs.html#howto>) or dialing up a shell
+-        account or a BBS, even using term (term is a program which gives you
+-        almost full Internet connectivity if you have a regular dial up
+-        shell account on some Internet connected Unix computer. Read
+-        <http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html>).
++        any other computer at all.
+         You'll have to say Y if your computer contains a network card that
+-        you want to use under Linux (make sure you know its name because you
+-        will be asked for it and read the Ethernet-HOWTO (especially if you
+-        plan to use more than one network card under Linux)) or if you want
+-        to use SLIP (Serial Line Internet Protocol is the protocol used to
+-        send Internet traffic over telephone lines or null modem cables) or
+-        CSLIP (compressed SLIP) or PPP (Point to Point Protocol, a better
+-        and newer replacement for SLIP) or PLIP (Parallel Line Internet
+-        Protocol is mainly used to create a mini network by connecting the
+-        parallel ports of two local machines) or AX.25/KISS (protocol for
+-        sending Internet traffic over amateur radio links).
+-
+-        Make sure to read the NET-3-HOWTO. Eventually, you will have to read
+-        Olaf Kirch's excellent and free book "Network Administrator's
+-        Guide", to be found in <http://www.tldp.org/docs.html#guide>. If
+-        unsure, say Y.
++        you want to use under Linux. If you are going to run SLIP or PPP over
++        telephone line or null modem cable you need say Y here. Connecting
++        two machines with parallel ports using PLIP needs this, as well as
++        AX.25/KISS for sending Internet traffic over amateur radio links.
++
++        See also "The Linux Network Administrator's Guide" by Olaf Kirch and
++        Terry Dawson. Available at <http://www.tldp.org/guides.html>.
++
++        If unsure, say Y.
+ if NETDEVICES
+       source "drivers/net/arcnet/Kconfig"
+@@ -332,7 +318,7 @@ config MAC8390
+ config MAC89x0
+       tristate "Macintosh CS89x0 based ethernet cards"
+-      depends on NETDEVICES && MAC
++      depends on NETDEVICES && MAC && BROKEN
+       ---help---
+         Support for CS89x0 chipset based Ethernet cards.  If you have a
+         Nubus or LC-PDS network (Ethernet) card of this type, say Y and
+@@ -405,7 +391,7 @@ config ATARILANCE
+ config ATARI_BIONET
+       tristate "BioNet-100 support"
+-      depends on NETDEVICES && ATARI && ATARI_ACSI!=n
++      depends on NETDEVICES && ATARI && ATARI_ACSI!=n && BROKEN
+       help
+         Say Y to include support for BioData's BioNet-100 Ethernet adapter
+         for the ACSI port. The driver works (has to work...) with a polled
+@@ -413,7 +399,7 @@ config ATARI_BIONET
+ config ATARI_PAMSNET
+       tristate "PAMsNet support"
+-      depends on NETDEVICES && ATARI && ATARI_ACSI!=n
++      depends on NETDEVICES && ATARI && ATARI_ACSI!=n && BROKEN
+       help
+         Say Y to include support for the PAMsNet Ethernet adapter for the
+         ACSI port ("ACSI node"). The driver works (has to work...) with a
+@@ -808,7 +794,7 @@ config ULTRA32
+ config SMC9194
+       tristate "SMC 9194 support"
+-      depends on NET_VENDOR_SMC && (ISA || MAC)
++      depends on NET_VENDOR_SMC && (ISA || MAC && BROKEN)
+       select CRC32
+       ---help---
+         This is support for the SMC9xxx based Ethernet cards. Choose this
+@@ -2455,6 +2441,9 @@ config SHAPER
+         To compile this driver as a module, choose M here: the module
+         will be called shaper.  If unsure, say N.
++config NET_POLL_CONTROLLER
++      def_bool KGDB
++
+ source "drivers/net/wan/Kconfig"
+ source "drivers/net/pcmcia/Kconfig"
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/drivers/net/kgdb_eth.c  2003-10-05 00:33:51.000000000 -0700
+@@ -0,0 +1,517 @@
++/*
++ * Network interface GDB stub
++ *
++ * Written by San Mehat (nettwerk@biodome.org)
++ * Based upon 'gdbserial' by David Grothe (dave@gcom.com)
++ * and Scott Foehner (sfoehner@engr.sgi.com)
++ *
++ * Twiddled for 2.6 by Robert Walsh <rjwalsh@durables.org>
++ * and wangdi <wangdi@clusterfs.com>.
++ */
++
++#include <linux/module.h>
++#include <linux/errno.h>
++#include <linux/signal.h>
++#include <linux/sched.h>
++#include <linux/timer.h>
++#include <linux/interrupt.h>
++#include <linux/config.h>
++#include <linux/major.h>
++#include <linux/string.h>
++#include <linux/fcntl.h>
++#include <linux/termios.h>
++#include <asm/kgdb.h>
++#include <linux/if_ether.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/skbuff.h>
++#include <linux/delay.h>
++#include <net/tcp.h>
++#include <net/udp.h>
++
++#include <asm/system.h>
++#include <asm/io.h>
++#include <asm/segment.h>
++#include <asm/bitops.h>
++#include <asm/system.h>
++#include <asm/irq.h>
++#include <asm/atomic.h>
++
++#define       GDB_BUF_SIZE    512             /* power of 2, please */
++
++static char   kgdb_buf[GDB_BUF_SIZE] ;
++static int    kgdb_buf_in_inx ;
++static atomic_t       kgdb_buf_in_cnt ;
++static int    kgdb_buf_out_inx ;
++
++extern void   set_debug_traps(void) ;         /* GDB routine */
++extern void   breakpoint(void);
++
++unsigned int  kgdb_remoteip = 0;
++unsigned short        kgdb_listenport = 6443;
++unsigned short        kgdb_sendport= 6442;
++int           kgdb_eth = -1; /* Default tty mode */
++unsigned char kgdb_remotemac[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
++unsigned char kgdb_localmac[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
++volatile int  kgdb_eth_is_initializing = 0;
++int           kgdb_eth_need_breakpoint[NR_CPUS];
++
++struct net_device *kgdb_netdevice = NULL;
++
++/*
++ * Get a char if available, return -1 if nothing available.
++ * Empty the receive buffer first, then look at the interface hardware.
++ */
++static int
++read_char(void)
++{
++      /* intr routine has queued chars */
++      if (atomic_read(&kgdb_buf_in_cnt) != 0)
++      {
++              int chr;
++
++              chr = kgdb_buf[kgdb_buf_out_inx++] ;
++              kgdb_buf_out_inx &= (GDB_BUF_SIZE - 1) ;
++              atomic_dec(&kgdb_buf_in_cnt) ;
++              return chr;
++      }
++
++      return -1; /* no data */
++}
++
++/*
++ * Wait until the interface can accept a char, then write it.
++ */
++static void
++write_buffer(char *buf, int len)
++{
++      int                     total_len, eth_len, ip_len, udp_len;
++      struct in_device        *in_dev;
++      struct sk_buff          *skb;
++      struct udphdr           *udph;
++      struct iphdr            *iph;
++      struct ethhdr           *eth;
++
++      if (!(in_dev = (struct in_device *) kgdb_netdevice->ip_ptr)) {
++              panic("No in_device available for interface!\n");
++      }
++
++      if (!(in_dev->ifa_list)) {
++              panic("No interface address set for interface!\n");
++      }
++
++      udp_len = len + sizeof(struct udphdr);
++      ip_len = eth_len = udp_len + sizeof(struct iphdr);
++      total_len = eth_len + ETH_HLEN;
++
++      if (!(skb = alloc_skb(total_len, GFP_ATOMIC))) {
++              return;
++      }
++
++      atomic_set(&skb->users, 1);
++      skb_reserve(skb, total_len - len);
++
++      memcpy(skb->data, (unsigned char *) buf, len);
++      skb->len += len;
++
++      udph = (struct udphdr *) skb_push(skb, sizeof(*udph));
++      udph->source = htons(kgdb_listenport);
++      udph->dest   = htons(kgdb_sendport);
++      udph->len    = htons(udp_len);
++      udph->check  = 0;
++
++      iph = (struct iphdr *)skb_push(skb, sizeof(*iph));
++      iph->version  = 4;
++      iph->ihl      = 5;
++      iph->tos      = 0;
++      iph->tot_len  = htons(ip_len);
++      iph->id       = 0;
++      iph->frag_off = 0;
++      iph->ttl      = 64;
++      iph->protocol = IPPROTO_UDP;
++      iph->check    = 0;
++      iph->saddr    = in_dev->ifa_list->ifa_address;
++      iph->daddr    = kgdb_remoteip;
++      iph->check    = ip_fast_csum((unsigned char *)iph, iph->ihl);
++
++      eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
++      eth->h_proto = htons(ETH_P_IP);
++      memcpy(eth->h_source, kgdb_localmac, kgdb_netdevice->addr_len);
++      memcpy(eth->h_dest, kgdb_remotemac, kgdb_netdevice->addr_len);
++
++repeat:
++      spin_lock(&kgdb_netdevice->xmit_lock);
++      kgdb_netdevice->xmit_lock_owner = smp_processor_id();
++
++      if (netif_queue_stopped(kgdb_netdevice)) {
++              kgdb_netdevice->xmit_lock_owner = -1;
++              spin_unlock(&kgdb_netdevice->xmit_lock);
++
++              kgdb_netdevice->poll_controller(kgdb_netdevice);
++              goto repeat;
++      }
++
++      kgdb_netdevice->hard_start_xmit(skb, kgdb_netdevice);
++      kgdb_netdevice->xmit_lock_owner = -1;
++      spin_unlock(&kgdb_netdevice->xmit_lock);
++}
++
++/*
++ * In the interrupt state the target machine will not respond to any
++ * arp requests, so handle them here.
++ */
++
++static struct sk_buff *send_skb = NULL;
++
++void
++kgdb_eth_reply_arp(void)
++{
++      if (send_skb) {
++              spin_lock(&kgdb_netdevice->xmit_lock);
++              kgdb_netdevice->xmit_lock_owner = smp_processor_id();
++              kgdb_netdevice->hard_start_xmit(send_skb, kgdb_netdevice);
++              kgdb_netdevice->xmit_lock_owner = -1;
++              spin_unlock(&kgdb_netdevice->xmit_lock);
++              send_skb = NULL;
++      }
++}
++
++static int
++make_arp_request(struct sk_buff *skb)
++{
++      struct arphdr *arp;
++      unsigned char *arp_ptr;
++      int type = ARPOP_REPLY;
++      int ptype = ETH_P_ARP;
++      u32 sip, tip;
++      unsigned char *sha, *tha;
++      struct in_device *in_dev = (struct in_device *) kgdb_netdevice->ip_ptr;
++
++      /* No arp on this interface */
++
++      if (kgdb_netdevice->flags & IFF_NOARP) {
++              return 0;
++      }
++
++      if (!pskb_may_pull(skb, (sizeof(struct arphdr) +
++                               (2 * kgdb_netdevice->addr_len) +
++                               (2 * sizeof(u32))))) {
++              return 0;
++      }
++
++      skb->h.raw = skb->nh.raw = skb->data;
++      arp = skb->nh.arph;
++
++      if ((arp->ar_hrd != htons(ARPHRD_ETHER) &&
++           arp->ar_hrd != htons(ARPHRD_IEEE802)) ||
++          arp->ar_pro != htons(ETH_P_IP)) {
++              return 0;
++      }
++
++      /* Understand only these message types */
++
++      if (arp->ar_op != htons(ARPOP_REQUEST)) {
++              return 0;
++      }
++
++      /* Extract fields */
++
++      arp_ptr= (unsigned char *)(arp+1);
++      sha = arp_ptr;
++      arp_ptr += kgdb_netdevice->addr_len;
++      memcpy(&sip, arp_ptr, 4);
++      arp_ptr += 4;
++      tha = arp_ptr;
++      arp_ptr += kgdb_netdevice->addr_len;
++      memcpy(&tip, arp_ptr, 4);
++
++      if (tip != in_dev->ifa_list->ifa_address) {
++              return 0;
++      }
++
++      if (kgdb_remoteip != sip) {
++              return 0;
++      }
++
++      /*
++       * Check for bad requests for 127.x.x.x and requests for multicast
++       * addresses.  If this is one such, delete it.
++       */
++
++      if (LOOPBACK(tip) || MULTICAST(tip)) {
++              return 0;
++      }
++
++      /* reply to the ARP request */
++
++      send_skb = alloc_skb(sizeof(struct arphdr) + 2 * (kgdb_netdevice->addr_len + 4) + LL_RESERVED_SPACE(kgdb_netdevice), GFP_ATOMIC);
++
++      if (send_skb == NULL) {
++              return 0;
++      }
++
++      skb_reserve(send_skb, LL_RESERVED_SPACE(kgdb_netdevice));
++      send_skb->nh.raw = send_skb->data;
++      arp = (struct arphdr *) skb_put(send_skb, sizeof(struct arphdr) + 2 * (kgdb_netdevice->addr_len + 4));
++      send_skb->dev = kgdb_netdevice;
++      send_skb->protocol = htons(ETH_P_ARP);
++
++      /* Fill the device header for the ARP frame */
++
++      if (kgdb_netdevice->hard_header &&
++          kgdb_netdevice->hard_header(send_skb, kgdb_netdevice, ptype,
++                                     kgdb_remotemac, kgdb_localmac,
++                                     send_skb->len) < 0) {
++              kfree_skb(send_skb);
++              return 0;
++      }
++
++      /*
++       * Fill out the arp protocol part.
++       *
++       * we only support ethernet device type,
++       * which (according to RFC 1390) should always equal 1 (Ethernet).
++       */
++
++      arp->ar_hrd = htons(kgdb_netdevice->type);
++      arp->ar_pro = htons(ETH_P_IP);
++
++      arp->ar_hln = kgdb_netdevice->addr_len;
++      arp->ar_pln = 4;
++      arp->ar_op = htons(type);
++
++      arp_ptr=(unsigned char *)(arp + 1);
++
++      memcpy(arp_ptr, kgdb_netdevice->dev_addr, kgdb_netdevice->addr_len);
++      arp_ptr += kgdb_netdevice->addr_len;
++      memcpy(arp_ptr, &tip, 4);
++      arp_ptr += 4;
++      memcpy(arp_ptr, kgdb_localmac, kgdb_netdevice->addr_len);
++      arp_ptr += kgdb_netdevice->addr_len;
++      memcpy(arp_ptr, &sip, 4);
++      return 0;
++}
++
++
++/*
++ * Accept an skbuff from net_device layer and add the payload onto
++ * kgdb buffer
++ *
++ * When the kgdb stub routine getDebugChar() is called it draws characters
++ * out of the buffer until it is empty and then reads directly from the
++ * serial port.
++ *
++ * We do not attempt to write chars from the interrupt routine since
++ * the stubs do all of that via putDebugChar() which writes one byte
++ * after waiting for the interface to become ready.
++ *
++ * The debug stubs like to run with interrupts disabled since, after all,
++ * they run as a consequence of a breakpoint in the kernel.
++ *
++ * NOTE: Return value of 1 means it was for us and is an indication to
++ * the calling driver to destroy the sk_buff and not send it up the stack.
++ */
++int
++kgdb_net_interrupt(struct sk_buff *skb)
++{
++      unsigned char   chr;
++      struct iphdr    *iph = (struct iphdr*)skb->data;
++      struct udphdr   *udph= (struct udphdr*)(skb->data+(iph->ihl<<2));
++      unsigned char   *data = (unsigned char *) udph + sizeof(struct udphdr);
++      int             len;
++      int             i;
++
++      if ((kgdb_eth != -1) && (!kgdb_netdevice) &&
++          (iph->protocol == IPPROTO_UDP) &&
++          (be16_to_cpu(udph->dest) == kgdb_listenport)) {
++              kgdb_sendport = be16_to_cpu(udph->source);
++
++              while (kgdb_eth_is_initializing)
++                      ;
++              if (!kgdb_netdevice)
++                      kgdb_eth_hook();
++              if (!kgdb_netdevice) {
++                      /* Lets not even try again. */
++                      kgdb_eth = -1;
++                      return 0;
++              }
++      }
++      if (!kgdb_netdevice) {
++              return 0;
++      }
++      if (skb->protocol == __constant_htons(ETH_P_ARP) && !send_skb) {
++              make_arp_request(skb);
++              return 0;
++      }
++      if (iph->protocol != IPPROTO_UDP) {
++              return 0;
++      }
++
++      if (be16_to_cpu(udph->dest) != kgdb_listenport) {
++              return 0;
++      }
++
++      len = (be16_to_cpu(iph->tot_len) -
++             (sizeof(struct udphdr) + sizeof(struct iphdr)));
++
++      for (i = 0; i < len; i++) {
++              chr = data[i];
++              if (chr == 3) {
++                      kgdb_eth_need_breakpoint[smp_processor_id()] = 1;
++                      continue;
++              }
++              if (atomic_read(&kgdb_buf_in_cnt) >= GDB_BUF_SIZE) {
++                      /* buffer overflow, clear it */
++                      kgdb_buf_in_inx = 0;
++                      atomic_set(&kgdb_buf_in_cnt, 0);
++                      kgdb_buf_out_inx = 0;
++                      break;
++              }
++              kgdb_buf[kgdb_buf_in_inx++] = chr;
++              kgdb_buf_in_inx &= (GDB_BUF_SIZE - 1);
++              atomic_inc(&kgdb_buf_in_cnt);
++      }
++
++      if (!kgdb_netdevice->kgdb_is_trapped) {
++              /*
++               * If a new gdb instance is trying to attach, we need to
++               * break here.
++               */
++              if (!strncmp(data, "$Hc-1#09", 8))
++                      kgdb_eth_need_breakpoint[smp_processor_id()] = 1;
++      }
++      return 1;
++}
++EXPORT_SYMBOL(kgdb_net_interrupt);
++
++int
++kgdb_eth_hook(void)
++{
++      char kgdb_netdev[16];
++      extern void kgdb_respond_ok(void);
++
++      if (kgdb_remotemac[0] == 0xff) {
++              panic("ERROR! 'gdbeth_remotemac' option not set!\n");
++      }
++      if (kgdb_localmac[0] == 0xff) {
++              panic("ERROR! 'gdbeth_localmac' option not set!\n");
++      }
++      if (kgdb_remoteip == 0) {
++              panic("ERROR! 'gdbeth_remoteip' option not set!\n");
++      }
++
++      sprintf(kgdb_netdev,"eth%d",kgdb_eth);
++
++#ifdef CONFIG_SMP
++      if (num_online_cpus() > CONFIG_NO_KGDB_CPUS) {
++              printk("kgdb: too manu cpus. Cannot enable debugger with more than %d cpus\n", CONFIG_NO_KGDB_CPUS);
++              return -1;
++      }
++#endif
++      for (kgdb_netdevice = dev_base;
++              kgdb_netdevice != NULL;
++              kgdb_netdevice = kgdb_netdevice->next) {
++              if (strncmp(kgdb_netdevice->name, kgdb_netdev, IFNAMSIZ) == 0) {
++                      break;
++              }
++      }
++      if (!kgdb_netdevice) {
++              printk("KGDB NET : Unable to find interface %s\n",kgdb_netdev);
++              return -ENODEV;
++      }
++
++      /*
++       * Call GDB routine to setup the exception vectors for the debugger
++       */
++      set_debug_traps();
++
++      /*
++       * Call the breakpoint() routine in GDB to start the debugging
++       * session.
++       */
++      kgdb_eth_is_initializing = 1;
++      kgdb_eth_need_breakpoint[smp_processor_id()] = 1;
++      return 0;
++}
++
++/*
++ * getDebugChar
++ *
++ * This is a GDB stub routine.  It waits for a character from the
++ * serial interface and then returns it.  If there is no serial
++ * interface connection then it returns a bogus value which will
++ * almost certainly cause the system to hang.
++ */
++int
++eth_getDebugChar(void)
++{
++      volatile int    chr;
++
++      while ((chr = read_char()) < 0) {
++              if (send_skb) {
++                      kgdb_eth_reply_arp();
++              }
++              if (kgdb_netdevice->poll_controller) {
++                      kgdb_netdevice->poll_controller(kgdb_netdevice);
++              } else {
++                      printk("KGDB NET: Error - Device %s is not supported!\n", kgdb_netdevice->name);
++                      panic("Please add support for kgdb net to this driver");
++              }
++      }
++      return chr;
++}
++
++#define ETH_QUEUE_SIZE 256
++static char eth_queue[ETH_QUEUE_SIZE];
++static int outgoing_queue;
++
++void
++eth_flushDebugChar(void)
++{
++      if(outgoing_queue) {
++              write_buffer(eth_queue, outgoing_queue);
++
++              outgoing_queue = 0;
++      }
++}
++
++static void
++put_char_on_queue(int chr)
++{
++      eth_queue[outgoing_queue++] = chr;
++      if(outgoing_queue == ETH_QUEUE_SIZE)
++      {
++              eth_flushDebugChar();
++      }
++}
++
++/*
++ * eth_putDebugChar
++ *
++ * This is a GDB stub routine.  It waits until the interface is ready
++ * to transmit a char and then sends it.
++ */
++void
++eth_putDebugChar(int chr)
++{
++      put_char_on_queue(chr); /* this routine will wait */
++}
++
++void
++kgdb_eth_set_trapmode(int mode)
++{
++      if (!kgdb_netdevice) {
++              return;
++      }
++      kgdb_netdevice->kgdb_is_trapped = mode;
++}
++
++int
++kgdb_eth_is_trapped()
++{
++      if (!kgdb_netdevice) {
++              return 0;
++      }
++      return kgdb_netdevice->kgdb_is_trapped;
++}
++EXPORT_SYMBOL(kgdb_eth_is_trapped);
+--- linux-2.6.0-test6/drivers/net/loopback.c   2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/net/loopback.c  2003-10-05 00:33:24.000000000 -0700
+@@ -30,6 +30,7 @@
+  */
+ #include <linux/kernel.h>
+ #include <linux/jiffies.h>
++#include <linux/module.h>
+ #include <linux/interrupt.h>
+ #include <linux/fs.h>
+ #include <linux/types.h>
+@@ -202,3 +203,5 @@ int __init loopback_init(void)
+       
+       return register_netdev(&loopback_dev);
+ };
++
++EXPORT_SYMBOL(loopback_dev);
+--- linux-2.6.0-test6/drivers/net/mac8390.c    2003-07-27 12:14:39.000000000 -0700
++++ 25/drivers/net/mac8390.c   2003-10-05 00:33:24.000000000 -0700
+@@ -442,14 +442,14 @@ int __init mac8390_initdev(struct net_de
+                ei_status.tx_start_page = CABLETRON_TX_START_PG;
+                ei_status.rx_start_page = CABLETRON_RX_START_PG;
+                ei_status.stop_page = CABLETRON_RX_STOP_PG;
+-               dev->rmem_start = dev->mem_start;
+-               dev->rmem_end = dev->mem_start + CABLETRON_RX_STOP_PG*256;
++               ei_status.rmem_start = dev->mem_start;
++               ei_status.rmem_end = dev->mem_start + CABLETRON_RX_STOP_PG*256;
+       } else {
+                ei_status.tx_start_page = WD_START_PG;
+                ei_status.rx_start_page = WD_START_PG + TX_PAGES;
+                ei_status.stop_page = (dev->mem_end - dev->mem_start)/256;
+-               dev->rmem_start = dev->mem_start + TX_PAGES*256;
+-               dev->rmem_end = dev->mem_end;
++               ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
++               ei_status.rmem_end = dev->mem_end;
+       }
+       
+       /* Fill in model-specific information and functions */
+@@ -621,12 +621,12 @@ static void sane_block_input(struct net_
+       unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
+       unsigned long xfer_start = xfer_base + dev->mem_start;
+-      if (xfer_start + count > dev->rmem_end) {
++      if (xfer_start + count > ei_status.rmem_end) {
+               /* We must wrap the input move. */
+-              int semi_count = dev->rmem_end - xfer_start;
++              int semi_count = ei_status.rmem_end - xfer_start;
+               memcpy_fromio(skb->data, (char *)dev->mem_start + xfer_base, semi_count);
+               count -= semi_count;
+-              memcpy_toio(skb->data + semi_count, (char *)dev->rmem_start, count);
++              memcpy_toio(skb->data + semi_count, (char *)ei_status.rmem_start, count);
+       } else {
+               memcpy_fromio(skb->data, (char *)dev->mem_start + xfer_base, count);
+       }
+@@ -657,15 +657,16 @@ static void dayna_block_input(struct net
+       /* Note the offset math is done in card memory space which is word
+          per long onto our space. */
+-       
+-      if (xfer_start + count > dev->rmem_end) 
++
++      if (xfer_start + count > ei_status.rmem_end)
+       {
+               /* We must wrap the input move. */
+-              int semi_count = dev->rmem_end - xfer_start;
++              int semi_count = ei_status.rmem_end - xfer_start;
+               dayna_memcpy_fromcard(dev, skb->data, xfer_base, semi_count);
+               count -= semi_count;
+-              dayna_memcpy_fromcard(dev, skb->data + semi_count, 
+-                      dev->rmem_start - dev->mem_start, count);
++              dayna_memcpy_fromcard(dev, skb->data + semi_count,
++                                    ei_status.rmem_start - dev->mem_start,
++                                    count);
+       }
+       else
+       {
+@@ -697,15 +698,15 @@ static void slow_sane_block_input(struct
+       unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
+       unsigned long xfer_start = xfer_base+dev->mem_start;
+-      if (xfer_start + count > dev->rmem_end)
++      if (xfer_start + count > ei_status.rmem_end)
+       {
+               /* We must wrap the input move. */
+-              int semi_count = dev->rmem_end - xfer_start;
++              int semi_count = ei_status.rmem_end - xfer_start;
+               word_memcpy_fromcard(skb->data, (char *)dev->mem_start +
+                       xfer_base, semi_count);
+               count -= semi_count;
+               word_memcpy_fromcard(skb->data + semi_count,
+-                      (char *)dev->rmem_start, count);
++                                   (char *)ei_status.rmem_start, count);
+       }
+       else
+       {
+--- linux-2.6.0-test6/drivers/net/Makefile     2003-09-27 18:57:44.000000000 -0700
++++ 25/drivers/net/Makefile    2003-10-05 00:33:44.000000000 -0700
+@@ -32,6 +32,8 @@ obj-$(CONFIG_BMAC) += bmac.o
+ obj-$(CONFIG_OAKNET) += oaknet.o 8390.o
++obj-$(CONFIG_KGDB) += kgdb_eth.o
++
+ obj-$(CONFIG_DGRS) += dgrs.o
+ obj-$(CONFIG_RCPCI) += rcpci.o
+ obj-$(CONFIG_VORTEX) += 3c59x.o
+--- linux-2.6.0-test6/drivers/net/ne2.c        2003-09-27 18:57:45.000000000 -0700
++++ 25/drivers/net/ne2.c       2003-10-05 00:33:24.000000000 -0700
+@@ -70,7 +70,7 @@ static const char *version = "ne2.c:v0.9
+ #include <linux/string.h>
+ #include <linux/errno.h>
+ #include <linux/init.h>
+-#include <linux/mca.h>
++#include <linux/mca-legacy.h>
+ #include <linux/netdevice.h>
+ #include <linux/etherdevice.h>
+ #include <linux/skbuff.h>
+--- linux-2.6.0-test6/drivers/net/ne3210.c     2003-09-27 18:57:45.000000000 -0700
++++ 25/drivers/net/ne3210.c    2003-10-05 00:33:24.000000000 -0700
+@@ -23,6 +23,7 @@
+       This driver WILL NOT WORK FOR THE NE3200 - it is completely different
+       and does not use an 8390 at all.
++      Updated to EISA probing API 5/2003 by Marc Zyngier.
+ */
+ static const char *version =
+@@ -44,9 +45,6 @@ static const char *version =
+ #include "8390.h"
+-int ne3210_probe(struct net_device *dev);
+-static int ne3210_probe1(struct net_device *dev, int ioaddr);
+-
+ static int ne3210_open(struct net_device *dev);
+ static int ne3210_close(struct net_device *dev);
+@@ -59,7 +57,6 @@ static void ne3210_block_output(struct n
+ #define NE3210_START_PG               0x00    /* First page of TX buffer      */
+ #define NE3210_STOP_PG                0x80    /* Last page +1 of RX ring      */
+-#define NE3210_ID_PORT                0xc80   /* Same for all EISA cards      */
+ #define NE3210_IO_EXTENT      0x20
+ #define NE3210_SA_PROM                0x16    /* Start of e'net addr.         */
+ #define NE3210_RESET_PORT     0xc84
+@@ -69,10 +66,9 @@ static void ne3210_block_output(struct n
+ #define NE3210_ADDR1          0x00
+ #define NE3210_ADDR2          0x1b
+-#define NE3210_ID     0x0118cc3a      /* 0x3acc = 1110 10110 01100 =  nvl */
+-
+ #define NE3210_CFG1           0xc84   /* NB: 0xc84 is also "reset" port. */
+ #define NE3210_CFG2           0xc90
++#define NE3210_CFG_EXTENT       (NE3210_CFG2 - NE3210_CFG1 + 1)
+ /*
+  *    You can OR any of the following bits together and assign it
+@@ -89,152 +85,108 @@ static void ne3210_block_output(struct n
+ static unsigned char irq_map[] __initdata = {15, 12, 11, 10, 9, 7, 5, 3};
+ static unsigned int shmem_map[] __initdata = {0xff0, 0xfe0, 0xfff0, 0xd8, 0xffe0, 0xffc0, 0xd0, 0x0};
++static const char *ifmap[] __initdata = {"UTP", "?", "BNC", "AUI"};
++static int ifmap_val[] __initdata = {
++              IF_PORT_10BASET,
++              IF_PORT_UNKNOWN,
++              IF_PORT_10BASE2,
++              IF_PORT_AUI,
++};
+-/*
+- *    Probe for the card. The best way is to read the EISA ID if it
+- *    is known. Then we can check the prefix of the station address
+- *    PROM for a match against the value assigned to Novell.
+- */
+-
+-int __init ne3210_probe(struct net_device *dev)
++static int __init ne3210_eisa_probe (struct device *device)
+ {
+-      unsigned short ioaddr = dev->base_addr;
+-
+-      SET_MODULE_OWNER(dev);
++      unsigned long ioaddr, phys_mem;
++      int i, retval, port_index;
++      struct eisa_device *edev = to_eisa_device (device);
++      struct net_device *dev;
+-      if (ioaddr > 0x1ff)             /* Check a single specified location. */
+-              return ne3210_probe1(dev, ioaddr);
+-      else if (ioaddr > 0)            /* Don't probe at all. */
+-              return -ENXIO;
+-
+-      if (!EISA_bus) {
+-#if NE3210_DEBUG & NE3210_D_PROBE
+-              printk("ne3210-debug: Not an EISA bus. Not probing high ports.\n");
+-#endif
+-              return -ENXIO;
++      /* Allocate dev->priv and fill in 8390 specific dev fields. */
++      if (!(dev = alloc_ei_netdev ())) {
++              printk ("ne3210.c: unable to allocate memory for dev!\n");
++              return -ENOMEM;
+       }
+-      /* EISA spec allows for up to 16 slots, but 8 is typical. */
+-      for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000)
+-              if (ne3210_probe1(dev, ioaddr) == 0)
+-                      return 0;
+-
+-      return -ENODEV;
+-}
+-
+-static int __init ne3210_probe1(struct net_device *dev, int ioaddr)
+-{
+-      int i, retval;
+-      unsigned long eisa_id;
+-      const char *ifmap[] = {"UTP", "?", "BNC", "AUI"};
+-
+-      if (!request_region(dev->base_addr, NE3210_IO_EXTENT, dev->name))
+-              return -EBUSY;
++      SET_MODULE_OWNER(dev);
++      SET_NETDEV_DEV(dev, device);
++      device->driver_data = dev;
++      ioaddr = edev->base_addr;
+-      if (inb_p(ioaddr + NE3210_ID_PORT) == 0xff) {
+-              retval = -ENODEV;
++      if (ethdev_init (dev)) {
++              printk ("ne3210.c: unable to allocate memory for dev->priv!\n");
++              retval = -ENOMEM;
+               goto out;
+       }
+-#if NE3210_DEBUG & NE3210_D_PROBE
+-      printk("ne3210-debug: probe at %#x, ID %#8x\n", ioaddr, inl(ioaddr + NE3210_ID_PORT));
+-      printk("ne3210-debug: config regs: %#x %#x\n",
+-              inb(ioaddr + NE3210_CFG1), inb(ioaddr + NE3210_CFG2));
+-#endif
+-
+-
+-/*    Check the EISA ID of the card. */
+-      eisa_id = inl(ioaddr + NE3210_ID_PORT);
+-      if (eisa_id != NE3210_ID) {
+-              retval = -ENODEV;
++      if (!request_region(ioaddr, NE3210_IO_EXTENT, dev->name)) {
++              retval = -EBUSY;
+               goto out;
+       }
+-      
+-#if 0
+-/*    Check the vendor ID as well. Not really required. */
+-      if (inb(ioaddr + NE3210_SA_PROM + 0) != NE3210_ADDR0
+-              || inb(ioaddr + NE3210_SA_PROM + 1) != NE3210_ADDR1
+-              || inb(ioaddr + NE3210_SA_PROM + 2) != NE3210_ADDR2 ) {
+-              printk("ne3210.c: card not found");
+-              for(i = 0; i < ETHER_ADDR_LEN; i++)
+-                      printk(" %02x", inb(ioaddr + NE3210_SA_PROM + i));
+-              printk(" (invalid prefix).\n");
+-              retval = -ENODEV;
+-              goto out;
++      if (!request_region(ioaddr + NE3210_CFG1,
++                          NE3210_CFG_EXTENT, dev->name)) {
++              retval = -EBUSY;
++              goto out1;
+       }
++
++#if NE3210_DEBUG & NE3210_D_PROBE
++      printk("ne3210-debug: probe at %#x, ID %s\n", ioaddr, edev->id.sig);
++      printk("ne3210-debug: config regs: %#x %#x\n",
++              inb(ioaddr + NE3210_CFG1), inb(ioaddr + NE3210_CFG2));
+ #endif
+-      /* Allocate dev->priv and fill in 8390 specific dev fields. */
+-      if (ethdev_init(dev)) {
+-              printk ("ne3210.c: unable to allocate memory for dev->priv!\n");
+-              retval = -ENOMEM;
+-              goto out;
+-      }
++      port_index = inb(ioaddr + NE3210_CFG2) >> 6;
+       printk("ne3210.c: NE3210 in EISA slot %d, media: %s, addr:",
+-              ioaddr/0x1000, ifmap[inb(ioaddr + NE3210_CFG2) >> 6]);
++              edev->slot, ifmap[port_index]);
+       for(i = 0; i < ETHER_ADDR_LEN; i++)
+               printk(" %02x", (dev->dev_addr[i] = inb(ioaddr + NE3210_SA_PROM + i)));
+-      printk(".\nne3210.c: ");
++      
+       /* Snarf the interrupt now. CFG file has them all listed as `edge' with share=NO */
+-      if (dev->irq == 0) {
+-              unsigned char irq_reg = inb(ioaddr + NE3210_CFG2) >> 3;
+-              dev->irq = irq_map[irq_reg & 0x07];
+-              printk("using");
+-      } else {
+-              /* This is useless unless we reprogram the card here too */
+-              if (dev->irq == 2) dev->irq = 9;        /* Doh! */
+-              printk("assigning");
+-      }
+-      printk(" IRQ %d,", dev->irq);
++      dev->irq = irq_map[(inb(ioaddr + NE3210_CFG2) >> 3) & 0x07];
++      printk(".\nne3210.c: using IRQ %d, ", dev->irq);
+       retval = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev);
+       if (retval) {
+               printk (" unable to get IRQ %d.\n", dev->irq);
+-              goto out1;
+-      }
+-
+-      if (dev->mem_start == 0) {
+-              unsigned char mem_reg = inb(ioaddr + NE3210_CFG2) & 0x07;
+-              dev->mem_start = shmem_map[mem_reg] * 0x1000;
+-              printk(" using ");
+-      } else {
+-              /* Should check for value in shmem_map and reprogram the card to use it */
+-              dev->mem_start &= 0xfff8000;
+-              printk(" assigning ");
++              goto out2;
+       }
+-      printk("%dkB memory at physical address %#lx\n",
+-                      NE3210_STOP_PG/4, dev->mem_start);
++      phys_mem = shmem_map[inb(ioaddr + NE3210_CFG2) & 0x07] * 0x1000;
+       /*
+          BEWARE!! Some dain-bramaged EISA SCUs will allow you to put
+          the card mem within the region covered by `normal' RAM  !!!
+       */
+-      if (dev->mem_start > 1024*1024) {       /* phys addr > 1MB */
+-              if (dev->mem_start < virt_to_phys(high_memory)) {
++      if (phys_mem > 1024*1024) {     /* phys addr > 1MB */
++              if (phys_mem < virt_to_phys(high_memory)) {
+                       printk(KERN_CRIT "ne3210.c: Card RAM overlaps with normal memory!!!\n");
+                       printk(KERN_CRIT "ne3210.c: Use EISA SCU to set card memory below 1MB,\n");
+                       printk(KERN_CRIT "ne3210.c: or to an address above 0x%lx.\n", virt_to_phys(high_memory));
+                       printk(KERN_CRIT "ne3210.c: Driver NOT installed.\n");
+                       retval = -EINVAL;
+-                      goto out2;
++                      goto out3;
+               }
+-              dev->mem_start = (unsigned long)ioremap(dev->mem_start, NE3210_STOP_PG*0x100);
+-              if (dev->mem_start == 0) {
+-                      printk(KERN_ERR "ne3210.c: Unable to remap card memory above 1MB !!\n");
+-                      printk(KERN_ERR "ne3210.c: Try using EISA SCU to set memory below 1MB.\n");
+-                      printk(KERN_ERR "ne3210.c: Driver NOT installed.\n");
+-                      retval = -EAGAIN;
+-                      goto out2;
+-              }
+-              ei_status.reg0 = 1;     /* Use as remap flag */
+-              printk("ne3210.c: remapped %dkB card memory to virtual address %#lx\n",
+-                              NE3210_STOP_PG/4, dev->mem_start);
+       }
++      
++      if (!request_mem_region (phys_mem, NE3210_STOP_PG*0x100, dev->name)) {
++              printk ("ne3210.c: Unable to request shared memory at physical address %#lx\n",
++                      phys_mem);
++              goto out3;
++      }
++      
++      printk("%dkB memory at physical address %#lx\n",
++             NE3210_STOP_PG/4, phys_mem);
++      dev->mem_start = (unsigned long)ioremap(phys_mem, NE3210_STOP_PG*0x100);
++      if (dev->mem_start == 0) {
++              printk(KERN_ERR "ne3210.c: Unable to remap card memory !!\n");
++              printk(KERN_ERR "ne3210.c: Driver NOT installed.\n");
++              retval = -EAGAIN;
++              goto out4;
++      }
++      printk("ne3210.c: remapped %dkB card memory to virtual address %#lx\n",
++             NE3210_STOP_PG/4, dev->mem_start);
+       dev->mem_end = ei_status.rmem_end = dev->mem_start
+               + (NE3210_STOP_PG - NE3210_START_PG)*256;
+       ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
+@@ -247,6 +199,7 @@ static int __init ne3210_probe1(struct n
+       ei_status.rx_start_page = NE3210_START_PG + TX_PAGES;
+       ei_status.stop_page = NE3210_STOP_PG;
+       ei_status.word16 = 1;
++      ei_status.priv = phys_mem;
+       if (ei_debug > 0)
+               printk(version);
+@@ -258,18 +211,46 @@ static int __init ne3210_probe1(struct n
+       dev->open = &ne3210_open;
+       dev->stop = &ne3210_close;
++      dev->if_port = ifmap_val[port_index];
++
++      if ((retval = register_netdev (dev)))
++              goto out5;
++              
+       NS8390_init(dev, 0);
+       return 0;
+-out2:
+-      free_irq(dev->irq, dev);        
+-out1:
+-      kfree(dev->priv);
+-      dev->priv = NULL;
+-out:
+-      release_region(ioaddr, NE3210_IO_EXTENT);
++
++ out5:
++      iounmap((void *)dev->mem_start);
++ out4:
++      release_mem_region (phys_mem, NE3210_STOP_PG*0x100);
++ out3:
++      free_irq (dev->irq, dev);
++ out2:
++      release_region (ioaddr + NE3210_CFG1, NE3210_CFG_EXTENT);
++ out1:
++      release_region (ioaddr, NE3210_IO_EXTENT);
++ out:
++      free_netdev (dev);
++      
+       return retval;
+ }
++static int __devexit ne3210_eisa_remove (struct device *device)
++{
++      struct net_device  *dev    = device->driver_data;
++      unsigned long       ioaddr = to_eisa_device (device)->base_addr;
++
++      unregister_netdev (dev);
++      iounmap((void *)dev->mem_start);
++      release_mem_region (ei_status.priv, NE3210_STOP_PG*0x100);
++      free_irq (dev->irq, dev);
++      release_region (ioaddr + NE3210_CFG1, NE3210_CFG_EXTENT);
++      release_region (ioaddr, NE3210_IO_EXTENT);
++      free_netdev (dev);
++
++      return 0;
++}
++
+ /*
+  *    Reset by toggling the "Board Enable" bits (bit 2 and 0).
+  */
+@@ -309,7 +290,7 @@ static void
+ ne3210_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
+ {
+       unsigned long hdr_start = dev->mem_start + ((ring_page - NE3210_START_PG)<<8);
+-      isa_memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
++      memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
+       hdr->count = (hdr->count + 3) & ~3;     /* Round up allocation. */
+ }
+@@ -327,12 +308,12 @@ static void ne3210_block_input(struct ne
+       if (xfer_start + count > ei_status.rmem_end) {
+               /* Packet wraps over end of ring buffer. */
+               int semi_count = ei_status.rmem_end - xfer_start;
+-              isa_memcpy_fromio(skb->data, xfer_start, semi_count);
++              memcpy_fromio(skb->data, xfer_start, semi_count);
+               count -= semi_count;
+-              isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
++              memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
+       } else {
+               /* Packet is in one chunk. */
+-              isa_memcpy_fromio(skb->data, xfer_start, count);
++              memcpy_fromio(skb->data, xfer_start, count);
+       }
+ }
+@@ -342,7 +323,7 @@ static void ne3210_block_output(struct n
+       unsigned long shmem = dev->mem_start + ((start_page - NE3210_START_PG)<<8);
+       count = (count + 3) & ~3;     /* Round up to doubleword */
+-      isa_memcpy_toio(shmem, buf, count);
++      memcpy_toio(shmem, buf, count);
+ }
+ static int ne3210_open(struct net_device *dev)
+@@ -361,7 +342,23 @@ static int ne3210_close(struct net_devic
+       return 0;
+ }
++static struct eisa_device_id ne3210_ids[] = {
++      { "EGL0101" },
++      { "NVL1801" },
++      { "" },
++};
++
++static struct eisa_driver ne3210_eisa_driver = {
++      .id_table = ne3210_ids,
++      .driver   = {
++              .name   = "ne3210",
++              .probe  = ne3210_eisa_probe,
++              .remove = __devexit_p (ne3210_eisa_remove),
++      },
++};
++
+ #ifdef MODULE
++#if 0
+ #define MAX_NE3210_CARDS      4       /* Max number of NE3210 cards per module */
+ static struct net_device dev_ne3210[MAX_NE3210_CARDS];
+ static int io[MAX_NE3210_CARDS];
+@@ -374,50 +371,22 @@ MODULE_PARM(mem, "1-" __MODULE_STRING(MA
+ MODULE_PARM_DESC(io, "I/O base address(es)");
+ MODULE_PARM_DESC(irq, "IRQ number(s)");
+ MODULE_PARM_DESC(mem, "memory base address(es)");
++#endif
++#endif /* MODULE */
++
++
+ MODULE_DESCRIPTION("NE3210 EISA Ethernet driver");
+ MODULE_LICENSE("GPL");
+-int init_module(void)
++int ne3210_init(void)
+ {
+-      int this_dev, found = 0;
+-
+-      for (this_dev = 0; this_dev < MAX_NE3210_CARDS; this_dev++) {
+-              struct net_device *dev = &dev_ne3210[this_dev];
+-              dev->irq = irq[this_dev];
+-              dev->base_addr = io[this_dev];
+-              dev->mem_start = mem[this_dev];
+-              dev->init = ne3210_probe;
+-              /* Default is to only install one card. */
+-              if (io[this_dev] == 0 && this_dev != 0) break;
+-              if (register_netdev(dev) != 0) {
+-                      printk(KERN_WARNING "ne3210.c: No NE3210 card found (i/o = 0x%x).\n", io[this_dev]);
+-                      if (found != 0) {       /* Got at least one. */
+-                              return 0;
+-                      }
+-                      return -ENXIO;
+-              }
+-              found++;
+-      }
+-      return 0;
++      return eisa_driver_register (&ne3210_eisa_driver);
+ }
+-void cleanup_module(void)
++void ne3210_cleanup(void)
+ {
+-      int this_dev;
+-
+-      for (this_dev = 0; this_dev < MAX_NE3210_CARDS; this_dev++) {
+-              struct net_device *dev = &dev_ne3210[this_dev];
+-              if (dev->priv != NULL) {
+-                      free_irq(dev->irq, dev);
+-                      release_region(dev->base_addr, NE3210_IO_EXTENT);
+-                      if (ei_status.reg0)
+-                              iounmap((void *)dev->mem_start);
+-                      unregister_netdev(dev);
+-                      kfree(dev->priv);
+-                      dev->priv = NULL;
+-              }
+-      }
++      eisa_driver_unregister (&ne3210_eisa_driver);
+ }
+-#endif /* MODULE */
+-
++module_init (ne3210_init);
++module_exit (ne3210_cleanup);
+--- linux-2.6.0-test6/drivers/net/sk_mca.c     2003-09-08 13:58:57.000000000 -0700
++++ 25/drivers/net/sk_mca.c    2003-10-05 00:33:24.000000000 -0700
+@@ -89,7 +89,7 @@ History:
+ #include <linux/interrupt.h>
+ #include <linux/delay.h>
+ #include <linux/time.h>
+-#include <linux/mca.h>
++#include <linux/mca-legacy.h>
+ #include <linux/init.h>
+ #include <linux/module.h>
+ #include <linux/version.h>
+--- linux-2.6.0-test6/drivers/net/slip.c       2003-09-27 18:57:45.000000000 -0700
++++ 25/drivers/net/slip.c      2003-10-05 00:36:15.000000000 -0700
+@@ -1307,7 +1307,7 @@ static int sl_ioctl(struct net_device *d
+               /* Resolve race condition, when ioctl'ing hanged up 
+                  and opened by another process device.
+                */
+-              if (sl->tty != current->tty && sl->pid != current->pid) {
++              if (sl->tty != process_tty(current) && sl->pid != current->pid) {
+                       spin_unlock_bh(&sl->lock);
+                       return -EPERM;
+               }
+--- linux-2.6.0-test6/drivers/net/Space.c      2003-09-27 18:57:45.000000000 -0700
++++ 25/drivers/net/Space.c     2003-10-05 00:33:24.000000000 -0700
+@@ -67,7 +67,6 @@ extern int elplus_probe(struct net_devic
+ extern int ac3200_probe(struct net_device *);
+ extern int es_probe(struct net_device *);
+ extern int lne390_probe(struct net_device *);
+-extern int ne3210_probe(struct net_device *);
+ extern int e2100_probe(struct net_device *);
+ extern int ni5010_probe(struct net_device *);
+ extern int ni52_probe(struct net_device *);
+@@ -155,9 +154,6 @@ static struct devprobe eisa_probes[] __i
+ #ifdef CONFIG_LNE390
+       {lne390_probe, 0},
+ #endif
+-#ifdef CONFIG_NE3210
+-      {ne3210_probe, 0},
+-#endif
+       {NULL, 0},
+ };
+@@ -480,3 +476,5 @@ void __init probe_old_netdevs(void)
+ struct net_device *dev_base;
+ rwlock_t dev_base_lock = RW_LOCK_UNLOCKED;
++EXPORT_SYMBOL(dev_base);
++EXPORT_SYMBOL(dev_base_lock);
+--- linux-2.6.0-test6/drivers/net/tlan.c       2003-09-27 18:57:45.000000000 -0700
++++ 25/drivers/net/tlan.c      2003-10-05 00:33:48.000000000 -0700
+@@ -297,6 +297,7 @@ static int TLan_ioctl( struct net_device
+ static int      TLan_probe1( struct pci_dev *pdev, long ioaddr, int irq, int rev, const struct pci_device_id *ent);
+ static void   TLan_tx_timeout( struct net_device *dev);
+ static int    tlan_init_one( struct pci_dev *pdev, const struct pci_device_id *ent);
++static void   TLan_Poll(struct net_device *dev);
+ static u32    TLan_HandleInvalid( struct net_device *, u16 );
+ static u32    TLan_HandleTxEOF( struct net_device *, u16 );
+@@ -453,6 +454,25 @@ static void __devexit tlan_remove_one( s
+       pci_set_drvdata( pdev, NULL );
+ } 
++#ifdef CONFIG_NET_POLL_CONTROLLER
++
++/*
++ * Polling 'interrupt' - used by things like netconsole to send skbs
++ * without having to re-enable interrupts. It's not called while
++ * the interrupt routine is executing.
++ */
++
++static void TLan_Poll (struct net_device *dev)
++{
++       disable_irq(dev->irq);
++       TLan_HandleInterrupt(dev->irq, dev, NULL);
++       enable_irq(dev->irq);
++}
++
++#endif
++
++
++
+ static struct pci_driver tlan_driver = {
+       .name           = "tlan",
+       .id_table       = tlan_pci_tbl,
+@@ -895,6 +915,9 @@ static int TLan_Init( struct net_device 
+       dev->do_ioctl = &TLan_ioctl;
+       dev->tx_timeout = &TLan_tx_timeout;
+       dev->watchdog_timeo = TX_TIMEOUT;
++#ifdef CONFIG_NET_POLL_CONTROLLER
++      dev->poll_controller = &TLan_Poll;
++#endif
+       return 0;
+--- linux-2.6.0-test6/drivers/net/tokenring/madgemc.c  2003-08-22 19:23:41.000000000 -0700
++++ 25/drivers/net/tokenring/madgemc.c 2003-10-05 00:33:24.000000000 -0700
+@@ -20,7 +20,7 @@
+ static const char version[] = "madgemc.c: v0.91 23/01/2000 by Adam Fritzler\n";
+ #include <linux/module.h>
+-#include <linux/mca.h>
++#include <linux/mca-legacy.h>
+ #include <linux/kernel.h>
+ #include <linux/errno.h>
+ #include <linux/pci.h>
+--- linux-2.6.0-test6/drivers/net/tokenring/smctr.c    2003-09-27 18:57:45.000000000 -0700
++++ 25/drivers/net/tokenring/smctr.c   2003-10-05 00:33:24.000000000 -0700
+@@ -43,7 +43,7 @@
+ #include <linux/errno.h>
+ #include <linux/init.h>
+ #include <linux/pci.h>
+-#include <linux/mca.h>
++#include <linux/mca-legacy.h>
+ #include <linux/delay.h>
+ #include <linux/netdevice.h>
+ #include <linux/etherdevice.h>
+--- linux-2.6.0-test6/drivers/net/tulip/interrupt.c    2003-06-14 12:18:04.000000000 -0700
++++ 25/drivers/net/tulip/interrupt.c   2003-10-05 00:36:07.000000000 -0700
+@@ -19,13 +19,13 @@
+ #include <linux/etherdevice.h>
+ #include <linux/pci.h>
+-
+ int tulip_rx_copybreak;
+ unsigned int tulip_max_interrupt_work;
+-#ifdef CONFIG_NET_HW_FLOWCONTROL
+-
++#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION
+ #define MIT_SIZE 15
++#define MIT_TABLE 15 /* We use 0 or max */
++
+ unsigned int mit_table[MIT_SIZE+1] =
+ {
+         /*  CRS11 21143 hardware Mitigation Control Interrupt
+@@ -99,16 +99,28 @@ int tulip_refill_rx(struct net_device *d
+       return refilled;
+ }
++#ifdef CONFIG_TULIP_NAPI
+-static int tulip_rx(struct net_device *dev)
++void oom_timer(unsigned long data)
++{
++        struct net_device *dev = (struct net_device *)data;
++      netif_rx_schedule(dev);
++}
++
++int tulip_poll(struct net_device *dev, int *budget)
+ {
+       struct tulip_private *tp = (struct tulip_private *)dev->priv;
+       int entry = tp->cur_rx % RX_RING_SIZE;
+-      int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx;
++      int rx_work_limit = *budget;
+       int received = 0;
+-#ifdef CONFIG_NET_HW_FLOWCONTROL
+-        int drop = 0, mit_sel = 0;
++      if (!netif_running(dev))
++              goto done;
++
++      if (rx_work_limit > dev->quota)
++              rx_work_limit = dev->quota;
++
++#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION
+ /* that one buffer is needed for mit activation; or might be a
+    bug in the ring buffer code; check later -- JHS*/
+@@ -119,6 +131,237 @@ static int tulip_rx(struct net_device *d
+       if (tulip_debug > 4)
+               printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry,
+                          tp->rx_ring[entry].status);
++
++       do {
++               /* Acknowledge current RX interrupt sources. */
++               outl((RxIntr | RxNoBuf), dev->base_addr + CSR5);
++
++
++               /* If we own the next entry, it is a new packet. Send it up. */
++               while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) {
++                       s32 status = le32_to_cpu(tp->rx_ring[entry].status);
++
++
++                       if (tp->dirty_rx + RX_RING_SIZE == tp->cur_rx)
++                               break;
++
++                       if (tulip_debug > 5)
++                               printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n",
++                                      dev->name, entry, status);
++                       if (--rx_work_limit < 0)
++                               goto not_done;
++
++                       if ((status & 0x38008300) != 0x0300) {
++                               if ((status & 0x38000300) != 0x0300) {
++                                /* Ingore earlier buffers. */
++                                       if ((status & 0xffff) != 0x7fff) {
++                                               if (tulip_debug > 1)
++                                                       printk(KERN_WARNING "%s: Oversized Ethernet frame "
++                                                              "spanned multiple buffers, status %8.8x!\n",
++                                                              dev->name, status);
++                                               tp->stats.rx_length_errors++;
++                                       }
++                               } else if (status & RxDescFatalErr) {
++                                /* There was a fatal error. */
++                                       if (tulip_debug > 2)
++                                               printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n",
++                                                      dev->name, status);
++                                       tp->stats.rx_errors++; /* end of a packet.*/
++                                       if (status & 0x0890) tp->stats.rx_length_errors++;
++                                       if (status & 0x0004) tp->stats.rx_frame_errors++;
++                                       if (status & 0x0002) tp->stats.rx_crc_errors++;
++                                       if (status & 0x0001) tp->stats.rx_fifo_errors++;
++                               }
++                       } else {
++                               /* Omit the four octet CRC from the length. */
++                               short pkt_len = ((status >> 16) & 0x7ff) - 4;
++                               struct sk_buff *skb;
++
++#ifndef final_version
++                               if (pkt_len > 1518) {
++                                       printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\n",
++                                              dev->name, pkt_len, pkt_len);
++                                       pkt_len = 1518;
++                                       tp->stats.rx_length_errors++;
++                               }
++#endif
++                               /* Check if the packet is long enough to accept without copying
++                                  to a minimally-sized skbuff. */
++                               if (pkt_len < tulip_rx_copybreak
++                                   && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
++                                       skb->dev = dev;
++                                       skb_reserve(skb, 2);    /* 16 byte align the IP header */
++                                       pci_dma_sync_single(tp->pdev,
++                                                           tp->rx_buffers[entry].mapping,
++                                                           pkt_len, PCI_DMA_FROMDEVICE);
++#if ! defined(__alpha__)
++                                       eth_copy_and_sum(skb, tp->rx_buffers[entry].skb->tail,
++                                                        pkt_len, 0);
++                                       skb_put(skb, pkt_len);
++#else
++                                       memcpy(skb_put(skb, pkt_len),
++                                              tp->rx_buffers[entry].skb->tail,
++                                              pkt_len);
++#endif
++                               } else {        /* Pass up the skb already on the Rx ring. */
++                                       char *temp = skb_put(skb = tp->rx_buffers[entry].skb,
++                                                            pkt_len);
++
++#ifndef final_version
++                                       if (tp->rx_buffers[entry].mapping !=
++                                           le32_to_cpu(tp->rx_ring[entry].buffer1)) {
++                                               printk(KERN_ERR "%s: Internal fault: The skbuff addresses "
++                                                      "do not match in tulip_rx: %08x vs. %08x %p / %p.\n",
++                                                      dev->name,
++                                                      le32_to_cpu(tp->rx_ring[entry].buffer1),
++                                                      tp->rx_buffers[entry].mapping,
++                                                      skb->head, temp);
++                                       }
++#endif
++
++                                       pci_unmap_single(tp->pdev, tp->rx_buffers[entry].mapping,
++                                                        PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
++
++                                       tp->rx_buffers[entry].skb = NULL;
++                                       tp->rx_buffers[entry].mapping = 0;
++                               }
++                               skb->protocol = eth_type_trans(skb, dev);
++
++                               netif_receive_skb(skb);
++
++                               dev->last_rx = jiffies;
++                               tp->stats.rx_packets++;
++                               tp->stats.rx_bytes += pkt_len;
++                       }
++                       received++;
++
++                       entry = (++tp->cur_rx) % RX_RING_SIZE;
++                       if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/4)
++                               tulip_refill_rx(dev);
++
++                }
++
++               /* New ack strategy... irq does not ack Rx any longer
++                  hopefully this helps */
++
++               /* Really bad things can happen here... If new packet arrives
++                * and an irq arrives (tx or just due to occasionally unset
++                * mask), it will be acked by irq handler, but new thread
++                * is not scheduled. It is major hole in design.
++                * No idea how to fix this if "playing with fire" will fail
++                * tomorrow (night 011029). If it will not fail, we won
++                * finally: amount of IO did not increase at all. */
++       } while ((inl(dev->base_addr + CSR5) & RxIntr));
++
++done:
++
++ #ifdef CONFIG_TULIP_NAPI_HW_MITIGATION
++
++          /* We use this simplistic scheme for IM. It's proven by
++             real life installations. We can have IM enabled
++            continuesly but this would cause unnecessary latency.
++            Unfortunely we can't use all the NET_RX_* feedback here.
++            This would turn on IM for devices that is not contributing
++            to backlog congestion with unnecessary latency.
++
++             We monitor the the device RX-ring and have:
++
++             HW Interrupt Mitigation either ON or OFF.
++
++            ON:  More then 1 pkt received (per intr.) OR we are dropping
++             OFF: Only 1 pkt received
++
++             Note. We only use min and max (0, 15) settings from mit_table */
++
++
++          if( tp->flags &  HAS_INTR_MITIGATION) {
++                 if( received > 1 ) {
++                         if( ! tp->mit_on ) {
++                                 tp->mit_on = 1;
++                                 outl(mit_table[MIT_TABLE], dev->base_addr + CSR11);
++                         }
++                  }
++                 else {
++                         if( tp->mit_on ) {
++                                 tp->mit_on = 0;
++                                 outl(0, dev->base_addr + CSR11);
++                         }
++                  }
++          }
++
++#endif /* CONFIG_TULIP_NAPI_HW_MITIGATION */
++
++         dev->quota -= received;
++         *budget -= received;
++
++         tulip_refill_rx(dev);
++
++         /* If RX ring is not full we are out of memory. */
++         if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) goto oom;
++
++         /* Remove us from polling list and enable RX intr. */
++
++         netif_rx_complete(dev);
++         outl(tulip_tbl[tp->chip_id].valid_intrs, dev->base_addr+CSR7);
++
++         /* The last op happens after poll completion. Which means the following:
++          * 1. it can race with disabling irqs in irq handler
++          * 2. it can race with dise/enabling irqs in other poll threads
++          * 3. if an irq raised after beginning loop, it will be immediately
++          *    triggered here.
++          *
++          * Summarizing: the logic results in some redundant irqs both
++          * due to races in masking and due to too late acking of already
++          * processed irqs. But it must not result in losing events.
++          */
++
++         return 0;
++
++ not_done:
++         if (!received) {
++
++                 received = dev->quota; /* Not to happen */
++         }
++         dev->quota -= received;
++         *budget -= received;
++
++         if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/2 ||
++             tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL)
++                 tulip_refill_rx(dev);
++
++         if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) goto oom;
++
++         return 1;
++
++
++ oom:    /* Executed with RX ints disabled */
++
++
++         /* Start timer, stop polling, but do not enable rx interrupts. */
++         mod_timer(&tp->oom_timer, jiffies+1);
++
++         /* Think: timer_pending() was an explicit signature of bug.
++          * Timer can be pending now but fired and completed
++          * before we did netif_rx_complete(). See? We would lose it. */
++
++         /* remove ourselves from the polling list */
++         netif_rx_complete(dev);
++
++         return 0;
++}
++
++#else /* CONFIG_TULIP_NAPI */
++
++static int tulip_rx(struct net_device *dev)
++{
++      struct tulip_private *tp = (struct tulip_private *)dev->priv;
++      int entry = tp->cur_rx % RX_RING_SIZE;
++      int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx;
++      int received = 0;
++
++      if (tulip_debug > 4)
++              printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry,
++                         tp->rx_ring[entry].status);
+       /* If we own the next entry, it is a new packet. Send it up. */
+       while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) {
+               s32 status = le32_to_cpu(tp->rx_ring[entry].status);
+@@ -163,11 +406,6 @@ static int tulip_rx(struct net_device *d
+                       }
+ #endif
+-#ifdef CONFIG_NET_HW_FLOWCONTROL
+-                        drop = atomic_read(&netdev_dropping);
+-                        if (drop)
+-                                goto throttle;
+-#endif
+                       /* Check if the packet is long enough to accept without copying
+                          to a minimally-sized skbuff. */
+                       if (pkt_len < tulip_rx_copybreak
+@@ -209,44 +447,9 @@ static int tulip_rx(struct net_device *d
+                               tp->rx_buffers[entry].mapping = 0;
+                       }
+                       skb->protocol = eth_type_trans(skb, dev);
+-#ifdef CONFIG_NET_HW_FLOWCONTROL
+-                        mit_sel =
+-#endif
+-                      netif_rx(skb);
+-#ifdef CONFIG_NET_HW_FLOWCONTROL
+-                        switch (mit_sel) {
+-                        case NET_RX_SUCCESS:
+-                        case NET_RX_CN_LOW:
+-                        case NET_RX_CN_MOD:
+-                                break;
+-
+-                        case NET_RX_CN_HIGH:
+-                                rx_work_limit -= NET_RX_CN_HIGH; /* additional*/
+-                                break;
+-                        case NET_RX_DROP:
+-                                rx_work_limit = -1;
+-                                break;
+-                        default:
+-                                printk("unknown feedback return code %d\n", mit_sel);
+-                                break;
+-                        }
++                      netif_rx(skb);
+-                        drop = atomic_read(&netdev_dropping);
+-                        if (drop) {
+-throttle:
+-                                rx_work_limit = -1;
+-                                mit_sel = NET_RX_DROP;
+-
+-                                if (tp->fc_bit) {
+-                                        long ioaddr = dev->base_addr;
+-
+-                                        /* disable Rx & RxNoBuf ints. */
+-                                        outl(tulip_tbl[tp->chip_id].valid_intrs&RX_A_NBF_STOP, ioaddr + CSR7);
+-                                        set_bit(tp->fc_bit, &netdev_fc_xoff);
+-                                }
+-                        }
+-#endif
+                       dev->last_rx = jiffies;
+                       tp->stats.rx_packets++;
+                       tp->stats.rx_bytes += pkt_len;
+@@ -254,42 +457,9 @@ throttle:
+               received++;
+               entry = (++tp->cur_rx) % RX_RING_SIZE;
+       }
+-#ifdef CONFIG_NET_HW_FLOWCONTROL
+-
+-        /* We use this simplistic scheme for IM. It's proven by
+-           real life installations. We can have IM enabled
+-           continuesly but this would cause unnecessary latency.
+-           Unfortunely we can't use all the NET_RX_* feedback here.
+-           This would turn on IM for devices that is not contributing
+-           to backlog congestion with unnecessary latency.
+-
+-           We monitor the device RX-ring and have:
+-
+-           HW Interrupt Mitigation either ON or OFF.
+-
+-           ON:  More then 1 pkt received (per intr.) OR we are dropping
+-           OFF: Only 1 pkt received
+-
+-           Note. We only use min and max (0, 15) settings from mit_table */
+-
+-
+-        if( tp->flags &  HAS_INTR_MITIGATION) {
+-                if((received > 1 || mit_sel == NET_RX_DROP)
+-                   && tp->mit_sel != 15 ) {
+-                        tp->mit_sel = 15;
+-                        tp->mit_change = 1; /* Force IM change */
+-                }
+-                if((received <= 1 && mit_sel != NET_RX_DROP) && tp->mit_sel != 0 ) {
+-                        tp->mit_sel = 0;
+-                        tp->mit_change = 1; /* Force IM change */
+-                }
+-        }
+-
+-        return RX_RING_SIZE+1; /* maxrx+1 */
+-#else
+       return received;
+-#endif
+ }
++#endif  /* CONFIG_TULIP_NAPI */
+ static inline unsigned int phy_interrupt (struct net_device *dev)
+ {
+@@ -323,7 +493,6 @@ irqreturn_t tulip_interrupt(int irq, voi
+       struct tulip_private *tp = (struct tulip_private *)dev->priv;
+       long ioaddr = dev->base_addr;
+       int csr5;
+-      int entry;
+       int missed;
+       int rx = 0;
+       int tx = 0;
+@@ -331,6 +500,11 @@ irqreturn_t tulip_interrupt(int irq, voi
+       int maxrx = RX_RING_SIZE;
+       int maxtx = TX_RING_SIZE;
+       int maxoi = TX_RING_SIZE;
++#ifdef CONFIG_TULIP_NAPI
++      int rxd = 0;
++#else
++      int entry;
++#endif
+       unsigned int work_count = tulip_max_interrupt_work;
+       unsigned int handled = 0;
+@@ -346,22 +520,41 @@ irqreturn_t tulip_interrupt(int irq, voi
+       tp->nir++;
+       do {
++
++#ifdef CONFIG_TULIP_NAPI
++
++              if (!rxd && (csr5 & (RxIntr | RxNoBuf))) {
++                      rxd++;
++                      /* Mask RX intrs and add the device to poll list. */
++                      outl(tulip_tbl[tp->chip_id].valid_intrs&~RxPollInt, ioaddr + CSR7);
++                      netif_rx_schedule(dev);
++
++                      if (!(csr5&~(AbnormalIntr|NormalIntr|RxPollInt|TPLnkPass)))
++                               break;
++              }
++
++               /* Acknowledge the interrupt sources we handle here ASAP
++                  the poll function does Rx and RxNoBuf acking */
++
++              outl(csr5 & 0x0001ff3f, ioaddr + CSR5);
++
++#else
+               /* Acknowledge all of the current interrupt sources ASAP. */
+               outl(csr5 & 0x0001ffff, ioaddr + CSR5);
+-              if (tulip_debug > 4)
+-                      printk(KERN_DEBUG "%s: interrupt  csr5=%#8.8x new csr5=%#8.8x.\n",
+-                                 dev->name, csr5, inl(dev->base_addr + CSR5));
+               if (csr5 & (RxIntr | RxNoBuf)) {
+-#ifdef CONFIG_NET_HW_FLOWCONTROL
+-                        if ((!tp->fc_bit) ||
+-                          (!test_bit(tp->fc_bit, &netdev_fc_xoff)))
+-#endif
+                               rx += tulip_rx(dev);
+                       tulip_refill_rx(dev);
+               }
++#endif /*  CONFIG_TULIP_NAPI */
++
++              if (tulip_debug > 4)
++                      printk(KERN_DEBUG "%s: interrupt  csr5=%#8.8x new csr5=%#8.8x.\n",
++                             dev->name, csr5, inl(dev->base_addr + CSR5));
++
++
+               if (csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt)) {
+                       unsigned int dirty_tx;
+@@ -462,15 +655,8 @@ irqreturn_t tulip_interrupt(int irq, voi
+                       }
+                       if (csr5 & RxDied) {            /* Missed a Rx frame. */
+                                 tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
+-#ifdef CONFIG_NET_HW_FLOWCONTROL
+-                              if (tp->fc_bit && !test_bit(tp->fc_bit, &netdev_fc_xoff)) {
+-                                      tp->stats.rx_errors++;
+-                                      tulip_start_rxtx(tp);
+-                              }
+-#else
+                               tp->stats.rx_errors++;
+                               tulip_start_rxtx(tp);
+-#endif
+                       }
+                       /*
+                        * NB: t21142_lnk_change() does a del_timer_sync(), so be careful if this
+@@ -504,10 +690,6 @@ irqreturn_t tulip_interrupt(int irq, voi
+                       if (tulip_debug > 2)
+                               printk(KERN_ERR "%s: Re-enabling interrupts, %8.8x.\n",
+                                          dev->name, csr5);
+-#ifdef CONFIG_NET_HW_FLOWCONTROL
+-                        if (tp->fc_bit && (test_bit(tp->fc_bit, &netdev_fc_xoff)))
+-                          if (net_ratelimit()) printk("BUG!! enabling interrupt when FC off (timerintr.) \n");
+-#endif
+                       outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
+                       tp->ttimer = 0;
+                       oi++;
+@@ -520,16 +702,9 @@ irqreturn_t tulip_interrupt(int irq, voi
+                        /* Acknowledge all interrupt sources. */
+                         outl(0x8001ffff, ioaddr + CSR5);
+                         if (tp->flags & HAS_INTR_MITIGATION) {
+-#ifdef CONFIG_NET_HW_FLOWCONTROL
+-                                if(tp->mit_change) {
+-                                        outl(mit_table[tp->mit_sel], ioaddr + CSR11);
+-                                        tp->mit_change = 0;
+-                                }
+-#else
+                      /* Josip Loncaric at ICASE did extensive experimentation
+                       to develop a good interrupt mitigation setting.*/
+                                 outl(0x8b240000, ioaddr + CSR11);
+-#endif
+                         } else if (tp->chip_id == LC82C168) {
+                               /* the LC82C168 doesn't have a hw timer.*/
+                               outl(0x00, ioaddr + CSR7);
+@@ -537,10 +712,8 @@ irqreturn_t tulip_interrupt(int irq, voi
+                       } else {
+                           /* Mask all interrupting sources, set timer to
+                               re-enable. */
+-#ifndef CONFIG_NET_HW_FLOWCONTROL
+                                 outl(((~csr5) & 0x0001ebef) | AbnormalIntr | TimerInt, ioaddr + CSR7);
+                                 outl(0x0012, ioaddr + CSR11);
+-#endif
+                         }
+                       break;
+               }
+@@ -550,6 +723,21 @@ irqreturn_t tulip_interrupt(int irq, voi
+                       break;
+               csr5 = inl(ioaddr + CSR5);
++
++#ifdef CONFIG_TULIP_NAPI
++              if (rxd)
++                      csr5 &= ~RxPollInt;
++      } while ((csr5 & (TxNoBuf |
++                        TxDied |
++                        TxIntr |
++                        TimerInt |
++                        /* Abnormal intr. */
++                        RxDied |
++                        TxFIFOUnderflow |
++                        TxJabber |
++                        TPLnkFail |
++                        SytemError )) != 0);
++#else
+       } while ((csr5 & (NormalIntr|AbnormalIntr)) != 0);
+       tulip_refill_rx(dev);
+@@ -574,6 +762,7 @@ irqreturn_t tulip_interrupt(int irq, voi
+                       }
+               }
+       }
++#endif /* CONFIG_TULIP_NAPI */
+       if ((missed = inl(ioaddr + CSR8) & 0x1ffff)) {
+               tp->stats.rx_dropped += missed & 0x10000 ? 0x10000 : missed;
+--- linux-2.6.0-test6/drivers/net/tulip/Kconfig        2003-09-27 18:57:45.000000000 -0700
++++ 25/drivers/net/tulip/Kconfig       2003-10-05 00:34:49.000000000 -0700
+@@ -68,6 +68,26 @@ config TULIP_MMIO
+         obscure bugs if your mainboard has memory controller timing issues.
+         If in doubt, say N.
++config TULIP_NAPI
++      bool "Use NAPI RX polling "
++      depends on TULIP
++      ---help---
++        This is of useful for servers and routers dealing with high network loads.
++
++        See <file:Documentation/networking/NAPI_HOWTO.txt>.
++
++        If in doubt, say N.
++
++config TULIP_NAPI_HW_MITIGATION
++      bool "Use Interrupt Mitigation "
++      depends on TULIP_NAPI
++      ---help---
++        Use HW to reduce RX interrupts. Not strict necessary since NAPI reduces
++        RX interrupts but itself. Although this reduces RX interrupts even at
++        low levels traffic at the cost of a small latency.
++
++        If in doubt, say Y.
++
+ config DE4X5
+       tristate "Generic DECchip & DIGITAL EtherWORKS PCI/EISA"
+       depends on NET_TULIP && (PCI || EISA)
+--- linux-2.6.0-test6/drivers/net/tulip/tulip_core.c   2003-08-22 19:23:41.000000000 -0700
++++ 25/drivers/net/tulip/tulip_core.c  2003-10-05 00:34:49.000000000 -0700
+@@ -14,11 +14,17 @@
+ */
++#include <linux/config.h>
++
+ #define DRV_NAME      "tulip"
++#ifdef CONFIG_TULIP_NAPI
++#define DRV_VERSION    "1.1.13-NAPI" /* Keep at least for test */
++#else
+ #define DRV_VERSION   "1.1.13"
++#endif
+ #define DRV_RELDATE   "May 11, 2002"
+-#include <linux/config.h>
++
+ #include <linux/module.h>
+ #include "tulip.h"
+ #include <linux/pci.h>
+@@ -246,6 +252,7 @@ static void tulip_down(struct net_device
+ static struct net_device_stats *tulip_get_stats(struct net_device *dev);
+ static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+ static void set_rx_mode(struct net_device *dev);
++static void poll_tulip(struct net_device *dev);
+@@ -465,29 +472,16 @@ media_picked:
+          to an alternate media type. */
+       tp->timer.expires = RUN_AT(next_tick);
+       add_timer(&tp->timer);
+-}
+-
+-#ifdef CONFIG_NET_HW_FLOWCONTROL
+-/* Enable receiver */
+-void tulip_xon(struct net_device *dev)
+-{
+-        struct tulip_private *tp = (struct tulip_private *)dev->priv;
+-
+-        clear_bit(tp->fc_bit, &netdev_fc_xoff);
+-        if (netif_running(dev)){
+-
+-                tulip_refill_rx(dev);
+-                outl(tulip_tbl[tp->chip_id].valid_intrs,  dev->base_addr+CSR7);
+-        }
+-}
++#ifdef CONFIG_TULIP_NAPI
++      init_timer(&tp->oom_timer);
++        tp->oom_timer.data = (unsigned long)dev;
++        tp->oom_timer.function = oom_timer;
+ #endif
++}
+ static int
+ tulip_open(struct net_device *dev)
+ {
+-#ifdef CONFIG_NET_HW_FLOWCONTROL
+-        struct tulip_private *tp = (struct tulip_private *)dev->priv;
+-#endif
+       int retval;
+       if ((retval = request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev)))
+@@ -497,10 +491,6 @@ tulip_open(struct net_device *dev)
+       tulip_up (dev);
+-#ifdef CONFIG_NET_HW_FLOWCONTROL
+-        tp->fc_bit = netdev_register_fc(dev, tulip_xon);
+-#endif
+-
+       netif_start_queue (dev);
+       return 0;
+@@ -581,10 +571,7 @@ static void tulip_tx_timeout(struct net_
+ #endif
+       /* Stop and restart the chip's Tx processes . */
+-#ifdef CONFIG_NET_HW_FLOWCONTROL
+-        if (tp->fc_bit && test_bit(tp->fc_bit,&netdev_fc_xoff))
+-                printk("BUG tx_timeout restarting rx when fc on\n");
+-#endif
++
+       tulip_restart_rxtx(tp);
+       /* Trigger an immediate transmit demand. */
+       outl(0, ioaddr + CSR1);
+@@ -741,7 +728,9 @@ static void tulip_down (struct net_devic
+       unsigned long flags;
+       del_timer_sync (&tp->timer);
+-
++#ifdef CONFIG_TULIP_NAPI
++      del_timer_sync (&tp->oom_timer);
++#endif
+       spin_lock_irqsave (&tp->lock, flags);
+       /* Disable interrupts by clearing the interrupt mask. */
+@@ -780,13 +769,6 @@ static int tulip_close (struct net_devic
+       netif_stop_queue (dev);
+-#ifdef CONFIG_NET_HW_FLOWCONTROL
+-        if (tp->fc_bit) {
+-                int bit = tp->fc_bit;
+-                tp->fc_bit = 0;
+-                netdev_unregister_fc(bit);
+-        }
+-#endif
+       tulip_down (dev);
+       if (tulip_debug > 1)
+@@ -1627,10 +1609,17 @@ static int __devinit tulip_init_one (str
+       dev->hard_start_xmit = tulip_start_xmit;
+       dev->tx_timeout = tulip_tx_timeout;
+       dev->watchdog_timeo = TX_TIMEOUT;
++#ifdef CONFIG_TULIP_NAPI
++      dev->poll = tulip_poll;
++      dev->weight = 16;
++#endif
+       dev->stop = tulip_close;
+       dev->get_stats = tulip_get_stats;
+       dev->do_ioctl = private_ioctl;
+       dev->set_multicast_list = set_rx_mode;
++#ifdef CONFIG_NET_POLL_CONTROLLER
++      dev->poll_controller = &poll_tulip;
++#endif
+       if (register_netdev(dev))
+               goto err_out_free_ring;
+@@ -1788,6 +1777,24 @@ static void __devexit tulip_remove_one (
+ }
++#ifdef CONFIG_NET_POLL_CONTROLLER
++
++/*
++ * Polling 'interrupt' - used by things like netconsole to send skbs
++ * without having to re-enable interrupts. It's not called while
++ * the interrupt routine is executing.
++ */
++
++static void poll_tulip (struct net_device *dev)
++{
++       disable_irq(dev->irq);
++       tulip_interrupt (dev->irq, dev, NULL);
++       enable_irq(dev->irq);
++}
++
++#endif
++
++
+ static struct pci_driver tulip_driver = {
+       .name           = DRV_NAME,
+       .id_table       = tulip_pci_tbl,
+--- linux-2.6.0-test6/drivers/net/tulip/tulip.h        2003-06-14 12:18:34.000000000 -0700
++++ 25/drivers/net/tulip/tulip.h       2003-10-05 00:34:49.000000000 -0700
+@@ -126,6 +126,7 @@ enum pci_cfg_driver_reg {
+       CFDD_Snooze = (1 << 30),
+ };
++#define RxPollInt (RxIntr|RxNoBuf|RxDied|RxJabber)
+ /* The bits in the CSR5 status registers, mostly interrupt sources. */
+ enum status_bits {
+@@ -251,9 +252,9 @@ enum t21143_csr6_bits {
+    Making the Tx ring too large decreases the effectiveness of channel
+    bonding and packet priority.
+    There are no ill effects from too-large receive rings. */
+-#define TX_RING_SIZE  16
+-#define RX_RING_SIZE  32
++#define TX_RING_SIZE  32
++#define RX_RING_SIZE  128
+ #define MEDIA_MASK     31
+ #define PKT_BUF_SZ            1536    /* Size of each temporary Rx buffer. */
+@@ -343,17 +344,15 @@ struct tulip_private {
+       int flags;
+       struct net_device_stats stats;
+       struct timer_list timer;        /* Media selection timer. */
++      struct timer_list oom_timer;    /* Out of memory timer. */
+       u32 mc_filter[2];
+       spinlock_t lock;
+       spinlock_t mii_lock;
+       unsigned int cur_rx, cur_tx;    /* The next free ring entry */
+       unsigned int dirty_rx, dirty_tx;        /* The ring entries to be free()ed. */
+-#ifdef CONFIG_NET_HW_FLOWCONTROL
+-#define RX_A_NBF_STOP 0xffffff3f /* To disable RX and RX-NOBUF ints. */
+-        int fc_bit;
+-        int mit_sel;
+-        int mit_change; /* Signal for Interrupt Mitigtion */
++#ifdef        CONFIG_TULIP_NAPI_HW_MITIGATION
++        int mit_on;
+ #endif
+       unsigned int full_duplex:1;     /* Full-duplex operation requested. */
+       unsigned int full_duplex_lock:1;
+@@ -415,6 +414,10 @@ extern unsigned int tulip_max_interrupt_
+ extern int tulip_rx_copybreak;
+ irqreturn_t tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+ int tulip_refill_rx(struct net_device *dev);
++#ifdef CONFIG_TULIP_NAPI
++int tulip_poll(struct net_device *dev, int *budget);
++#endif
++
+ /* media.c */
+ int tulip_mdio_read(struct net_device *dev, int phy_id, int location);
+@@ -438,6 +441,7 @@ extern int tulip_debug;
+ extern const char * const medianame[];
+ extern const char tulip_media_cap[];
+ extern struct tulip_chip_table tulip_tbl[];
++void oom_timer(unsigned long data);
+ extern u8 t21040_csr13[];
+ #ifndef USE_IO_OPS
+--- linux-2.6.0-test6/drivers/net/wan/comx-hw-munich.c 2003-09-27 18:57:45.000000000 -0700
++++ 25/drivers/net/wan/comx-hw-munich.c        2003-10-05 00:33:24.000000000 -0700
+@@ -1849,7 +1849,7 @@ static int MUNICH_open(struct net_device
+     if (board->isx21)
+     {
+       init_timer(&board->modemline_timer);
+-      board->modemline_timer.data = (unsigned int)board;
++      board->modemline_timer.data = (unsigned long)board;
+       board->modemline_timer.function = pcicom_modemline;
+       board->modemline_timer.expires = jiffies + HZ;
+       add_timer((struct timer_list *)&board->modemline_timer);
+--- linux-2.6.0-test6/drivers/net/wan/dscc4.c  2003-09-27 18:57:45.000000000 -0700
++++ 25/drivers/net/wan/dscc4.c 2003-10-05 00:36:13.000000000 -0700
+@@ -107,7 +107,7 @@
+ #include <linux/hdlc.h>
+ /* Version */
+-static const char version[] = "$Id: 2.6.0-test6-mm4.patch,v 1.1.4.1 2003/10/10 09:31:08 ericm Exp $ for Linux\n";
++static const char version[] = "$Id: 2.6.0-test6-mm4.patch,v 1.1.4.1 2003/10/10 09:31:08 ericm Exp $ for Linux\n";
+ static int debug;
+ static int quartz;
+@@ -592,6 +592,7 @@ static inline int dscc4_xpr_ack(struct d
+       return (i >= 0 ) ? i : -EAGAIN;
+ }
++#if 0 /* dscc4_{rx/tx}_reset are both unreliable - more tweak needed */
+ static void dscc4_rx_reset(struct dscc4_dev_priv *dpriv, struct net_device *dev)
+ {
+       unsigned long flags;
+@@ -606,6 +607,9 @@ static void dscc4_rx_reset(struct dscc4_
+       spin_unlock_irqrestore(&dpriv->pci_priv->lock, flags);
+ }
++#endif
++
++#if 0
+ static void dscc4_tx_reset(struct dscc4_dev_priv *dpriv, struct net_device *dev)
+ {
+       u16 i = 0;
+@@ -625,6 +629,7 @@ static void dscc4_tx_reset(struct dscc4_
+       if (dscc4_do_action(dev, "Rdt") < 0)
+               printk(KERN_ERR "%s: Tx reset failed\n", dev->name);
+ }
++#endif
+ /* TODO: (ab)use this function to refill a completely depleted RX ring. */
+ static inline void dscc4_rx_skb(struct dscc4_dev_priv *dpriv,
+@@ -859,7 +864,7 @@ static int dscc4_found1(struct pci_dev *
+ {
+       struct dscc4_pci_priv *ppriv;
+       struct dscc4_dev_priv *root;
+-      int i = 0;
++      int i, ret = -ENOMEM;
+       root = (struct dscc4_dev_priv *)
+               kmalloc(dev_per_card*sizeof(*root), GFP_KERNEL);
+@@ -900,7 +905,8 @@ static int dscc4_found1(struct pci_dev *
+               hdlc->xmit = dscc4_start_xmit;
+               hdlc->attach = dscc4_hdlc_attach;
+-              if (register_hdlc_device(hdlc)) {
++              ret = register_hdlc_device(hdlc);
++              if (ret < 0) {
+                       printk(KERN_ERR "%s: unable to register\n", DRV_NAME);
+                       goto err_unregister;
+               }
+@@ -908,17 +914,20 @@ static int dscc4_found1(struct pci_dev *
+               dscc4_init_registers(dpriv, d);
+               dpriv->parity = PARITY_CRC16_PR0_CCITT;
+               dpriv->encoding = ENCODING_NRZ;
+-              if (dscc4_init_ring(d)) {
++
++              ret = dscc4_init_ring(d);
++              if (ret < 0) {
+                       unregister_hdlc_device(hdlc);
+                       goto err_unregister;
+               }
+       }
+-      if (dscc4_set_quartz(root, quartz) < 0)
++      ret = dscc4_set_quartz(root, quartz);
++      if (ret < 0)
+               goto err_unregister;
+       ppriv->root = root;
+       spin_lock_init(&ppriv->lock);
+       pci_set_drvdata(pdev, ppriv);
+-      return 0;
++      return ret;
+ err_unregister:
+       while (--i >= 0) {
+@@ -929,7 +938,7 @@ err_unregister:
+ err_free_dev:
+       kfree(root);
+ err_out:
+-      return -1;
++      return ret;
+ };
+ /* FIXME: get rid of the unneeded code */
+@@ -1092,9 +1101,7 @@ done:
+ err_disable_scc_events:
+       scc_writel(0xffffffff, dpriv, dev, IMR);
+-err_free_ring:
+       scc_patchl(PowerUp | Vis, 0, dpriv, dev, CCR0);
+-      dscc4_release_ring(dpriv);
+ err_out:
+       hdlc_close(hdlc);
+ err:
+@@ -1160,7 +1167,6 @@ static int dscc4_close(struct net_device
+       dpriv->flags |= FakeReset;
+       hdlc_close(hdlc);
+-      dscc4_release_ring(dpriv);
+       return 0;
+ }
+@@ -2006,6 +2012,7 @@ static int dscc4_hdlc_attach(hdlc_device
+       return 0;
+ }
++#ifndef MODULE
+ static int __init dscc4_setup(char *str)
+ {
+       int *args[] = { &debug, &quartz, NULL }, **p = args;
+@@ -2016,6 +2023,7 @@ static int __init dscc4_setup(char *str)
+ }
+ __setup("dscc4.setup=", dscc4_setup);
++#endif
+ static struct pci_device_id dscc4_pci_tbl[] = {
+       { PCI_VENDOR_ID_SIEMENS, PCI_DEVICE_ID_SIEMENS_DSCC4,
+--- linux-2.6.0-test6/drivers/net/wan/sbni.c   2003-09-27 18:57:45.000000000 -0700
++++ 25/drivers/net/wan/sbni.c  2003-10-05 00:33:24.000000000 -0700
+@@ -1300,12 +1300,9 @@ sbni_ioctl( struct net_device  *dev,  st
+   
+       switch( cmd ) {
+       case  SIOCDEVGETINSTATS :
+-              error = verify_area( VERIFY_WRITE, ifr->ifr_data,
+-                                   sizeof(struct sbni_in_stats) );
+-              if( !error )
+-                      if (copy_to_user( ifr->ifr_data, &nl->in_stats,
+-                                    sizeof(struct sbni_in_stats) ))
+-                              return -EFAULT;
++              if (copy_to_user( ifr->ifr_data, &nl->in_stats,
++                                      sizeof(struct sbni_in_stats) ))
++                      error = -EFAULT;
+               break;
+       case  SIOCDEVRESINSTATS :
+@@ -1321,11 +1318,8 @@ sbni_ioctl( struct net_device  *dev,  st
+               flags.rxl       = nl->cur_rxl_index;
+               flags.fixed_rxl = nl->delta_rxl == 0;
+-              error = verify_area( VERIFY_WRITE, ifr->ifr_data,
+-                                   sizeof flags );
+-              if( !error )
+-                      if (copy_to_user( ifr->ifr_data, &flags, sizeof flags ))
+-                              return -EFAULT;
++              if (copy_to_user( ifr->ifr_data, &flags, sizeof flags ))
++                      error = -EFAULT;
+               break;
+       case  SIOCDEVSHWSTATE :
+@@ -1353,10 +1347,6 @@ sbni_ioctl( struct net_device  *dev,  st
+               if( current->euid != 0 )        /* root only */
+                       return  -EPERM;
+-              if( (error = verify_area( VERIFY_READ, ifr->ifr_data,
+-                                        sizeof slave_name )) != 0 )
+-                      return  error;
+-
+               if (copy_from_user( slave_name, ifr->ifr_data, sizeof slave_name ))
+                       return -EFAULT;
+               slave_dev = dev_get_by_name( slave_name );
+--- linux-2.6.0-test6/drivers/net/wan/syncppp.c        2003-09-27 18:57:45.000000000 -0700
++++ 25/drivers/net/wan/syncppp.c       2003-10-05 00:33:24.000000000 -0700
+@@ -236,7 +236,7 @@ void sppp_input (struct net_device *dev,
+               sp->ipkts++;
+       }
+-      if (skb->len <= PPP_HEADER_LEN) {
++      if (!pskb_may_pull(skb, PPP_HEADER_LEN)) {
+               /* Too small packet, drop it. */
+               if (sp->pp_flags & PP_DEBUG)
+                       printk (KERN_DEBUG "%s: input packet is too small, %d bytes\n",
+@@ -473,7 +473,7 @@ static void sppp_lcp_input (struct sppp 
+       u8 *p, opt[6];
+       u32 rmagic;
+-      if (len < 4) {
++      if (!pskb_may_pull(skb, sizeof(struct lcp_header))) {
+               if (sp->pp_flags & PP_DEBUG)
+                       printk (KERN_WARNING "%s: invalid lcp packet length: %d bytes\n",
+                               dev->name, len);
+@@ -707,7 +707,9 @@ static void sppp_cisco_input (struct spp
+       struct cisco_packet *h;
+       struct net_device *dev = sp->pp_if;
+-      if (skb->len != CISCO_PACKET_LEN && skb->len != CISCO_BIG_PACKET_LEN) {
++      if (!pskb_may_pull(skb, sizeof(struct cisco_packet))
++          || (skb->len != CISCO_PACKET_LEN
++              && skb->len != CISCO_BIG_PACKET_LEN)) {
+               if (sp->pp_flags & PP_DEBUG)
+                       printk (KERN_WARNING "%s: invalid cisco packet length: %d bytes\n",
+                               dev->name,  skb->len);
+@@ -1211,8 +1213,7 @@ static void sppp_ipcp_input (struct sppp
+       struct net_device *dev = sp->pp_if;
+       int len = skb->len;
+-      if (len < 4) 
+-      {
++      if (!pskb_may_pull(skb, sizeof(struct lcp_header))) {
+               if (sp->pp_flags & PP_DEBUG)
+                       printk (KERN_WARNING "%s: invalid ipcp packet length: %d bytes\n",
+                               dev->name,  len);
+--- linux-2.6.0-test6/drivers/net/wireless/arlan-main.c        2003-09-27 18:57:45.000000000 -0700
++++ 25/drivers/net/wireless/arlan-main.c       2003-10-05 00:33:24.000000000 -0700
+@@ -5,7 +5,6 @@
+  * This module provides support for the Arlan 655 card made by Aironet
+  */
+-#include <linux/version.h>
+ #include <linux/config.h>
+ #include "arlan.h"
+@@ -721,9 +720,9 @@ static int arlan_hw_tx(struct net_device
+       else
+       {
+               netif_stop_queue (dev);
+-              return -1;
+               IFDEBUG(ARLAN_DEBUG_TX_CHAIN)
+                       printk(KERN_ERR "TX TAIL & HEAD full, return, tailStart %d headEnd %d\n", tailStarts, headEnds);
++              return -1;
+       }
+       priv->out_bytes += length;
+       priv->out_bytes10 += length;
+@@ -1881,6 +1880,8 @@ int __init arlan_probe(struct net_device
+ #ifdef  MODULE
++static int probe = probeUNKNOWN;
++
+ static int __init arlan_find_devices(void)
+ {
+       int m;
+--- linux-2.6.0-test6/drivers/parisc/superio.c 2003-08-08 22:55:12.000000000 -0700
++++ 25/drivers/parisc/superio.c        2003-10-05 00:33:24.000000000 -0700
+@@ -530,11 +530,6 @@ static struct pci_driver superio_driver 
+ static int __init superio_modinit(void)
+ {
+-#ifdef CONFIG_SERIAL_8250
+-      extern int serial8250_init(void);
+-      serial8250_init();
+-#endif
+-
+       return pci_module_init(&superio_driver);
+ }
+@@ -543,5 +538,10 @@ static void __exit superio_exit(void)
+       pci_unregister_driver(&superio_driver);
+ }
+-module_init(superio_modinit);
++/* Make late initcall to ensure the serial and tty layers are initialised
++ * before we start superio.
++ *
++ * FIXME: does this break the superio console?
++ */
++late_initcall(superio_modinit);
+ module_exit(superio_exit);
+--- linux-2.6.0-test6/drivers/pci/hotplug/cpqphp.h     2003-09-27 18:57:45.000000000 -0700
++++ 25/drivers/pci/hotplug/cpqphp.h    2003-10-05 00:33:24.000000000 -0700
+@@ -766,7 +766,6 @@ static inline int wait_for_ctrl_irq (str
+       set_current_state(TASK_INTERRUPTIBLE);
+       /* Sleep for up to 1 second to wait for the LED to change. */
+       schedule_timeout(1*HZ);
+-      set_current_state(TASK_RUNNING);
+       remove_wait_queue(&ctrl->queue, &wait);
+       if (signal_pending(current))
+               retval =  -EINTR;
+--- linux-2.6.0-test6/drivers/pci/hotplug/pci_hotplug_core.c   2003-09-27 18:57:45.000000000 -0700
++++ 25/drivers/pci/hotplug/pci_hotplug_core.c  2003-10-05 00:33:24.000000000 -0700
+@@ -69,7 +69,7 @@ static int debug;
+ static LIST_HEAD(pci_hotplug_slot_list);
+-static struct subsystem hotplug_slots_subsys;
++struct subsystem pci_hotplug_slots_subsys;
+ static ssize_t hotplug_slot_attr_show(struct kobject *kobj,
+               struct attribute *attr, char *buf)
+@@ -104,7 +104,7 @@ static struct kobj_type hotplug_slot_kty
+       .release = &hotplug_slot_release,
+ };
+-static decl_subsys(hotplug_slots, &hotplug_slot_ktype, NULL);
++decl_subsys(pci_hotplug_slots, &hotplug_slot_ktype, NULL);
+ /* these strings match up with the values in pci_bus_speed */
+@@ -534,7 +534,7 @@ int pci_hp_register (struct hotplug_slot
+               return -EINVAL;
+       strlcpy(slot->kobj.name, slot->name, KOBJ_NAME_LEN);
+-      kobj_set_kset_s(slot, hotplug_slots_subsys);
++      kobj_set_kset_s(slot, pci_hotplug_slots_subsys);
+       /* this can fail if we have already registered a slot with the same name */
+       if (kobject_register(&slot->kobj)) {
+@@ -629,8 +629,8 @@ static int __init pci_hotplug_init (void
+ {
+       int result;
+-      kset_set_kset_s(&hotplug_slots_subsys, pci_bus_type.subsys);
+-      result = subsystem_register(&hotplug_slots_subsys);
++      kset_set_kset_s(&pci_hotplug_slots_subsys, pci_bus_type.subsys);
++      result = subsystem_register(&pci_hotplug_slots_subsys);
+       if (result) {
+               err("Register subsys with error %d\n", result);
+               goto exit;
+@@ -645,7 +645,7 @@ static int __init pci_hotplug_init (void
+       goto exit;
+       
+ err_subsys:
+-      subsystem_unregister(&hotplug_slots_subsys);
++      subsystem_unregister(&pci_hotplug_slots_subsys);
+ exit:
+       return result;
+ }
+@@ -653,7 +653,7 @@ exit:
+ static void __exit pci_hotplug_exit (void)
+ {
+       cpci_hotplug_exit();
+-      subsystem_unregister(&hotplug_slots_subsys);
++      subsystem_unregister(&pci_hotplug_slots_subsys);
+ }
+ module_init(pci_hotplug_init);
+@@ -665,6 +665,7 @@ MODULE_LICENSE("GPL");
+ MODULE_PARM(debug, "i");
+ MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
++EXPORT_SYMBOL_GPL(pci_hotplug_slots_subsys);
+ EXPORT_SYMBOL_GPL(pci_hp_register);
+ EXPORT_SYMBOL_GPL(pci_hp_deregister);
+ EXPORT_SYMBOL_GPL(pci_hp_change_slot_info);
+--- linux-2.6.0-test6/drivers/pci/hotplug/pci_hotplug.h        2003-09-27 18:57:45.000000000 -0700
++++ 25/drivers/pci/hotplug/pci_hotplug.h       2003-10-05 00:33:24.000000000 -0700
+@@ -145,6 +145,7 @@ extern int pci_hp_register         (struct hotp
+ extern int pci_hp_deregister          (struct hotplug_slot *slot);
+ extern int pci_hp_change_slot_info    (struct hotplug_slot *slot,
+                                        struct hotplug_slot_info *info);
++extern struct subsystem pci_hotplug_slots_subsys;
+ #endif
+--- linux-2.6.0-test6/drivers/pci/Makefile     2003-07-27 12:14:39.000000000 -0700
++++ 25/drivers/pci/Makefile    2003-10-05 00:36:20.000000000 -0700
+@@ -4,7 +4,6 @@
+ obj-y         += access.o bus.o probe.o remove.o pci.o pool.o quirks.o \
+                       names.o pci-driver.o search.o pci-sysfs.o
+-obj-$(CONFIG_PM)  += power.o
+ obj-$(CONFIG_PROC_FS) += proc.o
+ ifndef CONFIG_SPARC64
+@@ -28,6 +27,7 @@ obj-$(CONFIG_PPC64) += setup-bus.o
+ obj-$(CONFIG_SGI_IP27) += setup-irq.o
+ obj-$(CONFIG_SGI_IP32) += setup-irq.o
+ obj-$(CONFIG_X86_VISWS) += setup-irq.o
++obj-$(CONFIG_PCI_USE_VECTOR) += msi.o
+ # Cardbus & CompactPCI use setup-bus
+ obj-$(CONFIG_HOTPLUG) += setup-bus.o
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/drivers/pci/msi.c       2003-10-05 00:36:21.000000000 -0700
+@@ -0,0 +1,1062 @@
++/*
++ * linux/drivers/pci/msi.c
++ */
++
++#include <linux/mm.h>
++#include <linux/irq.h>
++#include <linux/interrupt.h>
++#include <linux/init.h>
++#include <linux/config.h>
++#include <linux/ioport.h>
++#include <linux/smp_lock.h>
++#include <linux/pci.h>
++#include <linux/proc_fs.h>
++#include <linux/acpi.h>
++
++#include <asm/errno.h>
++#include <asm/io.h>
++#include <asm/smp.h>
++#include <asm/desc.h>
++#include <asm/io_apic.h>
++#include <mach_apic.h>
++
++#include <linux/pci_msi.h>
++
++_DEFINE_DBG_BUFFER
++
++static spinlock_t msi_lock = SPIN_LOCK_UNLOCKED;
++static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL };
++static kmem_cache_t* msi_cachep;
++
++static int pci_msi_enable = 1;
++static int nr_alloc_vectors = 0;
++static int nr_released_vectors = 0;
++static int nr_reserved_vectors = NR_HP_RESERVED_VECTORS;
++static int nr_msix_devices = 0;
++
++#ifndef CONFIG_X86_IO_APIC
++int vector_irq[NR_IRQS] = { [0 ... NR_IRQS -1] = -1};
++int irq_vector[NR_IRQS] = { FIRST_DEVICE_VECTOR , 0 };
++#endif
++
++static void msi_cache_ctor(void *p, kmem_cache_t *cache, unsigned long flags)
++{
++      memset(p, 0, NR_IRQS * sizeof(struct msi_desc));
++}
++
++static int msi_cache_init(void)
++{
++      msi_cachep = kmem_cache_create("msi_cache",
++                      NR_IRQS * sizeof(struct msi_desc),
++                      0, SLAB_HWCACHE_ALIGN, msi_cache_ctor, NULL);
++      if (!msi_cachep)
++              return -ENOMEM;
++
++      return 0;
++}
++
++static void msi_set_mask_bit(unsigned int vector, int flag)
++{
++      struct msi_desc *entry;
++
++      entry = (struct msi_desc *)msi_desc[vector];
++      if (!entry || !entry->dev || !entry->mask_base)
++              return;
++      switch (entry->msi_attrib.type) {
++      case PCI_CAP_ID_MSI:
++      {
++              int             pos;
++              unsigned int    mask_bits;
++
++              pos = entry->mask_base;
++              entry->dev->bus->ops->read(entry->dev->bus, entry->dev->devfn,
++                              pos, 4, &mask_bits);
++              mask_bits &= ~(1);
++              mask_bits |= flag;
++              entry->dev->bus->ops->write(entry->dev->bus, entry->dev->devfn,
++                              pos, 4, mask_bits);
++              break;
++      }
++      case PCI_CAP_ID_MSIX:
++      {
++              int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
++                      PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET;
++              writel(flag, entry->mask_base + offset);
++              break;
++      }
++      default:
++              break;
++      }
++}
++
++#ifdef CONFIG_SMP
++static void set_msi_affinity(unsigned int vector, unsigned long cpu_mask)
++{
++      struct msi_desc *entry;
++      struct msg_address address;
++      unsigned int dest_id;
++
++      entry = (struct msi_desc *)msi_desc[vector];
++      if (!entry || !entry->dev)
++              return;
++
++      switch (entry->msi_attrib.type) {
++      case PCI_CAP_ID_MSI:
++      {
++              int pos;
++
++              if (!(pos = pci_find_capability(entry->dev, PCI_CAP_ID_MSI)))
++                      return;
++
++              entry->dev->bus->ops->read(entry->dev->bus, entry->dev->devfn,
++                      msi_lower_address_reg(pos), 4,
++                      &address.lo_address.value);
++              dest_id = (address.lo_address.u.dest_id &
++                      MSI_ADDRESS_HEADER_MASK) |
++                      (cpu_mask_to_apicid(cpu_mask) << MSI_TARGET_CPU_SHIFT);
++              address.lo_address.u.dest_id = dest_id;
++              entry->msi_attrib.current_cpu = cpu_mask_to_apicid(cpu_mask);
++              entry->dev->bus->ops->write(entry->dev->bus, entry->dev->devfn,
++                      msi_lower_address_reg(pos), 4,
++                      address.lo_address.value);
++              break;
++      }
++      case PCI_CAP_ID_MSIX:
++      {
++              int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
++                      PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET;
++
++              address.lo_address.value = readl(entry->mask_base + offset);
++              dest_id = (address.lo_address.u.dest_id &
++                      MSI_ADDRESS_HEADER_MASK) |
++                      (cpu_mask_to_apicid(cpu_mask) << MSI_TARGET_CPU_SHIFT);
++              address.lo_address.u.dest_id = dest_id;
++              entry->msi_attrib.current_cpu = cpu_mask_to_apicid(cpu_mask);
++              writel(address.lo_address.value, entry->mask_base + offset);
++              break;
++      }
++      default:
++              break;
++      }
++}
++
++static inline void move_msi(int vector)
++{
++      if (unlikely(pending_irq_balance_cpumask[vector])) {
++              set_msi_affinity(vector, pending_irq_balance_cpumask[vector]);
++              pending_irq_balance_cpumask[vector] = 0;
++      }
++}
++#endif
++
++static void mask_MSI_irq(unsigned int vector)
++{
++      msi_set_mask_bit(vector, 1);
++}
++
++static void unmask_MSI_irq(unsigned int vector)
++{
++      msi_set_mask_bit(vector, 0);
++}
++
++static unsigned int startup_msi_irq_wo_maskbit(unsigned int vector)
++{
++      return 0;       /* never anything pending */
++}
++
++static void pci_disable_msi(unsigned int vector);
++static void shutdown_msi_irq(unsigned int vector)
++{
++      pci_disable_msi(vector);
++}
++
++#define shutdown_msi_irq_wo_maskbit   shutdown_msi_irq
++static void enable_msi_irq_wo_maskbit(unsigned int vector) {}
++static void disable_msi_irq_wo_maskbit(unsigned int vector) {}
++static void ack_msi_irq_wo_maskbit(unsigned int vector) {}
++static void end_msi_irq_wo_maskbit(unsigned int vector)
++{
++      move_msi(vector);
++      ack_APIC_irq();
++}
++
++static unsigned int startup_msi_irq_w_maskbit(unsigned int vector)
++{
++      unmask_MSI_irq(vector);
++      return 0;       /* never anything pending */
++}
++
++#define shutdown_msi_irq_w_maskbit    shutdown_msi_irq
++#define enable_msi_irq_w_maskbit      unmask_MSI_irq
++#define disable_msi_irq_w_maskbit     mask_MSI_irq
++#define ack_msi_irq_w_maskbit         mask_MSI_irq
++
++static void end_msi_irq_w_maskbit(unsigned int vector)
++{
++      move_msi(vector);
++      unmask_MSI_irq(vector);
++      ack_APIC_irq();
++}
++
++/*
++ * Interrupt Type for MSI-X PCI/PCI-X/PCI-Express Devices,
++ * which implement the MSI-X Capability Structure.
++ */
++static struct hw_interrupt_type msix_irq_type = {
++      .typename       = "PCI MSI-X",
++      .startup        = startup_msi_irq_w_maskbit,
++      .shutdown       = shutdown_msi_irq_w_maskbit,
++      .enable         = enable_msi_irq_w_maskbit,
++      .disable        = disable_msi_irq_w_maskbit,
++      .ack            = ack_msi_irq_w_maskbit,
++      .end            = end_msi_irq_w_maskbit,
++      .set_affinity   = set_msi_irq_affinity
++};
++
++/*
++ * Interrupt Type for MSI PCI/PCI-X/PCI-Express Devices,
++ * which implement the MSI Capability Structure with
++ * Mask-and-Pending Bits.
++ */
++static struct hw_interrupt_type msi_irq_w_maskbit_type = {
++      .typename       = "PCI MSI",
++      .startup        = startup_msi_irq_w_maskbit,
++      .shutdown       = shutdown_msi_irq_w_maskbit,
++      .enable         = enable_msi_irq_w_maskbit,
++      .disable        = disable_msi_irq_w_maskbit,
++      .ack            = ack_msi_irq_w_maskbit,
++      .end            = end_msi_irq_w_maskbit,
++      .set_affinity   = set_msi_irq_affinity
++};
++
++/*
++ * Interrupt Type for MSI PCI/PCI-X/PCI-Express Devices,
++ * which implement the MSI Capability Structure without
++ * Mask-and-Pending Bits.
++ */
++static struct hw_interrupt_type msi_irq_wo_maskbit_type = {
++      .typename       = "PCI MSI",
++      .startup        = startup_msi_irq_wo_maskbit,
++      .shutdown       = shutdown_msi_irq_wo_maskbit,
++      .enable         = enable_msi_irq_wo_maskbit,
++      .disable        = disable_msi_irq_wo_maskbit,
++      .ack            = ack_msi_irq_wo_maskbit,
++      .end            = end_msi_irq_wo_maskbit,
++      .set_affinity   = set_msi_irq_affinity
++};
++
++static void msi_data_init(struct msg_data *msi_data,
++                        unsigned int vector)
++{
++      memset(msi_data, 0, sizeof(struct msg_data));
++      msi_data->vector = (u8)vector;
++      msi_data->delivery_mode = MSI_DELIVERY_MODE;
++      msi_data->level = MSI_LEVEL_MODE;
++      msi_data->trigger = MSI_TRIGGER_MODE;
++}
++
++static void msi_address_init(struct msg_address *msi_address)
++{
++      unsigned int    dest_id;
++
++      memset(msi_address, 0, sizeof(struct msg_address));
++      msi_address->hi_address = (u32)0;
++      dest_id = (MSI_ADDRESS_HEADER << MSI_ADDRESS_HEADER_SHIFT) |
++               (MSI_TARGET_CPU << MSI_TARGET_CPU_SHIFT);
++      msi_address->lo_address.u.dest_mode = MSI_LOGICAL_MODE;
++      msi_address->lo_address.u.redirection_hint = MSI_REDIRECTION_HINT_MODE;
++      msi_address->lo_address.u.dest_id = dest_id;
++}
++
++static int pci_vector_resources(void)
++{
++      static int res = -EINVAL;
++      int nr_free_vectors;
++
++      if (res == -EINVAL) {
++              int i, repeat;
++              for (i = NR_REPEATS; i > 0; i--) {
++                      if ((FIRST_DEVICE_VECTOR + i * 8) > FIRST_SYSTEM_VECTOR)
++                              continue;
++                      break;
++              }
++              i++;
++              repeat = (FIRST_SYSTEM_VECTOR - FIRST_DEVICE_VECTOR)/i;
++              res = i * repeat - NR_RESERVED_VECTORS + 1;
++      }
++
++      nr_free_vectors = res + nr_released_vectors - nr_alloc_vectors;
++
++      return nr_free_vectors;
++}
++
++int assign_irq_vector(int irq)
++{
++      static int current_vector = FIRST_DEVICE_VECTOR, offset = 0;
++
++      if (irq != MSI_AUTO && IO_APIC_VECTOR(irq) > 0)
++              return IO_APIC_VECTOR(irq);
++next:
++      current_vector += 8;
++      if (current_vector == SYSCALL_VECTOR)
++              goto next;
++
++      if (current_vector > FIRST_SYSTEM_VECTOR) {
++              offset++;
++              current_vector = FIRST_DEVICE_VECTOR + offset;
++      }
++
++      if (current_vector == FIRST_SYSTEM_VECTOR)
++              return -ENOSPC;
++
++      vector_irq[current_vector] = irq;
++      if (irq != MSI_AUTO)
++              IO_APIC_VECTOR(irq) = current_vector;
++
++      nr_alloc_vectors++;
++
++      return current_vector;
++}
++
++static int assign_msi_vector(void)
++{
++      static int new_vector_avail = 1;
++      int vector;
++      unsigned long flags;
++
++      /*
++       * msi_lock is provided to ensure that successful allocation of MSI
++       * vector is assigned unique among drivers.
++       */
++      spin_lock_irqsave(&msi_lock, flags);
++      if (!(pci_vector_resources() > 0)) {
++              spin_unlock_irqrestore(&msi_lock, flags);
++              return -EBUSY;
++      }
++
++      if (!new_vector_avail) {
++              /*
++               * vector_irq[] = -1 indicates that this specific vector is:
++               * - assigned for MSI (since MSI have no associated IRQ) or
++               * - assigned for legacy if less than 16, or
++               * - having no corresponding 1:1 vector-to-IOxAPIC IRQ mapping
++               * vector_irq[] = 0 indicates that this vector, previously
++               * assigned for MSI, is freed by hotplug removed operations.
++               * This vector will be reused for any subsequent hotplug added
++               * operations.
++               * vector_irq[] > 0 indicates that this vector is assigned for
++               * IOxAPIC IRQs. This vector and its value provides a 1-to-1
++               * vector-to-IOxAPIC IRQ mapping.
++               */
++              for (vector = FIRST_DEVICE_VECTOR; vector < NR_IRQS; vector++) {
++                      if (vector_irq[vector] != 0)
++                              continue;
++                      vector_irq[vector] = -1;
++                      nr_released_vectors--;
++                      spin_unlock_irqrestore(&msi_lock, flags);
++                      return vector;
++              }
++              spin_unlock_irqrestore(&msi_lock, flags);
++              return -EBUSY;
++      }
++
++      vector = assign_irq_vector(MSI_AUTO);
++      if (vector  == (FIRST_SYSTEM_VECTOR - 8))
++              new_vector_avail = 0;
++
++      spin_unlock_irqrestore(&msi_lock, flags);
++      return vector;
++}
++
++static int get_new_vector(void)
++{
++      int vector;
++
++      if ((vector = assign_msi_vector()) > 0)
++              set_intr_gate(vector, interrupt[vector]);
++
++      return vector;
++}
++
++static int msi_init(void)
++{
++      static int status = -ENOMEM;
++
++      if (!status)
++              return status;
++
++      if ((status = msi_cache_init()) < 0) {
++              pci_msi_enable = 0;
++              printk(KERN_INFO "WARNING: MSI INIT FAILURE\n");
++              return status;
++      }
++      printk(KERN_INFO "MSI INIT SUCCESS\n");
++
++      return status;
++}
++
++static int get_msi_vector(struct pci_dev *dev)
++{
++      return get_new_vector();
++}
++
++static struct msi_desc* alloc_msi_entry(void)
++{
++      struct msi_desc *entry;
++
++      entry = (struct msi_desc*) kmem_cache_alloc(msi_cachep, SLAB_KERNEL);
++      if (!entry)
++              return NULL;
++
++      memset(entry, 0, sizeof(struct msi_desc));
++      entry->link.tail = entry->link.head = 0;        /* single message */
++      entry->dev = NULL;
++
++      return entry;
++}
++
++static void attach_msi_entry(struct msi_desc *entry, int vector)
++{
++      unsigned long flags;
++
++      spin_lock_irqsave(&msi_lock, flags);
++      msi_desc[vector] = entry;
++      spin_unlock_irqrestore(&msi_lock, flags);
++}
++
++static void irq_handler_init(int cap_id, int pos, int mask)
++{
++      spin_lock(&irq_desc[pos].lock);
++      if (cap_id == PCI_CAP_ID_MSIX)
++              irq_desc[pos].handler = &msix_irq_type;
++      else {
++              if (!mask)
++                      irq_desc[pos].handler = &msi_irq_wo_maskbit_type;
++              else
++                      irq_desc[pos].handler = &msi_irq_w_maskbit_type;
++      }
++      spin_unlock(&irq_desc[pos].lock);
++}
++
++static void enable_msi_mode(struct pci_dev *dev, int pos, int type)
++{
++      u32 control;
++
++      dev->bus->ops->read(dev->bus, dev->devfn,
++              msi_control_reg(pos), 2, &control);
++      if (type == PCI_CAP_ID_MSI) {
++              /* Set enabled bits to single MSI & enable MSI_enable bit */
++              msi_enable(control, 1);
++              dev->bus->ops->write(dev->bus, dev->devfn,
++                      msi_control_reg(pos), 2, control);
++      } else {
++              msix_enable(control);
++              dev->bus->ops->write(dev->bus, dev->devfn,
++                      msi_control_reg(pos), 2, control);
++      }
++      if (pci_find_capability(dev, PCI_CAP_ID_EXP)) {
++              /* PCI Express Endpoint device detected */
++              u32 cmd;
++              dev->bus->ops->read(dev->bus, dev->devfn, PCI_COMMAND, 2, &cmd);
++              cmd |= PCI_COMMAND_INTX_DISABLE;
++              dev->bus->ops->write(dev->bus, dev->devfn, PCI_COMMAND, 2, cmd);
++      }
++}
++
++static void disable_msi_mode(struct pci_dev *dev, int pos, int type)
++{
++      u32 control;
++
++      dev->bus->ops->read(dev->bus, dev->devfn,
++              msi_control_reg(pos), 2, &control);
++      if (type == PCI_CAP_ID_MSI) {
++              /* Set enabled bits to single MSI & enable MSI_enable bit */
++              msi_disable(control);
++              dev->bus->ops->write(dev->bus, dev->devfn,
++                      msi_control_reg(pos), 2, control);
++      } else {
++              msix_disable(control);
++              dev->bus->ops->write(dev->bus, dev->devfn,
++                      msi_control_reg(pos), 2, control);
++      }
++      if (pci_find_capability(dev, PCI_CAP_ID_EXP)) {
++              /* PCI Express Endpoint device detected */
++              u32 cmd;
++              dev->bus->ops->read(dev->bus, dev->devfn, PCI_COMMAND, 2, &cmd);
++              cmd &= ~PCI_COMMAND_INTX_DISABLE;
++              dev->bus->ops->write(dev->bus, dev->devfn, PCI_COMMAND, 2, cmd);
++      }
++}
++
++static int msi_lookup_vector(struct pci_dev *dev)
++{
++      int vector;
++      unsigned long flags;
++
++      spin_lock_irqsave(&msi_lock, flags);
++      for (vector = FIRST_DEVICE_VECTOR; vector < NR_IRQS; vector++) {
++              if (!msi_desc[vector] || msi_desc[vector]->dev != dev ||
++                      msi_desc[vector]->msi_attrib.entry_nr ||
++                      msi_desc[vector]->msi_attrib.default_vector != dev->irq)
++                      continue;       /* not entry 0, skip */
++              spin_unlock_irqrestore(&msi_lock, flags);
++              /* This pre-assigned entry-0 MSI vector for this device
++                 already exits. Override dev->irq with this vector */
++              dev->irq = vector;
++              return 0;
++      }
++      spin_unlock_irqrestore(&msi_lock, flags);
++
++      return -EACCES;
++}
++
++void pci_scan_msi_device(struct pci_dev *dev)
++{
++      if (!dev)
++              return;
++
++      if (pci_find_capability(dev, PCI_CAP_ID_MSIX) > 0) {
++              nr_reserved_vectors++;
++              nr_msix_devices++;
++      } else if (pci_find_capability(dev, PCI_CAP_ID_MSI) > 0)
++              nr_reserved_vectors++;
++}
++
++/**
++ * msi_capability_init - configure device's MSI capability structure
++ * @dev: pointer to the pci_dev data structure of MSI device function
++ *
++ * Setup the MSI capability structure of device funtion with a single
++ * MSI vector, regardless of device function is capable of handling
++ * multiple messages. A return of zero indicates the successful setup
++ * of an entry zero with the new MSI vector or non-zero for otherwise.
++ **/
++static int msi_capability_init(struct pci_dev *dev)
++{
++      struct msi_desc *entry;
++      struct msg_address address;
++      struct msg_data data;
++      int pos, vector;
++      u32 control;
++
++      pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
++      if (!pos)
++              return -EINVAL;
++
++      dev->bus->ops->read(dev->bus, dev->devfn, msi_control_reg(pos),
++              2, &control);
++      if (control & PCI_MSI_FLAGS_ENABLE)
++              return 0;
++
++      vector = dev->irq;
++      if (vector > 0 && !msi_lookup_vector(dev)) {
++              /* Lookup Sucess */
++              enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
++              return 0;
++      }
++      /* MSI Entry Initialization */
++      if (!(entry = alloc_msi_entry()))
++              return -ENOMEM;
++
++      if ((vector = get_msi_vector(dev)) < 0) {
++              kmem_cache_free(msi_cachep, entry);
++              return -EBUSY;
++      }
++      entry->msi_attrib.type = PCI_CAP_ID_MSI;
++      entry->msi_attrib.entry_nr = 0;
++      entry->msi_attrib.maskbit = is_mask_bit_support(control);
++      entry->msi_attrib.default_vector = dev->irq;
++      dev->irq = vector;      /* save default pre-assigned ioapic vector */
++      entry->dev = dev;
++      if (is_mask_bit_support(control)) {
++              entry->mask_base = msi_mask_bits_reg(pos,
++                              is_64bit_address(control));
++      }
++      /* Replace with MSI handler */
++      irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit);
++      /* Configure MSI capability structure */
++      msi_address_init(&address);
++      msi_data_init(&data, vector);
++      entry->msi_attrib.current_cpu = ((address.lo_address.u.dest_id >>
++                              MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK);
++      dev->bus->ops->write(dev->bus, dev->devfn, msi_lower_address_reg(pos),
++                              4, address.lo_address.value);
++      if (is_64bit_address(control)) {
++              dev->bus->ops->write(dev->bus, dev->devfn,
++                      msi_upper_address_reg(pos), 4, address.hi_address);
++              dev->bus->ops->write(dev->bus, dev->devfn,
++                      msi_data_reg(pos, 1), 2, *((u32*)&data));
++      } else
++              dev->bus->ops->write(dev->bus, dev->devfn,
++                      msi_data_reg(pos, 0), 2, *((u32*)&data));
++      if (entry->msi_attrib.maskbit) {
++              unsigned int maskbits, temp;
++              /* All MSIs are unmasked by default, Mask them all */
++              dev->bus->ops->read(dev->bus, dev->devfn,
++                      msi_mask_bits_reg(pos, is_64bit_address(control)), 4,
++                      &maskbits);
++              temp = (1 << multi_msi_capable(control));
++              temp = ((temp - 1) & ~temp);
++              maskbits |= temp;
++              dev->bus->ops->write(dev->bus, dev->devfn,
++                      msi_mask_bits_reg(pos, is_64bit_address(control)), 4,
++                      maskbits);
++      }
++      attach_msi_entry(entry, vector);
++      /* Set MSI enabled bits  */
++      enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
++
++      return 0;
++}
++
++/**
++ * msix_capability_init - configure device's MSI-X capability
++ * @dev: pointer to the pci_dev data structure of MSI-X device function
++ *
++ * Setup the MSI-X capability structure of device funtion with a
++ * single MSI-X vector. A return of zero indicates the successful setup
++ * of an entry zero with the new MSI-X vector or non-zero for otherwise.
++ * To request for additional MSI-X vectors, the device drivers are
++ * required to utilize the following supported APIs:
++ * 1) msi_alloc_vectors(...) for requesting one or more MSI-X vectors
++ * 2) msi_free_vectors(...) for releasing one or more MSI-X vectors
++ *    back to PCI subsystem before calling free_irq(...)
++ **/
++static int msix_capability_init(struct pci_dev        *dev)
++{
++      struct msi_desc *entry;
++      struct msg_address address;
++      struct msg_data data;
++      int vector, pos, dev_msi_cap;
++      u32 phys_addr, table_offset;
++      u32 control;
++      u8 bir;
++      void *base;
++
++      pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
++      if (!pos)
++              return -EINVAL;
++
++      /* Request & Map MSI-X table region */
++      dev->bus->ops->read(dev->bus, dev->devfn, msi_control_reg(pos), 2,
++              &control);
++      if (control & PCI_MSIX_FLAGS_ENABLE)
++              return 0;
++
++      vector = dev->irq;
++      if (vector > 0 && !msi_lookup_vector(dev)) {
++              /* Lookup Sucess */
++              enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
++              return 0;
++      }
++
++      dev_msi_cap = multi_msix_capable(control);
++      dev->bus->ops->read(dev->bus, dev->devfn,
++              msix_table_offset_reg(pos), 4, &table_offset);
++      bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK);
++      phys_addr = pci_resource_start (dev, bir);
++      phys_addr += (u32)(table_offset & ~PCI_MSIX_FLAGS_BIRMASK);
++      if (!request_mem_region(phys_addr,
++              dev_msi_cap * PCI_MSIX_ENTRY_SIZE,
++              "MSI-X iomap Failure"))
++              return -ENOMEM;
++      base = ioremap_nocache(phys_addr, dev_msi_cap * PCI_MSIX_ENTRY_SIZE);
++      if (base == NULL)
++              goto free_region;
++      /* MSI Entry Initialization */
++      entry = alloc_msi_entry();
++      if (!entry)
++              goto free_iomap;
++      if ((vector = get_msi_vector(dev)) < 0)
++              goto free_entry;
++
++      entry->msi_attrib.type = PCI_CAP_ID_MSIX;
++      entry->msi_attrib.entry_nr = 0;
++      entry->msi_attrib.maskbit = 1;
++      entry->msi_attrib.default_vector = dev->irq;
++      dev->irq = vector;      /* save default pre-assigned ioapic vector */
++      entry->dev = dev;
++      entry->mask_base = (unsigned long)base;
++      /* Replace with MSI handler */
++      irq_handler_init(PCI_CAP_ID_MSIX, vector, 1);
++      /* Configure MSI-X capability structure */
++      msi_address_init(&address);
++      msi_data_init(&data, vector);
++      entry->msi_attrib.current_cpu = ((address.lo_address.u.dest_id >>
++                              MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK);
++      writel(address.lo_address.value, base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
++      writel(address.hi_address, base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
++      writel(*(u32*)&data, base + PCI_MSIX_ENTRY_DATA_OFFSET);
++      /* Initialize all entries from 1 up to 0 */
++      for (pos = 1; pos < dev_msi_cap; pos++) {
++              writel(0, base + pos * PCI_MSIX_ENTRY_SIZE +
++                      PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
++              writel(0, base + pos * PCI_MSIX_ENTRY_SIZE +
++                      PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
++              writel(0, base + pos * PCI_MSIX_ENTRY_SIZE +
++                      PCI_MSIX_ENTRY_DATA_OFFSET);
++      }
++      attach_msi_entry(entry, vector);
++      /* Set MSI enabled bits  */
++      enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
++
++      return 0;
++
++free_entry:
++      kmem_cache_free(msi_cachep, entry);
++free_iomap:
++      iounmap(base);
++free_region:
++      release_mem_region(phys_addr, dev_msi_cap * PCI_MSIX_ENTRY_SIZE);
++
++      return ((vector < 0) ? -EBUSY : -ENOMEM);
++}
++
++/**
++ * pci_enable_msi - configure device's MSI(X) capability structure
++ * @dev: pointer to the pci_dev data structure of MSI(X) device function
++ *
++ * Setup the MSI/MSI-X capability structure of device function with
++ * a single MSI(X) vector upon its software driver call to request for
++ * MSI(X) mode enabled on its hardware device function. A return of zero
++ * indicates the successful setup of an entry zero with the new MSI(X)
++ * vector or non-zero for otherwise.
++ **/
++int pci_enable_msi(struct pci_dev* dev)
++{
++      int status = -EINVAL;
++
++      if (!pci_msi_enable || !dev)
++              return status;
++
++      if (msi_init() < 0)
++              return -ENOMEM;
++
++      if ((status = msix_capability_init(dev)) == -EINVAL)
++              status = msi_capability_init(dev);
++      if (!status)
++              nr_reserved_vectors--;
++
++      return status;
++}
++
++static int msi_free_vector(struct pci_dev* dev, int vector);
++static void pci_disable_msi(unsigned int vector)
++{
++      int head, tail, type, default_vector;
++      struct msi_desc *entry;
++      struct pci_dev *dev;
++      unsigned long flags;
++
++      spin_lock_irqsave(&msi_lock, flags);
++      entry = msi_desc[vector];
++      if (!entry || !entry->dev) {
++              spin_unlock_irqrestore(&msi_lock, flags);
++              return;
++      }
++      dev = entry->dev;
++      type = entry->msi_attrib.type;
++      head = entry->link.head;
++      tail = entry->link.tail;
++      default_vector = entry->msi_attrib.default_vector;
++      spin_unlock_irqrestore(&msi_lock, flags);
++
++      disable_msi_mode(dev, pci_find_capability(dev, type), type);
++      /* Restore dev->irq to its default pin-assertion vector */
++      dev->irq = default_vector;
++      if (type == PCI_CAP_ID_MSIX && head != tail) {
++              /* Bad driver, which do not call msi_free_vectors before exit.
++                 We must do a cleanup here */
++              while (1) {
++                      spin_lock_irqsave(&msi_lock, flags);
++                      entry = msi_desc[vector];
++                      head = entry->link.head;
++                      tail = entry->link.tail;
++                      spin_unlock_irqrestore(&msi_lock, flags);
++                      if (tail == head)
++                              break;
++                      if (msi_free_vector(dev, entry->link.tail))
++                              break;
++              }
++      }
++}
++
++static int msi_alloc_vector(struct pci_dev* dev, int head)
++{
++      struct msi_desc *entry;
++      struct msg_address address;
++      struct msg_data data;
++      int i, offset, pos, dev_msi_cap, vector;
++      u32 low_address, control;
++      unsigned long base = 0L;
++      unsigned long flags;
++
++      spin_lock_irqsave(&msi_lock, flags);
++      entry = msi_desc[dev->irq];
++      if (!entry) {
++              spin_unlock_irqrestore(&msi_lock, flags);
++              return -EINVAL;
++      }
++      base = entry->mask_base;
++      spin_unlock_irqrestore(&msi_lock, flags);
++
++      pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
++      dev->bus->ops->read(dev->bus, dev->devfn, msi_control_reg(pos),
++              2, &control);
++      dev_msi_cap = multi_msix_capable(control);
++      for (i = 1; i < dev_msi_cap; i++) {
++              if (!(low_address = readl(base + i * PCI_MSIX_ENTRY_SIZE)))
++                       break;
++      }
++      if (i >= dev_msi_cap)
++              return -EINVAL;
++
++      /* MSI Entry Initialization */
++      if (!(entry = alloc_msi_entry()))
++              return -ENOMEM;
++
++      if ((vector = get_new_vector()) < 0) {
++              kmem_cache_free(msi_cachep, entry);
++              return vector;
++      }
++      entry->msi_attrib.type = PCI_CAP_ID_MSIX;
++      entry->msi_attrib.entry_nr = i;
++      entry->msi_attrib.maskbit = 1;
++      entry->dev = dev;
++      entry->link.head = head;
++      entry->mask_base = base;
++      irq_handler_init(PCI_CAP_ID_MSIX, vector, 1);
++      /* Configure MSI-X capability structure */
++      msi_address_init(&address);
++      msi_data_init(&data, vector);
++      entry->msi_attrib.current_cpu = ((address.lo_address.u.dest_id >>
++                              MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK);
++      offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
++      writel(address.lo_address.value, base + offset +
++              PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
++      writel(address.hi_address, base + offset +
++              PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
++      writel(*(u32*)&data, base + offset + PCI_MSIX_ENTRY_DATA_OFFSET);
++      writel(1, base + offset + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
++      attach_msi_entry(entry, vector);
++
++      return vector;
++}
++
++static int msi_free_vector(struct pci_dev* dev, int vector)
++{
++      struct msi_desc *entry;
++      int entry_nr, type;
++      unsigned long base = 0L;
++      unsigned long flags;
++
++      spin_lock_irqsave(&msi_lock, flags);
++      entry = msi_desc[vector];
++      if (!entry || entry->dev != dev) {
++              spin_unlock_irqrestore(&msi_lock, flags);
++              return -EINVAL;
++      }
++      type = entry->msi_attrib.type;
++      entry_nr = entry->msi_attrib.entry_nr;
++      base = entry->mask_base;
++      if (entry->link.tail != entry->link.head) {
++              msi_desc[entry->link.head]->link.tail = entry->link.tail;
++              if (entry->link.tail)
++                      msi_desc[entry->link.tail]->link.head = entry->link.head;
++      }
++      entry->dev = NULL;
++      vector_irq[vector] = 0;
++      nr_released_vectors++;
++      msi_desc[vector] = NULL;
++      spin_unlock_irqrestore(&msi_lock, flags);
++
++      kmem_cache_free(msi_cachep, entry);
++      if (type == PCI_CAP_ID_MSIX) {
++              int offset;
++
++              offset = entry_nr * PCI_MSIX_ENTRY_SIZE;
++              writel(1, base + offset + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
++              writel(0, base + offset + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
++      }
++
++      return 0;
++}
++
++/**
++ * msi_alloc_vectors - allocate additional MSI-X vectors
++ * @dev: pointer to the pci_dev data structure of MSI-X device function
++ * @vector: pointer to an array of new allocated MSI-X vectors
++ * @nvec: number of MSI-X vectors requested for allocation by device driver
++ *
++ * Allocate additional MSI-X vectors requested by device driver. A
++ * return of zero indicates the successful setup of MSI-X capability
++ * structure with new allocated MSI-X vectors or non-zero for otherwise.
++ **/
++int msi_alloc_vectors(struct pci_dev* dev, int *vector, int nvec)
++{
++      struct msi_desc *entry;
++      int i, head, pos, vec, free_vectors, alloc_vectors;
++      int *vectors = (int *)vector;
++      u32 control;
++      unsigned long flags;
++
++      if (!pci_msi_enable || !dev)
++              return -EINVAL;
++
++      if (!(pos = pci_find_capability(dev, PCI_CAP_ID_MSIX)))
++              return -EINVAL;
++
++      dev->bus->ops->read(dev->bus, dev->devfn, msi_control_reg(pos),                         2, &control);
++      if (nvec > multi_msix_capable(control))
++              return -EINVAL;
++
++      spin_lock_irqsave(&msi_lock, flags);
++      entry = msi_desc[dev->irq];
++      if (!entry || entry->dev != dev ||              /* legal call */
++         entry->msi_attrib.type != PCI_CAP_ID_MSIX || /* must be MSI-X */
++         entry->link.head != entry->link.tail) {      /* already multi */
++              spin_unlock_irqrestore(&msi_lock, flags);
++              return -EINVAL;
++      }
++      /*
++       * msi_lock is provided to ensure that enough vectors resources are
++       * available before granting.
++       */
++      free_vectors = pci_vector_resources();
++      /* Ensure that each MSI/MSI-X device has one vector reserved by
++         default to avoid any MSI-X driver to take all available
++         resources */
++      free_vectors -= nr_reserved_vectors;
++      /* Find the average of free vectors among MSI-X devices */
++      if (nr_msix_devices > 0)
++              free_vectors /= nr_msix_devices;
++      spin_unlock_irqrestore(&msi_lock, flags);
++
++      if (nvec > free_vectors)
++              return -EBUSY;
++
++      alloc_vectors = 0;
++      head = dev->irq;
++      for (i = 0; i < nvec; i++) {
++              if ((vec = msi_alloc_vector(dev, head)) < 0)
++                      break;
++              *(vectors + i) = vec;
++              head = vec;
++              alloc_vectors++;
++      }
++      if (alloc_vectors != nvec) {
++              for (i = 0; i < alloc_vectors; i++) {
++                      vec = *(vectors + i);
++                      msi_free_vector(dev, vec);
++              }
++              spin_lock_irqsave(&msi_lock, flags);
++              msi_desc[dev->irq]->link.tail = msi_desc[dev->irq]->link.head;
++              spin_unlock_irqrestore(&msi_lock, flags);
++              return -EBUSY;
++      }
++      if (nr_msix_devices > 0)
++              nr_msix_devices--;
++
++      return 0;
++}
++
++/**
++ * msi_free_vectors - reclaim MSI-X vectors to unused state
++ * @dev: pointer to the pci_dev data structure of MSI-X device function
++ * @vector: pointer to an array of released MSI-X vectors
++ * @nvec: number of MSI-X vectors requested for release by device driver
++ *
++ * Reclaim MSI-X vectors released by device driver to unused state,
++ * which may be used later on. A return of zero indicates the
++ * success or non-zero for otherwise. Device driver should call this
++ * before calling function free_irq.
++ **/
++int msi_free_vectors(struct pci_dev* dev, int *vector, int nvec)
++{
++      struct msi_desc *entry;
++      int i;
++      unsigned long flags;
++
++      if (!pci_msi_enable)
++              return -EINVAL;
++
++      spin_lock_irqsave(&msi_lock, flags);
++      entry = msi_desc[dev->irq];
++      if (!entry || entry->dev != dev ||
++              entry->msi_attrib.type != PCI_CAP_ID_MSIX ||
++              entry->link.head == entry->link.tail) { /* Nothing to free */
++              spin_unlock_irqrestore(&msi_lock, flags);
++              return -EINVAL;
++      }
++      spin_unlock_irqrestore(&msi_lock, flags);
++
++      for (i = 0; i < nvec; i++) {
++              if (*(vector + i) == dev->irq)
++                      continue;/* Don't free entry 0 if mistaken by driver */
++              msi_free_vector(dev, *(vector + i));
++      }
++
++      return 0;
++}
++
++/**
++ * msi_remove_pci_irq_vectors - reclaim MSI(X) vectors to unused state
++ * @dev: pointer to the pci_dev data structure of MSI(X) device function
++ *
++ * Being called during hotplug remove, from which the device funciton
++ * is hot-removed. All previous assigned MSI/MSI-X vectors, if
++ * allocated for this device function, are reclaimed to unused state,
++ * which may be used later on.
++ **/
++void msi_remove_pci_irq_vectors(struct pci_dev* dev)
++{
++      struct msi_desc *entry;
++      int type;
++      unsigned long flags;
++
++      if (!pci_msi_enable)
++              return;
++
++      spin_lock_irqsave(&msi_lock, flags);
++      entry = msi_desc[dev->irq];
++      if (!entry || entry->dev != dev) {
++              spin_unlock_irqrestore(&msi_lock, flags);
++              return;
++      }
++      type = entry->msi_attrib.type;
++      spin_unlock_irqrestore(&msi_lock, flags);
++
++      msi_free_vector(dev, dev->irq);
++      if (type == PCI_CAP_ID_MSIX) {
++              int i, pos, dev_msi_cap;
++              u32 phys_addr, table_offset;
++              u32 control;
++              u8 bir;
++
++              pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
++              dev->bus->ops->read(dev->bus, dev->devfn, msi_control_reg(pos),                         2, &control);
++              dev_msi_cap = multi_msix_capable(control);
++              dev->bus->ops->read(dev->bus, dev->devfn,
++                      msix_table_offset_reg(pos), 4, &table_offset);
++              bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK);
++              phys_addr = pci_resource_start (dev, bir);
++              phys_addr += (u32)(table_offset & ~PCI_MSIX_FLAGS_BIRMASK);
++              for (i = FIRST_DEVICE_VECTOR; i < NR_IRQS; i++) {
++                      spin_lock_irqsave(&msi_lock, flags);
++                      if (!msi_desc[i] || msi_desc[i]->dev != dev) {
++                              spin_unlock_irqrestore(&msi_lock, flags);
++                              continue;
++                      }
++                      spin_unlock_irqrestore(&msi_lock, flags);
++                      msi_free_vector(dev, i);
++              }
++              writel(1, entry->mask_base + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
++              iounmap((void*)entry->mask_base);
++              release_mem_region(phys_addr, dev_msi_cap * PCI_MSIX_ENTRY_SIZE);
++      }
++      nr_reserved_vectors++;
++}
++
++EXPORT_SYMBOL(pci_enable_msi);
++EXPORT_SYMBOL(msi_alloc_vectors);
++EXPORT_SYMBOL(msi_free_vectors);
+--- linux-2.6.0-test6/drivers/pci/pci.c        2003-08-08 22:55:12.000000000 -0700
++++ 25/drivers/pci/pci.c       2003-10-05 00:36:10.000000000 -0700
+@@ -126,11 +126,13 @@ pci_find_capability(struct pci_dev *dev,
+ /**
+  * pci_bus_find_capability - query for devices' capabilities 
+- * @dev: PCI device to query
+- * @cap: capability code
++ * @bus:   the PCI bus to query
++ * @devfn: PCI device to query
++ * @cap:   capability code
+  *
+  * Like pci_find_capability() but works for pci devices that do not have a
+  * pci_dev structure set up yet. 
++ *
+  * Returns the address of the requested capability structure within the
+  * device's PCI configuration space or 0 in case the device does not
+  * support it.
+--- linux-2.6.0-test6/drivers/pci/pool.c       2003-07-27 12:14:39.000000000 -0700
++++ 25/drivers/pci/pool.c      2003-10-05 00:33:24.000000000 -0700
+@@ -296,7 +296,6 @@ restart:
+                       schedule_timeout (POOL_TIMEOUT_JIFFIES);
+-                      current->state = TASK_RUNNING;
+                       remove_wait_queue (&pool->waitq, &wait);
+                       goto restart;
+               }
+--- linux-2.6.0-test6/drivers/pci/power.c      2003-06-14 12:18:25.000000000 -0700
++++ /dev/null  2002-08-30 16:31:37.000000000 -0700
+@@ -1,159 +0,0 @@
+-#include <linux/pci.h>
+-#include <linux/pm.h>
+-#include <linux/init.h>
+-
+-/*
+- * PCI Power management..
+- *
+- * This needs to be done centralized, so that we power manage PCI
+- * devices in the right order: we should not shut down PCI bridges
+- * before we've shut down the devices behind them, and we should
+- * not wake up devices before we've woken up the bridge to the
+- * device.. Eh?
+- *
+- * We do not touch devices that don't have a driver that exports
+- * a suspend/resume function. That is just too dangerous. If the default
+- * PCI suspend/resume functions work for a device, the driver can
+- * easily implement them (ie just have a suspend function that calls
+- * the pci_set_power_state() function).
+- */
+-
+-static int pci_pm_save_state_device(struct pci_dev *dev, u32 state)
+-{
+-      int error = 0;
+-      if (dev) {
+-              struct pci_driver *driver = dev->driver;
+-              if (driver && driver->save_state) 
+-                      error = driver->save_state(dev,state);
+-      }
+-      return error;
+-}
+-
+-static int pci_pm_suspend_device(struct pci_dev *dev, u32 state)
+-{
+-      int error = 0;
+-      if (dev) {
+-              struct pci_driver *driver = dev->driver;
+-              if (driver && driver->suspend)
+-                      error = driver->suspend(dev,state);
+-      }
+-      return error;
+-}
+-
+-static int pci_pm_resume_device(struct pci_dev *dev)
+-{
+-      int error = 0;
+-      if (dev) {
+-              struct pci_driver *driver = dev->driver;
+-              if (driver && driver->resume)
+-                      error = driver->resume(dev);
+-      }
+-      return error;
+-}
+-
+-static int pci_pm_save_state_bus(struct pci_bus *bus, u32 state)
+-{
+-      struct list_head *list;
+-      int error = 0;
+-
+-      list_for_each(list, &bus->children) {
+-              error = pci_pm_save_state_bus(pci_bus_b(list),state);
+-              if (error) return error;
+-      }
+-      list_for_each(list, &bus->devices) {
+-              error = pci_pm_save_state_device(pci_dev_b(list),state);
+-              if (error) return error;
+-      }
+-      return 0;
+-}
+-
+-static int pci_pm_suspend_bus(struct pci_bus *bus, u32 state)
+-{
+-      struct list_head *list;
+-
+-      /* Walk the bus children list */
+-      list_for_each(list, &bus->children) 
+-              pci_pm_suspend_bus(pci_bus_b(list),state);
+-
+-      /* Walk the device children list */
+-      list_for_each(list, &bus->devices)
+-              pci_pm_suspend_device(pci_dev_b(list),state);
+-      return 0;
+-}
+-
+-static int pci_pm_resume_bus(struct pci_bus *bus)
+-{
+-      struct list_head *list;
+-
+-      /* Walk the device children list */
+-      list_for_each(list, &bus->devices)
+-              pci_pm_resume_device(pci_dev_b(list));
+-
+-      /* And then walk the bus children */
+-      list_for_each(list, &bus->children)
+-              pci_pm_resume_bus(pci_bus_b(list));
+-      return 0;
+-}
+-
+-static int pci_pm_save_state(u32 state)
+-{
+-      struct pci_bus *bus = NULL;
+-      int error = 0;
+-
+-      while ((bus = pci_find_next_bus(bus)) != NULL) {
+-              error = pci_pm_save_state_bus(bus,state);
+-              if (!error)
+-                      error = pci_pm_save_state_device(bus->self,state);
+-      }
+-      return error;
+-}
+-
+-static int pci_pm_suspend(u32 state)
+-{
+-      struct pci_bus *bus = NULL;
+-
+-      while ((bus = pci_find_next_bus(bus)) != NULL) {
+-              pci_pm_suspend_bus(bus,state);
+-              pci_pm_suspend_device(bus->self,state);
+-      }
+-      return 0;
+-}
+-
+-static int pci_pm_resume(void)
+-{
+-      struct pci_bus *bus = NULL;
+-
+-      while ((bus = pci_find_next_bus(bus)) != NULL) {
+-              pci_pm_resume_device(bus->self);
+-              pci_pm_resume_bus(bus);
+-      }
+-      return 0;
+-}
+-
+-static int 
+-pci_pm_callback(struct pm_dev *pm_device, pm_request_t rqst, void *data)
+-{
+-      int error = 0;
+-
+-      switch (rqst) {
+-      case PM_SAVE_STATE:
+-              error = pci_pm_save_state((unsigned long)data);
+-              break;
+-      case PM_SUSPEND:
+-              error = pci_pm_suspend((unsigned long)data);
+-              break;
+-      case PM_RESUME:
+-              error = pci_pm_resume();
+-              break;
+-      default: break;
+-      }
+-      return error;
+-}
+-
+-static int __init pci_pm_init(void)
+-{
+-      pm_register(PM_PCI_DEV, 0, pci_pm_callback);
+-      return 0;
+-}
+-
+-subsys_initcall(pci_pm_init);
+--- linux-2.6.0-test6/drivers/pci/probe.c      2003-08-08 22:55:12.000000000 -0700
++++ 25/drivers/pci/probe.c     2003-10-05 00:36:20.000000000 -0700
+@@ -176,7 +176,7 @@ void __devinit pci_read_bridge_bases(str
+               limit |= (io_limit_hi << 16);
+       }
+-      if (base && base <= limit) {
++      if (base <= limit) {
+               res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
+               res->start = base;
+               res->end = limit + 0xfff;
+@@ -187,7 +187,7 @@ void __devinit pci_read_bridge_bases(str
+       pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo);
+       base = (mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16;
+       limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16;
+-      if (base && base <= limit) {
++      if (base <= limit) {
+               res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM;
+               res->start = base;
+               res->end = limit + 0xfffff;
+@@ -213,7 +213,7 @@ void __devinit pci_read_bridge_bases(str
+               }
+ #endif
+       }
+-      if (base && base <= limit) {
++      if (base <= limit) {
+               res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM | IORESOURCE_PREFETCH;
+               res->start = base;
+               res->end = limit + 0xfffff;
+@@ -552,6 +552,7 @@ int __devinit pci_scan_slot(struct pci_b
+               struct pci_dev *dev;
+               dev = pci_scan_device(bus, devfn);
++              pci_scan_msi_device(dev);
+               if (func == 0) {
+                       if (!dev)
+                               break;
+--- linux-2.6.0-test6/drivers/pci/quirks.c     2003-08-22 19:23:41.000000000 -0700
++++ 25/drivers/pci/quirks.c    2003-10-05 00:33:24.000000000 -0700
+@@ -750,6 +750,9 @@ static void __init quirk_sis_96x_compati
+ /*
+  *  The main table of quirks.
++ *
++ *  Note: any hooks for hotpluggable devices in this table must _NOT_
++ *        be declared __init.
+  */
+ static struct pci_fixup pci_fixups[] __devinitdata = {
+--- linux-2.6.0-test6/drivers/pci/remove.c     2003-07-27 12:14:39.000000000 -0700
++++ 25/drivers/pci/remove.c    2003-10-05 00:36:20.000000000 -0700
+@@ -14,6 +14,8 @@ static void pci_free_resources(struct pc
+ {
+       int i;
++      msi_remove_pci_irq_vectors(dev);
++
+       for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+               struct resource *res = dev->resource + i;
+               if (res->parent)
+--- linux-2.6.0-test6/drivers/s390/block/dasd.c        2003-09-27 18:57:45.000000000 -0700
++++ 25/drivers/s390/block/dasd.c       2003-10-05 00:34:01.000000000 -0700
+@@ -1643,9 +1643,9 @@ dasd_flush_request_queue(struct dasd_dev
+ }
+ static int
+-dasd_open(struct inode *inp, struct file *filp)
++dasd_open(struct block_device *bdev, struct file *filp)
+ {
+-      struct gendisk *disk = inp->i_bdev->bd_disk;
++      struct gendisk *disk = bdev->bd_disk;
+       struct dasd_device *device = disk->private_data;
+       int rc;
+@@ -1676,10 +1676,8 @@ out:
+       return rc;
+ }
+-static int
+-dasd_release(struct inode *inp, struct file *filp)
++static int dasd_release(struct gendisk *disk)
+ {
+-      struct gendisk *disk = inp->i_bdev->bd_disk;
+       struct dasd_device *device = disk->private_data;
+       if (device->state < DASD_STATE_BASIC) {
+--- linux-2.6.0-test6/drivers/s390/block/dasd_int.h    2003-09-27 18:57:45.000000000 -0700
++++ 25/drivers/s390/block/dasd_int.h   2003-10-05 00:33:54.000000000 -0700
+@@ -493,7 +493,7 @@ int  dasd_ioctl_init(void);
+ void dasd_ioctl_exit(void);
+ int  dasd_ioctl_no_register(struct module *, int, dasd_ioctl_fn_t);
+ int  dasd_ioctl_no_unregister(struct module *, int, dasd_ioctl_fn_t);
+-int  dasd_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
++int  dasd_ioctl(struct block_device *, struct file *, unsigned int, unsigned long);
+ /* externals in dasd_proc.c */
+ int dasd_proc_init(void);
+--- linux-2.6.0-test6/drivers/s390/block/dasd_ioctl.c  2003-09-27 18:57:45.000000000 -0700
++++ 25/drivers/s390/block/dasd_ioctl.c 2003-10-05 00:33:54.000000000 -0700
+@@ -78,10 +78,9 @@ dasd_ioctl_no_unregister(struct module *
+ }
+ int
+-dasd_ioctl(struct inode *inp, struct file *filp,
++dasd_ioctl(struct block_device *bdev, struct file *filp,
+          unsigned int no, unsigned long data)
+ {
+-      struct block_device *bdev = inp->i_bdev;
+       struct dasd_device *device = bdev->bd_disk->private_data;
+       struct dasd_ioctl *ioctl;
+       const char *dir;
+--- linux-2.6.0-test6/drivers/s390/block/xpram.c       2003-09-27 18:57:45.000000000 -0700
++++ 25/drivers/s390/block/xpram.c      2003-10-05 00:33:54.000000000 -0700
+@@ -328,7 +328,7 @@ fail:
+       return 0;
+ }
+-static int xpram_ioctl (struct inode *inode, struct file *filp,
++static int xpram_ioctl (struct block_device *bdev, struct file *filp,
+                unsigned int cmd, unsigned long arg)
+ {
+       struct hd_geometry *geo;
+--- linux-2.6.0-test6/drivers/s390/char/tape_block.c   2003-09-27 18:57:45.000000000 -0700
++++ 25/drivers/s390/char/tape_block.c  2003-10-05 00:34:01.000000000 -0700
+@@ -27,8 +27,8 @@
+ /*
+  * file operation structure for tape block frontend
+  */
+-static int tapeblock_open(struct inode *, struct file *);
+-static int tapeblock_release(struct inode *, struct file *);
++static int tapeblock_open(block_device *, struct file *);
++static int tapeblock_release(struct gendisk *);
+ static struct block_device_operations tapeblock_fops = {
+       .owner          = THIS_MODULE,
+@@ -299,9 +299,9 @@ static int tapeblock_mediumdetect(struct
+  * Block frontend tape device open function.
+  */
+ static int
+-tapeblock_open(struct inode *inode, struct file *filp)
++tapeblock_open(struct block_device *bdev, struct file *filp)
+ {
+-      struct gendisk *disk = inode->i_bdev->bd_disk;
++      struct gendisk *disk = bdev->bd_disk;
+       struct tape_device *device = disk->private_data;
+       int rc;
+@@ -336,9 +336,8 @@ tapeblock_open(struct inode *inode, stru
+  * Block frontend tape device release function.
+  */
+ static int
+-tapeblock_release(struct inode *inode, struct file *filp)
++tapeblock_release(struct gendisk *disk)
+ {
+-      struct gendisk *disk = inode->i_bdev->bd_disk;
+       struct tape_device *device = disk->private_data;
+       tape_release(device);
+--- linux-2.6.0-test6/drivers/sbus/char/bbc_envctrl.c  2003-06-14 12:18:08.000000000 -0700
++++ 25/drivers/sbus/char/bbc_envctrl.c 2003-10-05 00:33:24.000000000 -0700
+@@ -59,7 +59,7 @@ static int errno;
+  * before the hardware based power-off event is triggered.
+  */
+-/* These settings are in celcius.  We use these defaults only
++/* These settings are in Celsius.  We use these defaults only
+  * if we cannot interrogate the cpu-fru SEEPROM.
+  */
+ struct temp_limits {
+--- linux-2.6.0-test6/drivers/sbus/char/cpwatchdog.c   2003-09-27 18:57:45.000000000 -0700
++++ 25/drivers/sbus/char/cpwatchdog.c  2003-10-05 00:33:24.000000000 -0700
+@@ -539,7 +539,7 @@ static void wd_toggleintr(struct wd_time
+ static void wd_pingtimer(struct wd_timer* pTimer)
+ {
+       if(wd_readb(&pTimer->regs->status) & WD_S_RUNNING) {
+-              wd_readb(&pTimer->regs->dcntr);
++              wd_readw(&pTimer->regs->dcntr);
+       }
+ }
+--- linux-2.6.0-test6/drivers/sbus/char/jsflash.c      2003-08-08 22:55:12.000000000 -0700
++++ 25/drivers/sbus/char/jsflash.c     2003-10-05 00:33:24.000000000 -0700
+@@ -37,6 +37,7 @@
+ #include <linux/string.h>
+ #include <linux/smp_lock.h>
+ #include <linux/genhd.h>
++#include <linux/blkdev.h>
+ #define MAJOR_NR      JSFD_MAJOR
+@@ -187,7 +188,7 @@ static void jsfd_read(char *buf, unsigne
+ static void jsfd_do_request(request_queue_t *q)
+ {
+       struct request *req;
+-      
++
+       while ((req = elv_next_request(q)) != NULL) {
+               struct jsfd_part *jdp = req->rq_disk->private_data;
+               unsigned long offset = req->sector << 9;
+@@ -198,16 +199,11 @@ static void jsfd_do_request(request_queu
+                       continue;
+               }
+-              if (req->cmd == WRITE) {
++              if (rq_data_dir(req) != READ) {
+                       printk(KERN_ERR "jsfd: write\n");
+                       end_request(req, 0);
+                       continue;
+               }
+-              if (req->cmd != READ) {
+-                      printk(KERN_ERR "jsfd: bad req->cmd %d\n", req->cmd);
+-                      end_request(req, 0);
+-                      continue;
+-              }
+               if ((jdp->dbase & 0xff000000) != 0x20000000) {
+                       printk(KERN_ERR "jsfd: bad base %x\n", (int)jdp->dbase);
+@@ -215,7 +211,6 @@ static void jsfd_do_request(request_queu
+                       continue;
+               }
+-/* printk("%s: read buf %p off %x len %x\n", req->rq_disk->disk_name, req->buffer, (int)offset, (int)len); */ /* P3 */
+               jsfd_read(req->buffer, jdp->dbase + offset, len);
+               end_request(req, 1);
+@@ -265,9 +260,6 @@ static ssize_t jsf_read(struct file * fi
+               unsigned int n;
+       } b;
+-      if (verify_area(VERIFY_WRITE, buf, togo))
+-              return -EFAULT; 
+-
+       if (p < JSF_BASE_ALL || p >= JSF_BASE_TOP) {
+               return 0;
+       }
+@@ -298,7 +290,8 @@ static ssize_t jsf_read(struct file * fi
+       while (togo >= 4) {
+               togo -= 4;
+               b.n = jsf_inl(p);
+-              copy_to_user(tmp, b.s, 4);
++              if (copy_to_user(tmp, b.s, 4))
++                      return -EFAULT;
+               tmp += 4;
+               p += 4;
+       }
+@@ -374,19 +367,17 @@ static int jsf_ioctl_program(unsigned lo
+               char s[4];
+       } b;
+-      if (verify_area(VERIFY_READ, (void *)arg, JSFPRGSZ))
++      if (copy_from_user(&abuf, (char *)arg, JSFPRGSZ))
+               return -EFAULT; 
+-      copy_from_user(&abuf, (char *)arg, JSFPRGSZ);
+       p = abuf.off;
+       togo = abuf.size;
+       if ((togo & 3) || (p & 3)) return -EINVAL;
+       uptr = (char *) (unsigned long) abuf.data;
+-      if (verify_area(VERIFY_READ, uptr, togo))
+-              return -EFAULT;
+       while (togo != 0) {
+               togo -= 4;
+-              copy_from_user(&b.s[0], uptr, 4);
++              if (copy_from_user(&b.s[0], uptr, 4))
++                      return -EFAULT;
+               jsf_write4(p, b.n);
+               p += 4;
+               uptr += 4;
+@@ -404,10 +395,8 @@ static int jsf_ioctl(struct inode *inode
+               return -EPERM;
+       switch (cmd) {
+       case JSFLASH_IDENT:
+-              if (verify_area(VERIFY_WRITE, (void *)arg, JSFIDSZ))
+-                      return -EFAULT; 
+-              copy_to_user(arg, &jsf0.id, JSFIDSZ);
+-              error = 0;
++              if (copy_to_user((void *)arg, &jsf0.id, JSFIDSZ))
++                      return -EFAULT;
+               break;
+       case JSFLASH_ERASE:
+               error = jsf_ioctl_erase(arg);
+--- linux-2.6.0-test6/drivers/scsi/a2091.c     2003-07-27 12:14:39.000000000 -0700
++++ 25/drivers/scsi/a2091.c    2003-10-05 00:33:24.000000000 -0700
+@@ -25,31 +25,20 @@
+ #define DMA(ptr) ((a2091_scsiregs *)((ptr)->base))
+ #define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata))
+-static struct Scsi_Host *first_instance = NULL;
+-static Scsi_Host_Template *a2091_template;
+-
+-static irqreturn_t a2091_intr (int irq, void *dummy, struct pt_regs *fp)
++static irqreturn_t a2091_intr (int irq, void *_instance, struct pt_regs *fp)
+ {
+     unsigned long flags;
+     unsigned int status;
+-    struct Scsi_Host *instance;
+-    int handled = 0;
++    struct Scsi_Host *instance = (struct Scsi_Host *)_instance;
+-    for (instance = first_instance; instance &&
+-       instance->hostt == a2091_template; instance = instance->next)
+-    {
+-      status = DMA(instance)->ISTR;
+-      if (!(status & (ISTR_INT_F|ISTR_INT_P)))
+-              continue;
+-
+-      if (status & ISTR_INTS) {
+-              spin_lock_irqsave(instance->host_lock, flags);
+-              wd33c93_intr (instance);
+-              spin_unlock_irqrestore(instance->host_lock, flags);
+-              handled = 1;
+-      }
+-    }
+-    return IRQ_RETVAL(handled);
++    status = DMA(instance)->ISTR;
++    if (!(status & (ISTR_INT_F|ISTR_INT_P)) || !(status & ISTR_INTS))
++      return IRQ_NONE;
++
++    spin_lock_irqsave(instance->host_lock, flags);
++    wd33c93_intr(instance);
++    spin_unlock_irqrestore(instance->host_lock, flags);
++    return IRQ_HANDLED;
+ }
+ static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
+@@ -184,8 +173,6 @@ static void dma_stop (struct Scsi_Host *
+     }
+ }
+-static int num_a2091 = 0;
+-
+ int __init a2091_detect(Scsi_Host_Template *tpnt)
+ {
+     static unsigned char called = 0;
+@@ -193,6 +180,7 @@ int __init a2091_detect(Scsi_Host_Templa
+     unsigned long address;
+     struct zorro_dev *z = NULL;
+     wd33c93_regs regs;
++    int num_a2091 = 0;
+     if (!MACH_IS_AMIGA || called)
+       return 0;
+@@ -221,13 +209,10 @@ int __init a2091_detect(Scsi_Host_Templa
+       regs.SASR = &(DMA(instance)->SASR);
+       regs.SCMD = &(DMA(instance)->SCMD);
+       wd33c93_init(instance, regs, dma_setup, dma_stop, WD33C93_FS_8_10);
+-      if (num_a2091++ == 0) {
+-          first_instance = instance;
+-          a2091_template = instance->hostt;
+-          request_irq(IRQ_AMIGA_PORTS, a2091_intr, SA_SHIRQ, "A2091 SCSI",
+-                      a2091_intr);
+-      }
++      request_irq(IRQ_AMIGA_PORTS, a2091_intr, SA_SHIRQ, "A2091 SCSI",
++                  instance);
+       DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
++      num_a2091++;
+     }
+     return num_a2091;
+@@ -266,8 +251,7 @@ int a2091_release(struct Scsi_Host *inst
+ #ifdef MODULE
+       DMA(instance)->CNTR = 0;
+       release_mem_region(ZTWO_PADDR(instance->base), 256);
+-      if (--num_a2091 == 0)
+-              free_irq(IRQ_AMIGA_PORTS, a2091_intr);
++      free_irq(IRQ_AMIGA_PORTS, instance);
+       wd33c93_release();
+ #endif
+       return 1;
+--- linux-2.6.0-test6/drivers/scsi/aic7xxx/aicasm/Makefile     2003-06-14 12:18:32.000000000 -0700
++++ 25/drivers/scsi/aic7xxx/aicasm/Makefile    2003-10-05 00:34:29.000000000 -0700
+@@ -49,14 +49,18 @@ aicdb.h:
+ clean:
+       rm -f $(clean-files)
+-aicasm_gram.c aicasm_gram.h: aicasm_gram.y
++aicasm_gram.c: aicasm_gram.h
++      mv $(<:.h=).tab.c $(<:.h=.c)
++
++aicasm_gram.h: aicasm_gram.y
+       $(YACC) $(YFLAGS) -b $(<:.y=) $<
+-      mv $(<:.y=).tab.c $(<:.y=.c)
+       mv $(<:.y=).tab.h $(<:.y=.h)
+-aicasm_macro_gram.c aicasm_macro_gram.h: aicasm_macro_gram.y
++aicasm_macro_gram.c: aicasm_macro_gram.h
++      mv $(<:.h=).tab.c $(<:.h=.c)
++
++aicasm_macro_gram.h: aicasm_macro_gram.y
+       $(YACC) $(YFLAGS) -b $(<:.y=) -p mm $<
+-      mv $(<:.y=).tab.c $(<:.y=.c)
+       mv $(<:.y=).tab.h $(<:.y=.h)
+ aicasm_scan.c: aicasm_scan.l
+--- linux-2.6.0-test6/drivers/scsi/aic7xxx/Makefile    2003-06-14 12:18:48.000000000 -0700
++++ 25/drivers/scsi/aic7xxx/Makefile   2003-10-05 00:34:29.000000000 -0700
+@@ -58,7 +58,9 @@ aicasm-7xxx-opts-$(CONFIG_AIC7XXX_REG_PR
+       -p $(obj)/aic7xxx_reg_print.c -i aic7xxx_osm.h
+ ifeq ($(CONFIG_AIC7XXX_BUILD_FIRMWARE),y)
+-$(aic7xxx-gen-y): $(src)/aic7xxx.seq $(src)/aic7xxx.reg $(obj)/aicasm/aicasm
++$(aic7xxx-gen-y): $(src)/aic7xxx.seq
++
++$(src)/aic7xxx.seq: $(obj)/aicasm/aicasm $(src)/aic7xxx.reg
+       $(obj)/aicasm/aicasm -I$(src) -r $(obj)/aic7xxx_reg.h \
+                             $(aicasm-7xxx-opts-y) -o $(obj)/aic7xxx_seq.h \
+                             $(src)/aic7xxx.seq
+@@ -72,7 +74,9 @@ aicasm-79xx-opts-$(CONFIG_AIC79XX_REG_PR
+       -p $(obj)/aic79xx_reg_print.c -i aic79xx_osm.h
+ ifeq ($(CONFIG_AIC79XX_BUILD_FIRMWARE),y)
+-$(aic79xx-gen-y): $(src)/aic79xx.seq $(src)/aic79xx.reg $(obj)/aicasm/aicasm
++$(aic79xx-gen-y): $(src)/aic79xx.seq
++
++$(src)/aic79xx.seq: $(obj)/aicasm/aicasm $(src)/aic79xx.reg
+       $(obj)/aicasm/aicasm -I$(src) -r $(obj)/aic79xx_reg.h \
+                             $(aicasm-79xx-opts-y) -o $(obj)/aic79xx_seq.h \
+                             $(src)/aic79xx.seq
+--- linux-2.6.0-test6/drivers/scsi/aic7xxx_old/aic7xxx_proc.c  2003-06-14 12:18:33.000000000 -0700
++++ 25/drivers/scsi/aic7xxx_old/aic7xxx_proc.c 2003-10-05 00:36:51.000000000 -0700
+@@ -92,7 +92,7 @@ aic7xxx_proc_info ( struct Scsi_Host *HB
+   HBAptr = NULL;
+-  for(p=first_aic7xxx; p->host != HBAptr; p=p->next)
++  for(p=first_aic7xxx; p && p->host != HBAptr; p=p->next)
+     ;
+   if (!p)
+--- linux-2.6.0-test6/drivers/scsi/g_NCR5380.c 2003-09-27 18:57:45.000000000 -0700
++++ 25/drivers/scsi/g_NCR5380.c        2003-10-05 00:33:24.000000000 -0700
+@@ -527,8 +527,9 @@ int generic_NCR5380_release_resources(st
+  *    Locks: none
+  */
+-int generic_NCR5380_biosparam(struct scsi_device *sdev,
+-              struct block_device *bdev, sector_t capacity, int *ip)
++static int
++generic_NCR5380_biosparam(struct scsi_device *sdev, struct block_device *bdev,
++                        sector_t capacity, int *ip)
+ {
+       ip[0] = 64;
+       ip[1] = 32;
+--- linux-2.6.0-test6/drivers/scsi/g_NCR5380.h 2003-06-14 12:17:56.000000000 -0700
++++ 25/drivers/scsi/g_NCR5380.h        2003-10-05 00:33:24.000000000 -0700
+@@ -52,7 +52,6 @@ static int generic_NCR5380_bus_reset(Scs
+ static int generic_NCR5380_host_reset(Scsi_Cmnd *);
+ static int generic_NCR5380_device_reset(Scsi_Cmnd *);
+ static const char* generic_NCR5380_info(struct Scsi_Host *);
+-static int generic_NCR5380_biosparam(struct scsi_device *, struct block_device *, sector_t, int *);
+ #ifndef CMD_PER_LUN
+ #define CMD_PER_LUN 2
+--- linux-2.6.0-test6/drivers/scsi/gvp11.c     2003-07-27 12:14:39.000000000 -0700
++++ 25/drivers/scsi/gvp11.c    2003-10-05 00:33:24.000000000 -0700
+@@ -25,29 +25,20 @@
+ #define DMA(ptr) ((gvp11_scsiregs *)((ptr)->base))
+ #define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata))
+-static struct Scsi_Host *first_instance = NULL;
+-static Scsi_Host_Template *gvp11_template;
+-
+-static irqreturn_t gvp11_intr (int irq, void *dummy, struct pt_regs *fp)
++static irqreturn_t gvp11_intr (int irq, void *_instance, struct pt_regs *fp)
+ {
+     unsigned long flags;
+     unsigned int status;
+-    struct Scsi_Host *instance;
+-    int handled = 0;
+-
+-    for (instance = first_instance; instance &&
+-       instance->hostt == gvp11_template; instance = instance->next)
+-    {
+-      status = DMA(instance)->CNTR;
+-      if (!(status & GVP11_DMAC_INT_PENDING))
+-          continue;
++    struct Scsi_Host *instance = (struct Scsi_Host *)_instance;
+-      spin_lock_irqsave(instance->host_lock, flags);
+-      wd33c93_intr (instance);
+-      spin_unlock_irqrestore(instance->host_lock, flags);
+-      handled = 1;
+-    }
+-    return IRQ_RETVAL(handled);
++    status = DMA(instance)->CNTR;
++    if (!(status & GVP11_DMAC_INT_PENDING))
++      return IRQ_NONE;
++
++    spin_lock_irqsave(instance->host_lock, flags);
++    wd33c93_intr(instance);
++    spin_unlock_irqrestore(instance->host_lock, flags);
++    return IRQ_HANDLED;
+ }
+ static int gvp11_xfer_mask = 0;
+@@ -177,8 +168,6 @@ static void dma_stop (struct Scsi_Host *
+     }
+ }
+-static int num_gvp11 = 0;
+-
+ #define CHECK_WD33C93
+ int __init gvp11_detect(Scsi_Host_Template *tpnt)
+@@ -190,6 +179,7 @@ int __init gvp11_detect(Scsi_Host_Templa
+     struct zorro_dev *z = NULL;
+     unsigned int default_dma_xfer_mask;
+     wd33c93_regs regs;
++    int num_gvp11 = 0;
+ #ifdef CHECK_WD33C93
+     volatile unsigned char *sasr_3393, *scmd_3393;
+     unsigned char save_sasr;
+@@ -339,13 +329,10 @@ int __init gvp11_detect(Scsi_Host_Templa
+                    (epc & GVP_SCSICLKMASK) ? WD33C93_FS_8_10
+                                            : WD33C93_FS_12_15);
+-      if (num_gvp11++ == 0) {
+-              first_instance = instance;
+-              gvp11_template = instance->hostt;
+-              request_irq(IRQ_AMIGA_PORTS, gvp11_intr, SA_SHIRQ,
+-                          "GVP11 SCSI", gvp11_intr);
+-      }
++      request_irq(IRQ_AMIGA_PORTS, gvp11_intr, SA_SHIRQ, "GVP11 SCSI",
++                  instance);
+       DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE;
++      num_gvp11++;
+       continue;
+ release:
+@@ -391,8 +378,7 @@ int gvp11_release(struct Scsi_Host *inst
+ #ifdef MODULE
+     DMA(instance)->CNTR = 0;
+     release_mem_region(ZTWO_PADDR(instance->base), 256);
+-    if (--num_gvp11 == 0)
+-          free_irq(IRQ_AMIGA_PORTS, gvp11_intr);
++    free_irq(IRQ_AMIGA_PORTS, instance);
+     wd33c93_release();
+ #endif
+     return 1;
+--- linux-2.6.0-test6/drivers/scsi/ide-scsi.c  2003-09-27 18:57:45.000000000 -0700
++++ 25/drivers/scsi/ide-scsi.c 2003-10-05 00:34:01.000000000 -0700
+@@ -635,24 +635,23 @@ static ide_driver_t idescsi_driver = {
+       .drives                 = LIST_HEAD_INIT(idescsi_driver.drives),
+ };
+-static int idescsi_ide_open(struct inode *inode, struct file *filp)
++static int idescsi_ide_open(struct block_device *bdev, struct file *filp)
+ {
+-      ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;
++      ide_drive_t *drive = bdev->bd_disk->private_data;
+       drive->usage++;
+       return 0;
+ }
+-static int idescsi_ide_release(struct inode *inode, struct file *filp)
++static int idescsi_ide_release(struct gendisk *disk)
+ {
+-      ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;
++      ide_drive_t *drive = disk->private_data;
+       drive->usage--;
+       return 0;
+ }
+-static int idescsi_ide_ioctl(struct inode *inode, struct file *file,
++static int idescsi_ide_ioctl(struct block_device *bdev, struct file *file,
+                       unsigned int cmd, unsigned long arg)
+ {
+-      struct block_device *bdev = inode->i_bdev;
+       return generic_ide_ioctl(bdev, cmd, arg);
+ }
+--- linux-2.6.0-test6/drivers/scsi/Kconfig     2003-09-27 18:57:45.000000000 -0700
++++ 25/drivers/scsi/Kconfig    2003-10-05 00:36:26.000000000 -0700
+@@ -55,6 +55,14 @@ config BLK_DEV_SD
+         In this case, do not compile the driver for your SCSI host adapter
+         (below) as a module either.
++config MAX_SD_DISKS
++      int "Maximum number of SCSI disks to support (256-8192)"
++      depends on BLK_DEV_SD
++      default "256"
++      help
++      The maximum number SCSI disks to support. Default is 256.
++      Change this value if you want kernel to support lots of SCSI devices.
++
+ config CHR_DEV_ST
+       tristate "SCSI tape support"
+       depends on SCSI
+@@ -1148,16 +1156,6 @@ config SCSI_QLOGIC_1280
+         To compile this driver as a module, choose M here: the
+         module will be called qla1280.
+-config SCSI_QLOGIC_1280_PIO
+-      bool "Use PIO instead of MMIO" if !X86_VISWS
+-      depends on SCSI_QLOGIC_1280
+-      default y if X86_VISWS
+-      help
+-        This instructs the driver to use programmed I/O ports (PIO) instead
+-        of PCI shared memory (MMIO).  This can possibly solve some problems
+-        in case your mainboard has memory consistency issues.  If unsure,
+-        say N.
+-
+ config SCSI_QLOGICPTI
+       tristate "PTI Qlogic, ISP Driver"
+       depends on SBUS && SCSI
+@@ -1435,7 +1433,7 @@ config A3000_SCSI
+ config A4000T_SCSI
+       bool "A4000T SCSI support (EXPERIMENTAL)"
+-      depends on AMIGA && SCSI && EXPERIMENTAL
++      depends on AMIGA && SCSI && EXPERIMENTAL && BROKEN
+       help
+         Support for the NCR53C710 SCSI controller on the Amiga 4000T.
+@@ -1503,7 +1501,7 @@ config FASTLANE_SCSI
+ config A4091_SCSI
+       bool "A4091 SCSI support (EXPERIMENTAL)"
+-      depends on ZORRO && SCSI && EXPERIMENTAL
++      depends on ZORRO && SCSI && EXPERIMENTAL && BROKEN
+       help
+         Support for the NCR53C710 chip on the Amiga 4091 Z3 SCSI2 controller
+         (1993).  Very obscure -- the 4091 was part of an Amiga 4000 upgrade
+@@ -1511,7 +1509,7 @@ config A4091_SCSI
+ config WARPENGINE_SCSI
+       bool "WarpEngine SCSI support (EXPERIMENTAL)"
+-      depends on ZORRO && SCSI && EXPERIMENTAL
++      depends on ZORRO && SCSI && EXPERIMENTAL && BROKEN
+       help
+         Support for MacroSystem Development's WarpEngine Amiga SCSI-2
+         controller. Info at
+@@ -1519,7 +1517,7 @@ config WARPENGINE_SCSI
+ config BLZ603EPLUS_SCSI
+       bool "Blizzard PowerUP 603e+ SCSI (EXPERIMENTAL)"
+-      depends on ZORRO && SCSI && EXPERIMENTAL
++      depends on ZORRO && SCSI && EXPERIMENTAL && BROKEN
+       help
+         If you have an Amiga 1200 with a Phase5 Blizzard PowerUP 603e+
+         accelerator, say Y. Otherwise, say N.
+@@ -1535,7 +1533,7 @@ config OKTAGON_SCSI
+ config ATARI_SCSI
+       tristate "Atari native SCSI support"
+-      depends on ATARI && SCSI
++      depends on ATARI && SCSI && BROKEN
+       ---help---
+         If you have an Atari with built-in NCR5380 SCSI controller (TT,
+         Falcon, ...) say Y to get it supported. Of course also, if you have
+@@ -1604,7 +1602,7 @@ config MVME147_SCSI
+ config MVME16x_SCSI
+       bool "NCR53C710 SCSI driver for MVME16x"
+-      depends on MVME16x && SCSI
++      depends on MVME16x && SCSI && BROKEN
+       help
+         The Motorola MVME162, 166, 167, 172 and 177 boards use the NCR53C710
+         SCSI controller chip.  Almost everyone using one of these boards
+@@ -1612,7 +1610,7 @@ config MVME16x_SCSI
+ config BVME6000_SCSI
+       bool "NCR53C710 SCSI driver for BVME6000"
+-      depends on BVME6000 && SCSI
++      depends on BVME6000 && SCSI && BROKEN
+       help
+         The BVME4000 and BVME6000 boards from BVM Ltd use the NCR53C710
+         SCSI controller chip.  Almost everyone using one of these boards
+--- linux-2.6.0-test6/drivers/scsi/megaraid.c  2003-09-08 13:58:58.000000000 -0700
++++ 25/drivers/scsi/megaraid.c 2003-10-05 00:33:24.000000000 -0700
+@@ -586,7 +586,7 @@ mega_find_card(Scsi_Host_Template *host_
+               /* Set the Mode of addressing to 64 bit if we can */
+               if((adapter->flag & BOARD_64BIT)&&(sizeof(dma_addr_t) == 8)) {
+-                      pci_set_dma_mask(pdev, 0xffffffffffffffff);
++                      pci_set_dma_mask(pdev, 0xffffffffffffffffULL);
+                       adapter->has_64bit_addr = 1;
+               }
+               else  {
+--- linux-2.6.0-test6/drivers/scsi/ncr53c8xx.c 2003-09-27 18:57:45.000000000 -0700
++++ 25/drivers/scsi/ncr53c8xx.c        2003-10-05 00:33:24.000000000 -0700
+@@ -7757,7 +7757,7 @@ static void ncr_init_ccb(ncb_p np, ccb_p
+       cp->start.schedule.l_cmd = cpu_to_scr(SCR_JUMP);
+       cp->start.p_phys         = cpu_to_scr(CCB_PHYS(cp, phys));
+-      bcopy(&cp->start, &cp->restart, sizeof(cp->restart));
++      memcpy(&cp->restart, &cp->start, sizeof(cp->restart));
+       cp->start.schedule.l_paddr   = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle));
+       cp->restart.schedule.l_paddr = cpu_to_scr(NCB_SCRIPTH_PHYS (np, abort));
+--- linux-2.6.0-test6/drivers/scsi/nsp32.c     2003-09-08 13:58:58.000000000 -0700
++++ 25/drivers/scsi/nsp32.c    2003-10-05 00:33:24.000000000 -0700
+@@ -3435,15 +3435,6 @@ static inline int nsp32_prom_get(nsp32_h
+  * Power Management
+  */
+ #ifdef CONFIG_PM
+-/* Save Device Context */
+-static int nsp32_save_state(struct pci_dev *pdev, u32 state)
+-{
+-      struct Scsi_Host *host = pci_get_drvdata(pdev);
+-
+-      nsp32_msg(KERN_INFO, "pci-save_state: stub, pdev=0x%p, state=%ld, slot=%s, host=0x%p", pdev, state, pci_name(pdev), host);
+-
+-      return 0;
+-}
+ /* Device suspended */
+ static int nsp32_suspend(struct pci_dev *pdev, u32 state)
+@@ -3573,7 +3564,6 @@ static struct pci_driver nsp32_driver = 
+       .probe          = nsp32_probe,
+       .remove         = __devexit_p(nsp32_remove),
+ #ifdef CONFIG_PM
+-      .save_state     = nsp32_save_state,
+       .suspend        = nsp32_suspend, 
+       .resume         = nsp32_resume, 
+       .enable_wake    = nsp32_enable_wake,
+--- linux-2.6.0-test6/drivers/scsi/qla1280.c   2003-09-27 18:57:45.000000000 -0700
++++ 25/drivers/scsi/qla1280.c  2003-10-05 00:33:24.000000000 -0700
+@@ -16,10 +16,15 @@
+ * General Public License for more details.
+ *
+ ******************************************************************************/
+-#define QLA1280_VERSION      "3.23.36"
++#define QLA1280_VERSION      "3.23.37"
+ /*****************************************************************************
+     Revision History:
+-    Rev  3.23.36 September 19, 2003, Christoph Hellwig
++    Rev  3.23.37 October 1, 2003, Jes Sorensen
++      - Make MMIO depend on CONFIG_X86_VISWS instead of yet another
++        random CONFIG option
++      - Clean up locking in probe path
++    Rev  3.23.36 October 1, 2003, Christoph Hellwig
++      - queuecommand only ever receives new commands - clear flags
+       - Reintegrate lost fixes from Linux 2.5
+     Rev  3.23.35 August 14, 2003, Jes Sorensen
+       - Build against 2.6
+@@ -315,14 +320,14 @@
+ #if LINUX_VERSION_CODE >= 0x020545
+ #include <scsi/scsi_host.h>
++#include "scsi.h"
+ #else
+ #include <linux/blk.h>
++#include "scsi.h"
+ #include "hosts.h"
+ #include "sd.h"
+ #endif
+-#include "scsi.h"
+-
+ #if LINUX_VERSION_CODE < 0x020407
+ #error "Kernels older than 2.4.7 are no longer supported"
+ #endif
+@@ -339,7 +344,10 @@
+ #define  DEBUG_PRINT_NVRAM    0
+ #define  DEBUG_QLA1280                0
+-#ifdef        CONFIG_SCSI_QLOGIC_1280_PIO
++/*
++ * The SGI VISWS is broken and doesn't support MMIO ;-(
++ */
++#ifdef CONFIG_X86_VISWS
+ #define       MEMORY_MAPPED_IO        0
+ #else
+ #define       MEMORY_MAPPED_IO        1
+@@ -414,6 +422,11 @@ scsi_adjust_queue_depth(Scsi_Device *dev
+ #else
+ #define HOST_LOCK                     ha->host->host_lock
+ #endif
++#if LINUX_VERSION_CODE < 0x020600
++#define DEV_SIMPLE_TAGS(device)               device->tagged_queue
++#else
++#define DEV_SIMPLE_TAGS(device)               device->simple_tags
++#endif
+ #if defined(__ia64__) && !defined(ia64_platform_is)
+ #define ia64_platform_is(foo)         (!strcmp(x, platform_name))
+ #endif
+@@ -647,11 +660,11 @@ static int ql_debug_level = 1;
+ #define       PROC_BUF        &qla1280_buffer[len]
+ #if LINUX_VERSION_CODE < 0x020600
+-static int qla1280_proc_info(char *buffer, char **start, off_t offset, int length,
+-                    int hostno, int inout)
++static int qla1280_proc_info(char *buffer, char **start, off_t offset,
++                           int length, int hostno, int inout)
+ #else
+-static int qla1280_proc_info(struct Scsi_Host *host, char *buffer, char **start,
+-                    off_t offset, int length, int inout)
++static int qla1280_proc_info(struct Scsi_Host *host, char *buffer,
++                           char **start, off_t offset, int length, int inout)
+ #endif
+ {
+       struct scsi_qla_host *ha;
+@@ -955,8 +968,8 @@ qla1280_do_device_init(struct pci_dev *p
+                      host->io_port, host->io_port + 0xff);
+               goto error_free_irq;
+       }
+-
+ #endif
++
+       /* load the F/W, read paramaters, and init the H/W */
+       if (qla1280_initialize_adapter(ha)) {
+               printk(KERN_INFO "qla1x160: Failed to initialize adapter\n");
+@@ -1598,6 +1611,7 @@ qla1280_intr_handler(int irq, void *dev_
+       return IRQ_RETVAL(handled);
+ }
++
+ static int
+ qla12160_set_target_parameters(struct scsi_qla_host *ha, int bus, int target)
+ {
+@@ -1666,9 +1680,7 @@ qla1280_slave_configure(Scsi_Device *dev
+       int target = device->id;
+       int status = 0;
+       struct nvram *nv;
+-#if LINUX_VERSION_CODE < 0x020500
+       unsigned long flags;
+-#endif
+       ha = (struct scsi_qla_host *)device->host->hostdata;
+       nv = &ha->nvram;
+@@ -1706,17 +1718,13 @@ qla1280_slave_configure(Scsi_Device *dev
+                       nv->bus[bus].target[target].ppr_1x160.flags.enable_ppr = 0;
+       }
+-#if LINUX_VERSION_CODE < 0x020500
+       spin_lock_irqsave(HOST_LOCK, flags);
+-#endif
+       if (nv->bus[bus].target[target].parameter.f.enable_sync) {
+               status = qla12160_set_target_parameters(ha, bus, target);
+       }
+       qla12160_get_target_parameters(ha, device);
+-#if LINUX_VERSION_CODE < 0x020500
+       spin_unlock_irqrestore(HOST_LOCK, flags);
+-#endif
+       return status;
+ }
+@@ -1995,7 +2003,7 @@ qla1280_mem_alloc(struct scsi_qla_host *
+       if (ha->request_ring)
+               pci_free_consistent(ha->pdev,
+                                     ((REQUEST_ENTRY_CNT + 1) *
+-                                     (sizeof(request_t))),
++                                   (sizeof(request_t))),
+                                     ha->request_ring, ha->request_dma);
+  finish:
+       LEAVE("qla1280_mem_alloc");
+@@ -2088,6 +2096,9 @@ qla1280_initialize_adapter(struct scsi_q
+       struct device_reg *reg;
+       int status;
+       int bus;
++#if LINUX_VERSION_CODE > 0x020500
++      unsigned long flags;
++#endif
+       ENTER("qla1280_initialize_adapter");
+@@ -2131,6 +2142,15 @@ qla1280_initialize_adapter(struct scsi_q
+                       "NVRAM\n");
+       }
++#if LINUX_VERSION_CODE >= 0x020500
++      /*
++       * It's necessary to grab the spin here as qla1280_mailbox_command
++       * needs to be able to drop the lock unconditionally to wait
++       * for completion.
++       * In 2.4 ->detect is called with the io_request_lock held.
++       */
++      spin_lock_irqsave(HOST_LOCK, flags);
++#endif
+       /* If firmware needs to be loaded */
+       if (qla1280_isp_firmware(ha)) {
+               if (!(status = qla1280_chip_diag (ha))) {
+@@ -2183,6 +2203,9 @@ qla1280_initialize_adapter(struct scsi_q
+               status = 1;
+  out:
++#if LINUX_VERSION_CODE >= 0x020500
++      spin_unlock_irqrestore(HOST_LOCK, flags);
++#endif
+       if (status)
+               dprintk(2, "qla1280_initialize_adapter: **** FAILED ****\n");
+@@ -3208,18 +3231,14 @@ qla1280_mailbox_command(struct scsi_qla_
+       timer.function = qla1280_mailbox_timeout;
+       add_timer(&timer);
+-#if LINUX_VERSION_CODE < 0x020500
+       spin_unlock_irq(HOST_LOCK);
+-#endif
+       WRT_REG_WORD(&reg->host_cmd, HC_SET_HOST_INT);
+       data = qla1280_debounce_register(&reg->istatus);
+       wait_for_completion(&wait);
+       del_timer_sync(&timer);
+-#if LINUX_VERSION_CODE < 0x020500
+       spin_lock_irq(HOST_LOCK);
+-#endif
+       ha->mailbox_wait = NULL;
+@@ -3636,7 +3655,7 @@ qla1280_64bit_start_scsi(struct scsi_qla
+               (SCSI_TCN_32(cmd) | BIT_7) : SCSI_TCN_32(cmd);
+       /* Enable simple tag queuing if device supports it. */
+-      if (cmd->device->simple_tags)
++      if (DEV_SIMPLE_TAGS(cmd->device))
+               pkt->control_flags |= cpu_to_le16(BIT_3);
+       /* Load SCSI command packet. */
+@@ -3936,7 +3955,7 @@ qla1280_32bit_start_scsi(struct scsi_qla
+               (SCSI_TCN_32(cmd) | BIT_7) : SCSI_TCN_32(cmd);
+       /* Enable simple tag queuing if device supports it. */
+-      if (cmd->device->simple_tags)
++      if (DEV_SIMPLE_TAGS(cmd->device))
+               pkt->control_flags |= cpu_to_le16(BIT_3);
+       /* Load SCSI command packet. */
+@@ -4823,6 +4842,7 @@ qla1280_debounce_register(volatile u16 *
+       return ret;
+ }
++
+ /************************************************************************
+  * qla1280_check_for_dead_scsi_bus                                      *
+  *                                                                      *
+@@ -4891,7 +4911,7 @@ qla12160_get_target_parameters(struct sc
+       } else
+               printk(" Async");
+-      if (device->simple_tags)
++      if (DEV_SIMPLE_TAGS(device))
+               printk(", Tagged queuing: depth %d", device->queue_depth);
+       printk("\n");
+ }
+@@ -5105,6 +5125,7 @@ qla1280_get_token(char *str)
+       return ret;
+ }
++
+ static Scsi_Host_Template driver_template = {
+       .proc_info              = qla1280_proc_info,
+       .name                   = "Qlogic ISP 1280/12160",
+@@ -5132,6 +5153,7 @@ static Scsi_Host_Template driver_templat
+ #include "scsi_module.c"
++
+ /*
+  * Overrides for Emacs so that we almost follow Linus's tabbing style.
+  * Emacs will notice this stuff at the end of the file and automatically
+--- linux-2.6.0-test6/drivers/scsi/qlogicfc.c  2003-08-22 19:23:41.000000000 -0700
++++ 25/drivers/scsi/qlogicfc.c 2003-10-05 00:33:24.000000000 -0700
+@@ -718,8 +718,8 @@ int isp2x00_detect(Scsi_Host_Template * 
+                               continue;
+                       /* Try to configure DMA attributes. */
+-                      if (pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff) &&
+-                          pci_set_dma_mask(pdev, (u64) 0xffffffff))
++                      if (pci_set_dma_mask(pdev, 0xffffffffffffffffULL) &&
++                          pci_set_dma_mask(pdev, 0xffffffffULL))
+                                       continue;
+                       host = scsi_register(tmpt, sizeof(struct isp2x00_hostdata));
+--- linux-2.6.0-test6/drivers/scsi/sd.c        2003-09-27 18:57:46.000000000 -0700
++++ 25/drivers/scsi/sd.c       2003-10-05 00:36:26.000000000 -0700
+@@ -62,6 +62,7 @@
+  */
+ #define SD_MAJORS     16
+ #define SD_DISKS      (SD_MAJORS << 4)
++#define TOTAL_SD_DISKS        CONFIG_MAX_SD_DISKS
+ /*
+  * Time out in seconds for disks and Magneto-opticals (which are slower).
+@@ -87,7 +88,7 @@ struct scsi_disk {
+       unsigned        RCD : 1;        /* state of disk RCD bit, unused */
+ };
+-static unsigned long sd_index_bits[SD_DISKS / BITS_PER_LONG];
++static unsigned long sd_index_bits[TOTAL_SD_DISKS / BITS_PER_LONG];
+ static spinlock_t sd_index_lock = SPIN_LOCK_UNLOCKED;
+ static int sd_revalidate_disk(struct gendisk *disk);
+@@ -122,6 +123,9 @@ static int sd_major(int major_idx)
+               return SCSI_DISK1_MAJOR + major_idx - 1;
+       case 8 ... 15:
+               return SCSI_DISK8_MAJOR + major_idx - 8;
++#define MAX_IDX        (TOTAL_SD_DISKS >> 4)
++      case 16 ... MAX_IDX:
++              return SCSI_DISK15_MAJOR;
+       default:
+               BUG();
+               return 0;       /* shut up gcc */
+@@ -348,9 +352,9 @@ queue:
+  *    In the latter case @inode and @filp carry an abridged amount
+  *    of information as noted above.
+  **/
+-static int sd_open(struct inode *inode, struct file *filp)
++static int sd_open(struct block_device *bdev, struct file *filp)
+ {
+-      struct gendisk *disk = inode->i_bdev->bd_disk;
++      struct gendisk *disk = bdev->bd_disk;
+       struct scsi_disk *sdkp = scsi_disk(disk);
+       struct scsi_device *sdev = sdkp->device;
+       int retval;
+@@ -370,7 +374,7 @@ static int sd_open(struct inode *inode, 
+               goto error_out;
+       if (sdev->removable || sdkp->write_prot)
+-              check_disk_change(inode->i_bdev);
++              check_disk_change(bdev);
+       /*
+        * If the drive is empty, just let the open fail.
+@@ -421,9 +425,8 @@ error_out:
+  *    Note: may block (uninterruptible) if error recovery is underway
+  *    on this disk.
+  **/
+-static int sd_release(struct inode *inode, struct file *filp)
++static int sd_release(struct gendisk *disk)
+ {
+-      struct gendisk *disk = inode->i_bdev->bd_disk;
+       struct scsi_disk *sdkp = scsi_disk(disk);
+       struct scsi_device *sdev = sdkp->device;
+@@ -486,10 +489,9 @@ static int sd_hdio_getgeo(struct block_d
+  *    Note: most ioctls are forward onto the block subsystem or further
+  *    down in the scsi subsytem.
+  **/
+-static int sd_ioctl(struct inode * inode, struct file * filp, 
++static int sd_ioctl(struct block_device *bdev, struct file *filp, 
+                   unsigned int cmd, unsigned long arg)
+ {
+-      struct block_device *bdev = inode->i_bdev;
+       struct gendisk *disk = bdev->bd_disk;
+       struct scsi_device *sdp = scsi_disk(disk)->device;
+       int error;
+@@ -1275,8 +1277,8 @@ static int sd_probe(struct device *dev)
+               goto out_free;
+       spin_lock(&sd_index_lock);
+-      index = find_first_zero_bit(sd_index_bits, SD_DISKS);
+-      if (index == SD_DISKS) {
++      index = find_first_zero_bit(sd_index_bits, TOTAL_SD_DISKS);
++      if (index == TOTAL_SD_DISKS) {
+               spin_unlock(&sd_index_lock);
+               error = -EBUSY;
+               goto out_put;
+@@ -1291,15 +1293,24 @@ static int sd_probe(struct device *dev)
+       sdkp->openers = 0;
+       gd->major = sd_major(index >> 4);
+-      gd->first_minor = (index & 15) << 4;
++      if (index > SD_DISKS)
++              gd->first_minor = ((index - SD_DISKS) & 15) << 4;
++      else
++              gd->first_minor = (index & 15) << 4;
+       gd->minors = 16;
+       gd->fops = &sd_fops;
+-      if (index >= 26) {
++      if (index < 26) {
++              sprintf(gd->disk_name, "sd%c", 'a' + index % 26);
++      } else if (index < (26*27)) {
+               sprintf(gd->disk_name, "sd%c%c",
+                       'a' + index/26-1,'a' + index % 26);
+       } else {
+-              sprintf(gd->disk_name, "sd%c", 'a' + index % 26);
++              const unsigned int m1 = (index/ 26 - 1) / 26 - 1;
++              const unsigned int m2 = (index / 26 - 1) % 26;
++              const unsigned int m3 = index % 26;
++              sprintf(gd->disk_name, "sd%c%c%c",
++                      'a' + m1, 'a' + m2, 'a' + m3);
+       }
+       strcpy(gd->devfs_name, sdp->devfs_name);
+--- linux-2.6.0-test6/drivers/scsi/sr.c        2003-09-27 18:57:46.000000000 -0700
++++ 25/drivers/scsi/sr.c       2003-10-05 00:34:45.000000000 -0700
+@@ -289,12 +289,12 @@ static int sr_init_command(struct scsi_c
+                       return 0;
+               memcpy(SCpnt->cmnd, rq->cmd, sizeof(SCpnt->cmnd));
+-              if (rq_data_dir(rq) == WRITE)
++              if (!rq->data_len)
++                      SCpnt->sc_data_direction = SCSI_DATA_NONE;
++              else if (rq_data_dir(rq) == WRITE)
+                       SCpnt->sc_data_direction = SCSI_DATA_WRITE;
+-              else if (rq->data_len)
+-                      SCpnt->sc_data_direction = SCSI_DATA_READ;
+               else
+-                      SCpnt->sc_data_direction = SCSI_DATA_NONE;
++                      SCpnt->sc_data_direction = SCSI_DATA_READ;
+               this_count = rq->data_len;
+               if (rq->timeout)
+@@ -413,22 +413,22 @@ queue:
+       return 1;
+ }
+-static int sr_block_open(struct inode *inode, struct file *file)
++static int sr_block_open(struct block_device *bdev, struct file *file)
+ {
+-      struct scsi_cd *cd = scsi_cd(inode->i_bdev->bd_disk);
+-      return cdrom_open(&cd->cdi, inode, file);
++      struct scsi_cd *cd = scsi_cd(bdev->bd_disk);
++      return cdrom_open(&cd->cdi, bdev, file);
+ }
+-static int sr_block_release(struct inode *inode, struct file *file)
++static int sr_block_release(struct gendisk *disk)
+ {
+-      struct scsi_cd *cd = scsi_cd(inode->i_bdev->bd_disk);
+-      return cdrom_release(&cd->cdi, file);
++      struct scsi_cd *cd = scsi_cd(disk);
++      return cdrom_release(&cd->cdi);
+ }
+-static int sr_block_ioctl(struct inode *inode, struct file *file, unsigned cmd,
+-                        unsigned long arg)
++static int sr_block_ioctl(struct block_device *bdev, struct file *file,
++                        unsigned cmd, unsigned long arg)
+ {
+-      struct scsi_cd *cd = scsi_cd(inode->i_bdev->bd_disk);
++      struct scsi_cd *cd = scsi_cd(bdev->bd_disk);
+       struct scsi_device *sdev = cd->device;
+         /*
+@@ -440,7 +440,7 @@ static int sr_block_ioctl(struct inode *
+                 case SCSI_IOCTL_GET_BUS_NUMBER:
+                         return scsi_ioctl(sdev, cmd, (void *)arg);
+       }
+-      return cdrom_ioctl(&cd->cdi, inode, cmd, arg);
++      return cdrom_ioctl(&cd->cdi, bdev, cmd, arg);
+ }
+ static int sr_block_media_changed(struct gendisk *disk)
+--- linux-2.6.0-test6/drivers/scsi/sun3_scsi.c 2003-07-27 12:14:40.000000000 -0700
++++ 25/drivers/scsi/sun3_scsi.c        2003-10-05 00:33:24.000000000 -0700
+@@ -308,7 +308,6 @@ int sun3scsi_detect(Scsi_Host_Template *
+       return 1;
+ }
+-#ifdef MODULE
+ int sun3scsi_release (struct Scsi_Host *shpnt)
+ {
+       if (shpnt->irq != SCSI_IRQ_NONE)
+@@ -318,7 +317,6 @@ int sun3scsi_release (struct Scsi_Host *
+       return 0;
+ }
+-#endif
+ #ifdef RESET_BOOT
+ /*
+--- linux-2.6.0-test6/drivers/scsi/sun3_scsi.h 2003-09-08 13:58:58.000000000 -0700
++++ 25/drivers/scsi/sun3_scsi.h        2003-10-05 00:33:24.000000000 -0700
+@@ -52,11 +52,7 @@ static int sun3scsi_detect (Scsi_Host_Te
+ static const char *sun3scsi_info (struct Scsi_Host *);
+ static int sun3scsi_bus_reset(Scsi_Cmnd *);
+ static int sun3scsi_queue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+-#ifdef MODULE
+ static int sun3scsi_release (struct Scsi_Host *);
+-#else
+-#define sun3scsi_release NULL
+-#endif
+ #ifndef CMD_PER_LUN
+ #define CMD_PER_LUN 2
+--- linux-2.6.0-test6/drivers/scsi/sun3_scsi_vme.c     2003-07-27 12:14:40.000000000 -0700
++++ 25/drivers/scsi/sun3_scsi_vme.c    2003-10-05 00:33:24.000000000 -0700
+@@ -140,7 +140,7 @@ static struct Scsi_Host *default_instanc
+  
+ static int sun3scsi_detect(Scsi_Host_Template * tpnt)
+ {
+-      unsigned long ioaddr, irq;
++      unsigned long ioaddr, irq = 0;
+       static int called = 0;
+       struct Scsi_Host *instance;
+       int i;
+@@ -277,17 +277,15 @@ static int sun3scsi_detect(Scsi_Host_Tem
+       return 1;
+ }
+-#ifdef MODULE
+ int sun3scsi_release (struct Scsi_Host *shpnt)
+ {
+       if (shpnt->irq != SCSI_IRQ_NONE)
+               free_irq (shpnt->irq, NULL);
+-      iounmap(sun3_scsi_regp);
++      iounmap((void *)sun3_scsi_regp);
+       return 0;
+ }
+-#endif
+ #ifdef RESET_BOOT
+ /*
+--- linux-2.6.0-test6/drivers/scsi/sym53c8xx_2/sym_glue.c      2003-09-27 18:57:46.000000000 -0700
++++ 25/drivers/scsi/sym53c8xx_2/sym_glue.c     2003-10-05 00:34:19.000000000 -0700
+@@ -2159,8 +2159,7 @@ sym53c8xx_pci_init(struct pci_dev *pdev,
+       /* If the chip can do Memory Write Invalidate, enable it */
+       if (chip->features & FE_WRIE) {
+-              if (pci_set_mwi(pdev))
+-                      return -1;
++              pci_set_mwi(pdev);
+       }
+       /*
+--- linux-2.6.0-test6/drivers/scsi/sym53c8xx_2/sym_glue.h      2003-09-27 18:57:46.000000000 -0700
++++ 25/drivers/scsi/sym53c8xx_2/sym_glue.h     2003-10-05 00:33:24.000000000 -0700
+@@ -70,10 +70,6 @@
+ #include <scsi/scsi_host.h>
+ #include "../scsi.h"          /* XXX: DID_* */
+-#ifndef bcopy
+-#define bcopy(s, d, n)        memcpy((d), (s), (n))
+-#endif
+-
+ #ifndef bzero
+ #define bzero(d, n)   memset((d), 0, (n))
+ #endif
+--- linux-2.6.0-test6/drivers/scsi/sym53c8xx_2/sym_hipd.c      2003-09-27 18:57:46.000000000 -0700
++++ 25/drivers/scsi/sym53c8xx_2/sym_hipd.c     2003-10-05 00:34:20.000000000 -0700
+@@ -838,7 +838,8 @@ static int sym_prepare_setting(hcb_p np,
+       period = parisc_setup_hcb(np, period);
+-      if      (period <= 250)         np->minsync = 10;
++      if      (period == 250)         np->minsync = 9;
++      else if (period <= 250)         np->minsync = 10;
+       else if (period <= 303)         np->minsync = 11;
+       else if (period <= 500)         np->minsync = 12;
+       else                            np->minsync = (period + 40 - 1) / 40;
+@@ -5889,9 +5890,9 @@ int sym_hcb_attach(hcb_p np, struct sym_
+       /*
+        *  Copy scripts to controller instance.
+        */
+-      bcopy(fw->a_base, np->scripta0, np->scripta_sz);
+-      bcopy(fw->b_base, np->scriptb0, np->scriptb_sz);
+-      bcopy(fw->z_base, np->scriptz0, np->scriptz_sz);
++      memcpy(np->scripta0, fw->a_base, np->scripta_sz);
++      memcpy(np->scriptb0, fw->b_base, np->scriptb_sz);
++      memcpy(np->scriptz0, fw->z_base, np->scriptz_sz);
+       /*
+        *  Setup variable parts in scripts and compute
+--- linux-2.6.0-test6/drivers/scsi/sym53c8xx_2/sym_misc.c      2003-06-14 12:18:32.000000000 -0700
++++ 25/drivers/scsi/sym53c8xx_2/sym_misc.c     2003-10-05 00:33:24.000000000 -0700
+@@ -225,7 +225,7 @@ void sym_announce_transfer_rate(hcb_p np
+  */
+ void sym_update_trans_settings(hcb_p np, tcb_p tp)
+ {
+-      bcopy(&tp->tinfo.user, &tp->tinfo.goal, sizeof(tp->tinfo.goal));
++      memcpy(&tp->tinfo.goal, &tp->tinfo.user, sizeof(tp->tinfo.goal));
+       if (tp->inq_version >= 4) {
+               switch(tp->inq_byte56 & INQ56_CLOCKING) {
+--- linux-2.6.0-test6/drivers/scsi/sym53c8xx_comm.h    2003-09-27 18:57:46.000000000 -0700
++++ 25/drivers/scsi/sym53c8xx_comm.h   2003-10-05 00:33:24.000000000 -0700
+@@ -88,10 +88,6 @@
+ #define u_int         unsigned int
+ #define u_long                unsigned long
+-#ifndef bcopy
+-#define bcopy(s, d, n)        memcpy((d), (s), (n))
+-#endif
+-
+ #ifndef bcmp
+ #define bcmp(s, d, n) memcmp((d), (s), (n))
+ #endif
+--- linux-2.6.0-test6/drivers/serial/8250.c    2003-09-27 18:57:46.000000000 -0700
++++ 25/drivers/serial/8250.c   2003-10-05 00:36:10.000000000 -0700
+@@ -469,8 +469,14 @@ static void autoconfig_16550a(struct uar
+        */
+       serial_outp(up, UART_LCR, UART_LCR_DLAB);
+       if (serial_in(up, UART_EFR) == 0) {
+-              DEBUG_AUTOCONF("EFRv1 ");
+-              up->port.type = PORT_16650;
++              serial_outp(up, UART_EFR, 0xA8);
++              if (serial_in(up, UART_EFR) != 0) {
++                      DEBUG_AUTOCONF("EFRv1 ");
++                      up->port.type = PORT_16650;
++              } else {
++                      DEBUG_AUTOCONF("Motorola 8xxx DUART ");
++              }
++              serial_outp(up, UART_EFR, 0);
+               return;
+       }
+@@ -490,7 +496,9 @@ static void autoconfig_16550a(struct uar
+        * Attempt to switch to bank 2, read the value of the LOOP bit
+        * from EXCR1. Switch back to bank 0, change it in MCR. Then
+        * switch back to bank 2, read it from EXCR1 again and check
+-       * it's changed. If so, set baud_base in EXCR2 to 921600.
++       * it's changed. If so, set baud_base in EXCR2 to 921600. -- dwmw2
++       * On PowerPC we don't want to change baud_base, as we have
++       * a number of different divisors.  -- Tom Rini
+        */
+       serial_outp(up, UART_LCR, 0);
+       status1 = serial_in(up, UART_MCR);
+@@ -506,12 +514,14 @@ static void autoconfig_16550a(struct uar
+               serial_outp(up, UART_MCR, status1);
+               if ((status2 ^ status1) & UART_MCR_LOOP) {
++#ifndef CONFIG_PPC
+                       serial_outp(up, UART_LCR, 0xE0);
+                       status1 = serial_in(up, 0x04); /* EXCR1 */
+                       status1 &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */
+                       status1 |= 0x10;  /* 1.625 divisor for baud_base --> 921600 */
+                       serial_outp(up, 0x04, status1);
+                       serial_outp(up, UART_LCR, 0);
++#endif
+                       up->port.type = PORT_NS16550A;
+                       up->port.uartclk = 921600*16;
+@@ -825,7 +835,7 @@ receive_chars(struct uart_8250_port *up,
+               if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
+                       tty->flip.work.func((void *)tty);
+                       if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+-                              return; // if TTY_DONT_FLIP is set
++                              return; /* if TTY_DONT_FLIP is set */
+               }
+               ch = serial_inp(up, UART_RX);
+               *tty->flip.char_buf_ptr = ch;
+@@ -1186,12 +1196,21 @@ static void serial8250_break_ctl(struct 
+       spin_unlock_irqrestore(&up->port.lock, flags);
+ }
++#ifdef CONFIG_KGDB
++static int kgdb_irq = -1;
++#endif
++
+ static int serial8250_startup(struct uart_port *port)
+ {
+       struct uart_8250_port *up = (struct uart_8250_port *)port;
+       unsigned long flags;
+       int retval;
++#ifdef CONFIG_KGDB
++      if (up->port.irq == kgdb_irq)
++              return -EBUSY;
++#endif
++
+       up->capabilities = uart_config[up->port.type].flags;
+       if (up->port.type == PORT_16C950) {
+@@ -1857,6 +1876,10 @@ static void __init serial8250_register_p
+       for (i = 0; i < UART_NR; i++) {
+               struct uart_8250_port *up = &serial8250_ports[i];
++#ifdef CONFIG_KGDB
++              if (up->port.irq == kgdb_irq)
++                      up->port.kgdb = 1;
++#endif
+               up->port.line = i;
+               up->port.ops = &serial8250_pops;
+               init_timer(&up->timer);
+@@ -2101,7 +2124,8 @@ void serial8250_get_irq_map(unsigned int
+ /**
+  *    serial8250_suspend_port - suspend one serial port
+- *    @line: serial line number
++ *    @line:  serial line number
++ *      @level: the level of port suspension, as per uart_suspend_port
+  *
+  *    Suspend one serial port.
+  */
+@@ -2112,7 +2136,8 @@ void serial8250_suspend_port(int line)
+ /**
+  *    serial8250_resume_port - resume one serial port
+- *    @line: serial line number
++ *    @line:  serial line number
++ *      @level: the level of port resumption, as per uart_resume_port
+  *
+  *    Resume one serial port.
+  */
+@@ -2121,6 +2146,31 @@ void serial8250_resume_port(int line)
+       uart_resume_port(&serial8250_reg, &serial8250_ports[line].port);
+ }
++#ifdef CONFIG_KGDB
++/*
++ * Find all the ports using the given irq and shut them down.
++ * Result should be that the irq will be released.
++ */
++void shutdown_for_kgdb(struct async_struct * info)
++{
++        int irq = info->state->irq;
++        struct uart_8250_port *up;
++      int ttyS;
++
++      kgdb_irq = irq;                 /* save for later init */
++      for (ttyS = 0; ttyS < UART_NR; ttyS++){
++              up =  &serial8250_ports[ttyS];
++              if (up->port.irq == irq && (irq_lists + irq)->head) {
++#ifdef CONFIG_DEBUG_SPINLOCK   /* ugly business... */
++                      if(up->port.lock.magic != SPINLOCK_MAGIC)
++                              spin_lock_init(&up->port.lock);
++#endif
++                      serial8250_shutdown(&up->port);
++              }
++        }
++}
++#endif        /* CONFIG_KGDB */
++
+ static int __init serial8250_init(void)
+ {
+       int ret, i;
+--- linux-2.6.0-test6/drivers/serial/serial_core.c     2003-09-27 18:57:46.000000000 -0700
++++ 25/drivers/serial/serial_core.c    2003-10-05 00:36:10.000000000 -0700
+@@ -263,9 +263,9 @@ static void uart_shutdown(struct uart_st
+ /**
+  *    uart_update_timeout - update per-port FIFO timeout.
+- *    @port: uart_port structure describing the port.
++ *    @port:  uart_port structure describing the port
+  *    @cflag: termios cflag value
+- *    @quot: uart clock divisor quotient
++ *    @baud:  speed of the port
+  *
+  *    Set the port FIFO timeout value.  The @cflag value should
+  *    reflect the actual hardware settings.
+@@ -1973,6 +1973,11 @@ uart_configure_port(struct uart_driver *
+ {
+       unsigned int flags;
++#ifdef CONFIG_KGDB
++      if (port->kgdb)
++              return;
++#endif
++
+       /*
+        * If there isn't a port here, don't do anything further.
+        */
+--- linux-2.6.0-test6/drivers/telephony/ixj.h  2003-06-22 12:04:44.000000000 -0700
++++ 25/drivers/telephony/ixj.h 2003-10-05 00:33:24.000000000 -0700
+@@ -42,6 +42,7 @@ static char ixj_h_rcsid[] = "$Id: ixj.h,
+ #define IXJ_VERSION 3031
++#include <linux/version.h>
+ #include <linux/types.h>
+ #include <linux/ixjuser.h>
+--- linux-2.6.0-test6/drivers/telephony/phonedev.c     2003-09-08 13:58:58.000000000 -0700
++++ 25/drivers/telephony/phonedev.c    2003-10-05 00:33:24.000000000 -0700
+@@ -14,7 +14,6 @@
+  *              phone_register_device now works with unit!=PHONE_UNIT_ANY
+  */
+-#include <linux/version.h>
+ #include <linux/module.h>
+ #include <linux/types.h>
+ #include <linux/kernel.h>
+--- linux-2.6.0-test6/drivers/usb/core/inode.c 2003-09-08 13:58:58.000000000 -0700
++++ 25/drivers/usb/core/inode.c        2003-10-05 00:33:24.000000000 -0700
+@@ -38,6 +38,7 @@
+ #include <linux/namei.h>
+ #include <linux/usbdevice_fs.h>
+ #include <linux/smp_lock.h>
++#include <linux/parser.h>
+ #include <asm/byteorder.h>
+ static struct super_operations usbfs_ops;
+@@ -62,86 +63,94 @@ static umode_t devmode = S_IWUSR | S_IRU
+ static umode_t busmode = S_IXUGO | S_IRUGO;
+ static umode_t listmode = S_IRUGO;
++enum {
++      Opt_devuid, Opt_devgid, Opt_devmode,
++      Opt_busuid, Opt_busgid, Opt_busmode,
++      Opt_listuid, Opt_listgid, Opt_listmode,
++      Opt_err,
++};
++
++static match_table_t tokens = {
++      {Opt_devuid, "devuid=%u"},
++      {Opt_devgid, "devgid=%u"},
++      {Opt_devmode, "devmode=%o"},
++      {Opt_busuid, "busuid=%u"},
++      {Opt_busgid, "busgid=%u"},
++      {Opt_busmode, "busmode=%o"},
++      {Opt_listuid, "listuid=%u"},
++      {Opt_listgid, "listgid=%u"},
++      {Opt_listmode, "listmode=%o"},
++      {Opt_err, NULL}
++};
++
+ static int parse_options(struct super_block *s, char *data)
+ {
+-      char *curopt = NULL, *value;
++      char *p;
++      int option;
+-      while ((curopt = strsep(&data, ",")) != NULL) {
+-              if (!*curopt)
++      while ((p = strsep(&data, ",")) != NULL) {
++              substring_t args[MAX_OPT_ARGS];
++              int token;
++              if (!*p)
+                       continue;
+-              if ((value = strchr(curopt, '=')) != NULL)
+-                      *value++ = 0;
+-              if (!strcmp(curopt, "devuid")) {
+-                      if (!value || !value[0])
+-                              return -EINVAL;
+-                      devuid = simple_strtoul(value, &value, 0);
+-                      if (*value)
+-                              return -EINVAL;
+-              }
+-              if (!strcmp(curopt, "devgid")) {
+-                      if (!value || !value[0])
+-                              return -EINVAL;
+-                      devgid = simple_strtoul(value, &value, 0);
+-                      if (*value)
+-                              return -EINVAL;
+-              }
+-              if (!strcmp(curopt, "devmode")) {
+-                      if (!value || !value[0])
+-                              return -EINVAL;
+-                      devmode = simple_strtoul(value, &value, 0) & S_IRWXUGO;
+-                      if (*value)
+-                              return -EINVAL;
+-              }
+-              if (!strcmp(curopt, "busuid")) {
+-                      if (!value || !value[0])
+-                              return -EINVAL;
+-                      busuid = simple_strtoul(value, &value, 0);
+-                      if (*value)
+-                              return -EINVAL;
+-              }
+-              if (!strcmp(curopt, "busgid")) {
+-                      if (!value || !value[0])
+-                              return -EINVAL;
+-                      busgid = simple_strtoul(value, &value, 0);
+-                      if (*value)
+-                              return -EINVAL;
+-              }
+-              if (!strcmp(curopt, "busmode")) {
+-                      if (!value || !value[0])
+-                              return -EINVAL;
+-                      busmode = simple_strtoul(value, &value, 0) & S_IRWXUGO;
+-                      if (*value)
+-                              return -EINVAL;
+-              }
+-              if (!strcmp(curopt, "listuid")) {
+-                      if (!value || !value[0])
+-                              return -EINVAL;
+-                      listuid = simple_strtoul(value, &value, 0);
+-                      if (*value)
+-                              return -EINVAL;
+-              }
+-              if (!strcmp(curopt, "listgid")) {
+-                      if (!value || !value[0])
+-                              return -EINVAL;
+-                      listgid = simple_strtoul(value, &value, 0);
+-                      if (*value)
++
++              token = match_token(p, tokens, args);
++              switch (token) {
++              case Opt_devuid:
++                      if (match_int(&args[0], &option))
++                             return -EINVAL;
++                      devuid = option;
++                      break;
++              case Opt_devgid:
++                      if (match_int(&args[0], &option))
++                             return -EINVAL;
++                      devgid = option;
++                      break;
++              case Opt_devmode:
++                      if (match_octal(&args[0], &option))
+                               return -EINVAL;
+-              }
+-              if (!strcmp(curopt, "listmode")) {
+-                      if (!value || !value[0])
++                      devmode = option & S_IRWXUGO;
++                      break;
++              case Opt_busuid:
++                      if (match_int(&args[0], &option))
++                             return -EINVAL;
++                      busuid = option;
++                      break;
++              case Opt_busgid:
++                      if (match_int(&args[0], &option))
++                             return -EINVAL;
++                      busgid = option;
++                      break;
++              case Opt_busmode:
++                      if (match_octal(&args[0], &option))
+                               return -EINVAL;
+-                      listmode = simple_strtoul(value, &value, 0) & S_IRWXUGO;
+-                      if (*value)
++                      busmode = option & S_IRWXUGO;
++                      break;
++              case Opt_listuid:
++                      if (match_int(&args[0], &option))
++                             return -EINVAL;
++                      listuid = option;
++                      break;
++              case Opt_listgid:
++                      if (match_int(&args[0], &option))
++                             return -EINVAL;
++                      listgid = option;
++                      break;
++              case Opt_listmode:
++                      if (match_octal(&args[0], &option))
+                               return -EINVAL;
++                      listmode = option & S_IRWXUGO;
++                      break;
++              default:
++                      err("usbfs: unrecognised mount option \"%s\" "
++                          "or missing value\n", p);
++                      return -EINVAL;
+               }
+       }
+       return 0;
+ }
+-
+-/* --------------------------------------------------------------------- */
+-
+ static struct inode *usbfs_get_inode (struct super_block *sb, int mode, dev_t dev)
+ {
+       struct inode *inode = new_inode(sb);
+--- linux-2.6.0-test6/drivers/usb/host/uhci-debug.c    2003-07-02 14:53:16.000000000 -0700
++++ 25/drivers/usb/host/uhci-debug.c   2003-10-05 00:33:24.000000000 -0700
+@@ -99,82 +99,6 @@ static int uhci_show_td(struct uhci_td *
+       return out - buf;
+ }
+-static int uhci_show_sc(int port, unsigned short status, char *buf, int len)
+-{
+-      char *out = buf;
+-
+-      /* Try to make sure there's enough memory */
+-      if (len < 80)
+-              return 0;
+-
+-      out += sprintf(out, "  stat%d     =     %04x   %s%s%s%s%s%s%s%s\n",
+-              port,
+-              status,
+-              (status & USBPORTSC_SUSP) ? "PortSuspend " : "",
+-              (status & USBPORTSC_PR) ?   "PortReset " : "",
+-              (status & USBPORTSC_LSDA) ? "LowSpeed " : "",
+-              (status & USBPORTSC_RD) ?   "ResumeDetect " : "",
+-              (status & USBPORTSC_PEC) ?  "EnableChange " : "",
+-              (status & USBPORTSC_PE) ?   "PortEnabled " : "",
+-              (status & USBPORTSC_CSC) ?  "ConnectChange " : "",
+-              (status & USBPORTSC_CCS) ?  "PortConnected " : "");
+-
+-      return out - buf;
+-}
+-
+-static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len)
+-{
+-      char *out = buf;
+-      unsigned int io_addr = uhci->io_addr;
+-      unsigned short usbcmd, usbstat, usbint, usbfrnum;
+-      unsigned int flbaseadd;
+-      unsigned char sof;
+-      unsigned short portsc1, portsc2;
+-
+-      /* Try to make sure there's enough memory */
+-      if (len < 80 * 6)
+-              return 0;
+-
+-      usbcmd    = inw(io_addr + 0);
+-      usbstat   = inw(io_addr + 2);
+-      usbint    = inw(io_addr + 4);
+-      usbfrnum  = inw(io_addr + 6);
+-      flbaseadd = inl(io_addr + 8);
+-      sof       = inb(io_addr + 12);
+-      portsc1   = inw(io_addr + 16);
+-      portsc2   = inw(io_addr + 18);
+-
+-      out += sprintf(out, "  usbcmd    =     %04x   %s%s%s%s%s%s%s%s\n",
+-              usbcmd,
+-              (usbcmd & USBCMD_MAXP) ?    "Maxp64 " : "Maxp32 ",
+-              (usbcmd & USBCMD_CF) ?      "CF " : "",
+-              (usbcmd & USBCMD_SWDBG) ?   "SWDBG " : "",
+-              (usbcmd & USBCMD_FGR) ?     "FGR " : "",
+-              (usbcmd & USBCMD_EGSM) ?    "EGSM " : "",
+-              (usbcmd & USBCMD_GRESET) ?  "GRESET " : "",
+-              (usbcmd & USBCMD_HCRESET) ? "HCRESET " : "",
+-              (usbcmd & USBCMD_RS) ?      "RS " : "");
+-
+-      out += sprintf(out, "  usbstat   =     %04x   %s%s%s%s%s%s\n",
+-              usbstat,
+-              (usbstat & USBSTS_HCH) ?    "HCHalted " : "",
+-              (usbstat & USBSTS_HCPE) ?   "HostControllerProcessError " : "",
+-              (usbstat & USBSTS_HSE) ?    "HostSystemError " : "",
+-              (usbstat & USBSTS_RD) ?     "ResumeDetect " : "",
+-              (usbstat & USBSTS_ERROR) ?  "USBError " : "",
+-              (usbstat & USBSTS_USBINT) ? "USBINT " : "");
+-
+-      out += sprintf(out, "  usbint    =     %04x\n", usbint);
+-      out += sprintf(out, "  usbfrnum  =   (%d)%03x\n", (usbfrnum >> 10) & 1,
+-              0xfff & (4*(unsigned int)usbfrnum));
+-      out += sprintf(out, "  flbaseadd = %08x\n", flbaseadd);
+-      out += sprintf(out, "  sof       =       %02x\n", sof);
+-      out += uhci_show_sc(1, portsc1, out, len - (out - buf));
+-      out += uhci_show_sc(2, portsc2, out, len - (out - buf));
+-
+-      return out - buf;
+-}
+-
+ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
+ {
+       char *out = buf;
+@@ -274,6 +198,13 @@ out:
+       return out - buf;
+ }
++#define show_frame_num()      \
++      if (!shown) {           \
++        shown = 1;            \
++        out += sprintf(out, "- Frame %d\n", i); \
++      }
++
++#ifdef CONFIG_PROC_FS
+ static const char *qh_names[] = {
+   "skel_int128_qh", "skel_int64_qh",
+   "skel_int32_qh", "skel_int16_qh",
+@@ -283,18 +214,88 @@ static const char *qh_names[] = {
+   "skel_bulk_qh", "skel_term_qh"
+ };
+-#define show_frame_num()      \
+-      if (!shown) {           \
+-        shown = 1;            \
+-        out += sprintf(out, "- Frame %d\n", i); \
+-      }
+-
+ #define show_qh_name()                \
+       if (!shown) {           \
+         shown = 1;            \
+         out += sprintf(out, "- %s\n", qh_names[i]); \
+       }
++static int uhci_show_sc(int port, unsigned short status, char *buf, int len)
++{
++      char *out = buf;
++
++      /* Try to make sure there's enough memory */
++      if (len < 80)
++              return 0;
++
++      out += sprintf(out, "  stat%d     =     %04x   %s%s%s%s%s%s%s%s\n",
++              port,
++              status,
++              (status & USBPORTSC_SUSP) ? "PortSuspend " : "",
++              (status & USBPORTSC_PR) ?   "PortReset " : "",
++              (status & USBPORTSC_LSDA) ? "LowSpeed " : "",
++              (status & USBPORTSC_RD) ?   "ResumeDetect " : "",
++              (status & USBPORTSC_PEC) ?  "EnableChange " : "",
++              (status & USBPORTSC_PE) ?   "PortEnabled " : "",
++              (status & USBPORTSC_CSC) ?  "ConnectChange " : "",
++              (status & USBPORTSC_CCS) ?  "PortConnected " : "");
++
++      return out - buf;
++}
++
++static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len)
++{
++      char *out = buf;
++      unsigned int io_addr = uhci->io_addr;
++      unsigned short usbcmd, usbstat, usbint, usbfrnum;
++      unsigned int flbaseadd;
++      unsigned char sof;
++      unsigned short portsc1, portsc2;
++
++      /* Try to make sure there's enough memory */
++      if (len < 80 * 6)
++              return 0;
++
++      usbcmd    = inw(io_addr + 0);
++      usbstat   = inw(io_addr + 2);
++      usbint    = inw(io_addr + 4);
++      usbfrnum  = inw(io_addr + 6);
++      flbaseadd = inl(io_addr + 8);
++      sof       = inb(io_addr + 12);
++      portsc1   = inw(io_addr + 16);
++      portsc2   = inw(io_addr + 18);
++
++      out += sprintf(out, "  usbcmd    =     %04x   %s%s%s%s%s%s%s%s\n",
++              usbcmd,
++              (usbcmd & USBCMD_MAXP) ?    "Maxp64 " : "Maxp32 ",
++              (usbcmd & USBCMD_CF) ?      "CF " : "",
++              (usbcmd & USBCMD_SWDBG) ?   "SWDBG " : "",
++              (usbcmd & USBCMD_FGR) ?     "FGR " : "",
++              (usbcmd & USBCMD_EGSM) ?    "EGSM " : "",
++              (usbcmd & USBCMD_GRESET) ?  "GRESET " : "",
++              (usbcmd & USBCMD_HCRESET) ? "HCRESET " : "",
++              (usbcmd & USBCMD_RS) ?      "RS " : "");
++
++      out += sprintf(out, "  usbstat   =     %04x   %s%s%s%s%s%s\n",
++              usbstat,
++              (usbstat & USBSTS_HCH) ?    "HCHalted " : "",
++              (usbstat & USBSTS_HCPE) ?   "HostControllerProcessError " : "",
++              (usbstat & USBSTS_HSE) ?    "HostSystemError " : "",
++              (usbstat & USBSTS_RD) ?     "ResumeDetect " : "",
++              (usbstat & USBSTS_ERROR) ?  "USBError " : "",
++              (usbstat & USBSTS_USBINT) ? "USBINT " : "");
++
++      out += sprintf(out, "  usbint    =     %04x\n", usbint);
++      out += sprintf(out, "  usbfrnum  =   (%d)%03x\n", (usbfrnum >> 10) & 1,
++              0xfff & (4*(unsigned int)usbfrnum));
++      out += sprintf(out, "  flbaseadd = %08x\n", flbaseadd);
++      out += sprintf(out, "  sof       =       %02x\n", sof);
++      out += uhci_show_sc(1, portsc1, out, len - (out - buf));
++      out += uhci_show_sc(2, portsc2, out, len - (out - buf));
++
++      return out - buf;
++}
++
+ static int uhci_show_urbp(struct uhci_hcd *uhci, struct urb_priv *urbp, char *buf, int len)
+ {
+       struct list_head *tmp;
+@@ -512,7 +513,6 @@ static int uhci_sprint_schedule(struct u
+       return out - buf;
+ }
+-#ifdef CONFIG_PROC_FS
+ #define MAX_OUTPUT    (64 * 1024)
+ static struct proc_dir_entry *uhci_proc_root = NULL;
+--- linux-2.6.0-test6/drivers/usb/host/uhci-hcd.c      2003-09-27 18:57:46.000000000 -0700
++++ 25/drivers/usb/host/uhci-hcd.c     2003-10-05 00:33:24.000000000 -0700
+@@ -2185,8 +2185,8 @@ static int uhci_reset(struct usb_hcd *hc
+       /* Maybe kick BIOS off this hardware.  Then reset, so we won't get
+        * interrupts from any previous setup.
+        */
+-      pci_write_config_word(hcd->pdev, USBLEGSUP, USBLEGSUP_DEFAULT);
+       reset_hc(uhci);
++      pci_write_config_word(hcd->pdev, USBLEGSUP, USBLEGSUP_DEFAULT);
+       return 0;
+ }
+--- linux-2.6.0-test6/drivers/usb/input/Kconfig        2003-09-27 18:57:46.000000000 -0700
++++ 25/drivers/usb/input/Kconfig       2003-10-05 00:33:24.000000000 -0700
+@@ -186,8 +186,5 @@ config USB_XPAD
+         For information about how to connect the X-Box pad to USB, see
+         Documentation/input/xpad.txt.
+-        This driver is also available as a module ( = code which can be
+-        inserted in and removed from the running kernel whenever you want).
+-        The module will be called xpad.  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 xpad.
+--- linux-2.6.0-test6/drivers/usb/misc/brlvger.c       2003-09-08 13:58:58.000000000 -0700
++++ 25/drivers/usb/misc/brlvger.c      2003-10-05 00:33:24.000000000 -0700
+@@ -591,14 +591,14 @@ brlvger_write(struct file *file, const c
+                       int firstpart = 6 - off;
+                       
+ #ifdef WRITE_DEBUG
+-                      dbg3("off: %d, rs: %d, count: %d, firstpart: %d",
++                      dbg3("off: %lld, rs: %d, count: %d, firstpart: %d",
+                            off, rs, count, firstpart);
+ #endif
+                       firstpart = (firstpart < count) ? firstpart : count;
+ #ifdef WRITE_DEBUG
+-                      dbg3("off: %d", off);
++                      dbg3("off: %lld", off);
+                       dbg3("firstpart: %d", firstpart);
+ #endif
+@@ -618,7 +618,7 @@ brlvger_write(struct file *file, const c
+                       off +=2;
+ #ifdef WRITE_DEBUG
+-                      dbg3("off: %d, rs: %d, count: %d, firstpart: %d, "
++                      dbg3("off: %lld, rs: %d, count: %d, firstpart: %d, "
+                               "written: %d",  off, rs, count, firstpart, written);
+ #endif
+               }
+--- linux-2.6.0-test6/drivers/usb/misc/speedtch.c      2003-09-27 18:57:46.000000000 -0700
++++ 25/drivers/usb/misc/speedtch.c     2003-10-05 00:33:24.000000000 -0700
+@@ -189,8 +189,7 @@ struct udsl_vcc_data {
+       struct atm_vcc *vcc;
+       /* raw cell reassembly */
+-      struct sk_buff *skb;
+-      unsigned int max_pdu;
++      struct sk_buff *sarb;
+ };
+ /* send */
+@@ -314,12 +313,10 @@ static void udsl_extract_cells (struct u
+ {
+       struct udsl_vcc_data *cached_vcc = NULL;
+       struct atm_vcc *vcc;
+-      struct sk_buff *skb;
++      struct sk_buff *sarb;
+       struct udsl_vcc_data *vcc_data;
+       int cached_vci = 0;
+       unsigned int i;
+-      unsigned int length;
+-      unsigned int pdu_length;
+       int pti;
+       int vci;
+       short cached_vpi = 0;
+@@ -344,74 +341,73 @@ static void udsl_extract_cells (struct u
+               }
+               vcc = vcc_data->vcc;
++              sarb = vcc_data->sarb;
+-              if (!vcc_data->skb && !(vcc_data->skb = dev_alloc_skb (vcc_data->max_pdu))) {
+-                      dbg ("udsl_extract_cells: no memory for skb (vcc: 0x%p)!", vcc);
+-                      if (pti)
+-                              atomic_inc (&vcc->stats->rx_err);
+-                      continue;
+-              }
+-
+-              skb = vcc_data->skb;
+-
+-              if (skb->len + ATM_CELL_PAYLOAD > vcc_data->max_pdu) {
+-                      dbg ("udsl_extract_cells: buffer overrun (max_pdu: %u, skb->len %u, vcc: 0x%p)", vcc_data->max_pdu, skb->len, vcc);
++              if (sarb->tail + ATM_CELL_PAYLOAD > sarb->end) {
++                      dbg ("udsl_extract_cells: buffer overrun (sarb->len %u, vcc: 0x%p)!", sarb->len, vcc);
+                       /* discard cells already received */
+-                      skb_trim (skb, 0);
+-                      DEBUG_ON (vcc_data->max_pdu < ATM_CELL_PAYLOAD);
++                      skb_trim (sarb, 0);
+               }
+-              memcpy (skb->tail, source + ATM_CELL_HEADER, ATM_CELL_PAYLOAD);
+-              __skb_put (skb, ATM_CELL_PAYLOAD);
++              memcpy (sarb->tail, source + ATM_CELL_HEADER, ATM_CELL_PAYLOAD);
++              __skb_put (sarb, ATM_CELL_PAYLOAD);
+               if (pti) {
++                      struct sk_buff *skb;
++                      unsigned int length;
++                      unsigned int pdu_length;
++
+                       length = (source [ATM_CELL_SIZE - 6] << 8) + source [ATM_CELL_SIZE - 5];
+                       /* guard against overflow */
+                       if (length > ATM_MAX_AAL5_PDU) {
+-                              dbg ("udsl_extract_cells: bogus length %u (vcc: 0x%p)", length, vcc);
+-                              goto drop;
++                              dbg ("udsl_extract_cells: bogus length %u (vcc: 0x%p)!", length, vcc);
++                              atomic_inc (&vcc->stats->rx_err);
++                              goto out;
+                       }
+                       pdu_length = UDSL_NUM_CELLS (length) * ATM_CELL_PAYLOAD;
+-                      if (skb->len < pdu_length) {
+-                              dbg ("udsl_extract_cells: bogus pdu_length %u (skb->len: %u, vcc: 0x%p)", pdu_length, skb->len, vcc);
+-                              goto drop;
++                      if (sarb->len < pdu_length) {
++                              dbg ("udsl_extract_cells: bogus pdu_length %u (sarb->len: %u, vcc: 0x%p)!", pdu_length, sarb->len, vcc);
++                              atomic_inc (&vcc->stats->rx_err);
++                              goto out;
+                       }
+-                      if (crc32_be (~0, skb->tail - pdu_length, pdu_length) != 0xc704dd7b) {
+-                              dbg ("udsl_extract_cells: packet failed crc check (vcc: 0x%p)", vcc);
+-                              goto drop;
++                      if (crc32_be (~0, sarb->tail - pdu_length, pdu_length) != 0xc704dd7b) {
++                              dbg ("udsl_extract_cells: packet failed crc check (vcc: 0x%p)!", vcc);
++                              atomic_inc (&vcc->stats->rx_err);
++                              goto out;
+                       }
+-                      if (!atm_charge (vcc, skb->truesize)) {
+-                              dbg ("udsl_extract_cells: failed atm_charge (skb->truesize: %u)", skb->truesize);
+-                              goto drop_no_stats; /* atm_charge increments rx_drop */
+-                      }
++                      vdbg ("udsl_extract_cells: got packet (length: %u, pdu_length: %u, vcc: 0x%p)", length, pdu_length, vcc);
+-                      /* now that we are sure to send the skb, it is ok to change skb->data */
+-                      if (skb->len > pdu_length)
+-                              skb_pull (skb, skb->len - pdu_length); /* discard initial junk */
++                      if (!(skb = dev_alloc_skb (length))) {
++                              dbg ("udsl_extract_cells: no memory for skb (length: %u)!", length);
++                              atomic_inc (&vcc->stats->rx_drop);
++                              goto out;
++                      }
+-                      skb_trim (skb, length); /* drop zero padding and trailer */
++                      vdbg ("udsl_extract_cells: allocated new sk_buff (skb: 0x%p, skb->truesize: %u)", skb, skb->truesize);
+-                      atomic_inc (&vcc->stats->rx);
++                      if (!atm_charge (vcc, skb->truesize)) {
++                              dbg ("udsl_extract_cells: failed atm_charge (skb->truesize: %u)!", skb->truesize);
++                              dev_kfree_skb (skb);
++                              goto out; /* atm_charge increments rx_drop */
++                      }
+-                      PACKETDEBUG (skb->data, skb->len);
++                      memcpy (skb->data, sarb->tail - pdu_length, length);
++                      __skb_put (skb, length);
+                       vdbg ("udsl_extract_cells: sending skb 0x%p, skb->len %u, skb->truesize %u", skb, skb->len, skb->truesize);
+-                      vcc->push (vcc, skb);
+-
+-                      vcc_data->skb = NULL;
++                      PACKETDEBUG (skb->data, skb->len);
+-                      continue;
++                      vcc->push (vcc, skb);
+-drop:
+-                      atomic_inc (&vcc->stats->rx_err);
+-drop_no_stats:
+-                      skb_trim (skb, 0);
++                      atomic_inc (&vcc->stats->rx);
++out:
++                      skb_trim (sarb, 0);
+               }
+       }
+ }
+@@ -871,6 +867,7 @@ static int udsl_atm_open (struct atm_vcc
+ {
+       struct udsl_instance_data *instance = vcc->dev->dev_data;
+       struct udsl_vcc_data *new;
++      unsigned int max_pdu;
+       dbg ("udsl_atm_open: vpi %hd, vci %d", vpi, vci);
+@@ -883,8 +880,10 @@ static int udsl_atm_open (struct atm_vcc
+               return -EINVAL;
+       /* only support AAL5 */
+-      if ((vcc->qos.aal != ATM_AAL5) || (vcc->qos.rxtp.max_sdu < 0) || (vcc->qos.rxtp.max_sdu > ATM_MAX_AAL5_PDU))
++      if ((vcc->qos.aal != ATM_AAL5) || (vcc->qos.rxtp.max_sdu < 0) || (vcc->qos.rxtp.max_sdu > ATM_MAX_AAL5_PDU)) {
++              dbg ("udsl_atm_open: unsupported ATM type %d!", vcc->qos.aal);
+               return -EINVAL;
++      }
+       if (!instance->firmware_loaded) {
+               dbg ("udsl_atm_open: firmware not loaded!");
+@@ -894,11 +893,13 @@ static int udsl_atm_open (struct atm_vcc
+       down (&instance->serialize); /* vs self, udsl_atm_close */
+       if (udsl_find_vcc (instance, vpi, vci)) {
++              dbg ("udsl_atm_open: %hd/%d already in use!", vpi, vci);
+               up (&instance->serialize);
+               return -EADDRINUSE;
+       }
+       if (!(new = kmalloc (sizeof (struct udsl_vcc_data), GFP_KERNEL))) {
++              dbg ("udsl_atm_open: no memory for vcc_data!");
+               up (&instance->serialize);
+               return -ENOMEM;
+       }
+@@ -907,7 +908,15 @@ static int udsl_atm_open (struct atm_vcc
+       new->vcc = vcc;
+       new->vpi = vpi;
+       new->vci = vci;
+-      new->max_pdu = max (1, UDSL_NUM_CELLS (vcc->qos.rxtp.max_sdu)) * ATM_CELL_PAYLOAD;
++
++      /* udsl_extract_cells requires at least one cell */
++      max_pdu = max (1, UDSL_NUM_CELLS (vcc->qos.rxtp.max_sdu)) * ATM_CELL_PAYLOAD;
++      if (!(new->sarb = alloc_skb (max_pdu, GFP_KERNEL))) {
++              dbg ("udsl_atm_open: no memory for SAR buffer!");
++              kfree (new);
++              up (&instance->serialize);
++              return -ENOMEM;
++      }
+       vcc->dev_data = new;
+       vcc->vpi = vpi;
+@@ -925,7 +934,7 @@ static int udsl_atm_open (struct atm_vcc
+       tasklet_schedule (&instance->receive_tasklet);
+-      dbg ("udsl_atm_open: allocated vcc data 0x%p (max_pdu: %u)", new, new->max_pdu);
++      dbg ("udsl_atm_open: allocated vcc data 0x%p (max_pdu: %u)", new, max_pdu);
+       return 0;
+ }
+@@ -952,9 +961,8 @@ static void udsl_atm_close (struct atm_v
+       list_del (&vcc_data->list);
+       tasklet_enable (&instance->receive_tasklet);
+-      if (vcc_data->skb)
+-              dev_kfree_skb (vcc_data->skb);
+-      vcc_data->skb = NULL;
++      kfree_skb (vcc_data->sarb);
++      vcc_data->sarb = NULL;
+       kfree (vcc_data);
+       vcc->dev_data = NULL;
+@@ -1216,7 +1224,7 @@ static void udsl_usb_disconnect (struct 
+       for (i = 0; i < num_rcv_urbs; i++)
+               if ((result = usb_unlink_urb (instance->receivers [i].urb)) < 0)
+-                      dbg ("udsl_usb_disconnect: usb_unlink_urb on receive urb %d returned %d", i, result);
++                      dbg ("udsl_usb_disconnect: usb_unlink_urb on receive urb %d returned %d!", i, result);
+       /* wait for completion handlers to finish */
+       do {
+@@ -1252,7 +1260,7 @@ static void udsl_usb_disconnect (struct 
+       for (i = 0; i < num_snd_urbs; i++)
+               if ((result = usb_unlink_urb (instance->senders [i].urb)) < 0)
+-                      dbg ("udsl_usb_disconnect: usb_unlink_urb on send urb %d returned %d", i, result);
++                      dbg ("udsl_usb_disconnect: usb_unlink_urb on send urb %d returned %d!", i, result);
+       /* wait for completion handlers to finish */
+       do {
+@@ -1298,11 +1306,9 @@ static void udsl_usb_disconnect (struct 
+ static int __init udsl_usb_init (void)
+ {
+-      struct sk_buff *skb; /* dummy for sizeof */
+-
+       dbg ("udsl_usb_init: driver version " DRIVER_VERSION);
+-      if (sizeof (struct udsl_control) > sizeof (skb->cb)) {
++      if (sizeof (struct udsl_control) > sizeof (((struct sk_buff *)0)->cb)) {
+               printk (KERN_ERR __FILE__ ": unusable with this kernel!\n");
+               return -EIO;
+       }
+--- linux-2.6.0-test6/drivers/usb/serial/keyspan.c     2003-09-08 13:58:58.000000000 -0700
++++ 25/drivers/usb/serial/keyspan.c    2003-10-05 00:33:24.000000000 -0700
+@@ -28,6 +28,9 @@
+   Change History
++    2003sep04 LPM (Keyspan) add support for new single port product USA19HS.
++                              Improve setup message handling for all devices.
++
+     Wed Feb 19 22:00:00 PST 2003 (Jeffrey S. Laing <keyspan@jsl.com>)
+       Merged the current (1/31/03) Keyspan code with the current (2.4.21-pre4)
+       Linux source tree.  The Linux tree lacked support for the 49WLC and
+@@ -172,6 +175,7 @@ struct keyspan_port_private {
+       int             baud;
+       int             old_baud;
+       unsigned int    cflag;
++      unsigned int    old_cflag;
+       enum            {flow_none, flow_cts, flow_xon} flow_control;
+       int             rts_state;      /* Handshaking pins (outputs) */
+       int             dtr_state;
+@@ -187,11 +191,12 @@ struct keyspan_port_private {
+       
+ /* Include Keyspan message headers.  All current Keyspan Adapters
+-   make use of one of three message formats which are referred
+-   to as USA-26, USA-28 and USA-49 by Keyspan and within this driver. */
++   make use of one of four message formats which are referred
++   to as USA-26, USA-28 and USA-49, USA-90 by Keyspan and within this driver. */
+ #include "keyspan_usa26msg.h"
+ #include "keyspan_usa28msg.h"
+ #include "keyspan_usa49msg.h"
++#include "keyspan_usa90msg.h"
+       
+ /* Functions used by new usb-serial code. */
+@@ -346,8 +351,8 @@ static int keyspan_ioctl(struct usb_seri
+       return -ENOIOCTLCMD;
+ }
+-      /* Write function is generic for the three protocols used
+-         with only a minor change for usa49 required */
++      /* Write function is similar for the four protocols used
++         with only a minor change for usa90 (usa19hs) required */
+ static int keyspan_write(struct usb_serial_port *port, int from_user, 
+                        const unsigned char *buf, int count)
+ {
+@@ -356,18 +361,26 @@ static int keyspan_write(struct usb_seri
+       int                             flip;
+       int                             left, todo;
+       struct urb                      *this_urb;
+-      int                             err;
++      int                             err, maxDataLen, dataOffset;
+       p_priv = usb_get_serial_port_data(port);
+       d_details = p_priv->device_details;
++      if (d_details->msg_format == msg_usa90) {
++              maxDataLen = 64;
++              dataOffset = 0;
++      } else {
++              maxDataLen = 63;
++              dataOffset = 1;
++      }
++      
+       dbg("%s - for port %d (%d chars), flip=%d",
+           __FUNCTION__, port->number, count, p_priv->out_flip);
+       for (left = count; left > 0; left -= todo) {
+               todo = left;
+-              if (todo > 63)
+-                      todo = 63;
++              if (todo > maxDataLen)
++                      todo = maxDataLen;
+               flip = p_priv->out_flip;
+       
+@@ -390,20 +403,20 @@ static int keyspan_write(struct usb_seri
+                       break;
+               }
+-              /* First byte in buffer is "last flag" - unused so
++              /* First byte in buffer is "last flag" (except for usa19hx) - unused so
+                  for now so set to zero */
+               ((char *)this_urb->transfer_buffer)[0] = 0;
+               if (from_user) {
+-                      if (copy_from_user(this_urb->transfer_buffer + 1, buf, todo))
++                      if (copy_from_user(this_urb->transfer_buffer + dataOffset, buf, todo))
+                               return -EFAULT;
+               } else {
+-                      memcpy (this_urb->transfer_buffer + 1, buf, todo);
++                      memcpy (this_urb->transfer_buffer + dataOffset, buf, todo);
+               }
+               buf += todo;
+               /* send the data out the bulk port */
+-              this_urb->transfer_buffer_length = todo + 1;
++              this_urb->transfer_buffer_length = todo + dataOffset;
+               this_urb->transfer_flags &= ~URB_ASYNC_UNLINK;
+               this_urb->dev = port->serial->dev;
+@@ -443,9 +456,12 @@ static void       usa26_indat_callback(struct 
+       if (urb->actual_length) {
+               /* 0x80 bit is error flag */
+               if ((data[0] & 0x80) == 0) {
+-                      /* no error on any byte */
++                      /* no errors on individual bytes, only possible overrun err*/
++                      if (data[0] & RXERROR_OVERRUN)
++                                      err = TTY_OVERRUN;
++                      else err = 0;
+                       for (i = 1; i < urb->actual_length ; ++i) {
+-                              tty_insert_flip_char(tty, data[i], 0);
++                              tty_insert_flip_char(tty, data[i], err);
+                       }
+               } else {
+                       /* some bytes had errors, every byte has status */
+@@ -474,7 +490,7 @@ static void        usa26_indat_callback(struct 
+       return;
+ }
+-      /* Outdat handling is common for usa26, usa28 and usa49 messages */
++      /* Outdat handling is common for all devices */
+ static void   usa2x_outdat_callback(struct urb *urb, struct pt_regs *regs)
+ {
+       struct usb_serial_port *port;
+@@ -577,7 +593,7 @@ static void        usa26_glocont_callback(struc
+ }
+-static void     usa28_indat_callback(struct urb *urb, struct pt_regs *regs)
++static void usa28_indat_callback(struct urb *urb, struct pt_regs *regs)
+ {
+       int                     i, err;
+       struct usb_serial_port  *port;
+@@ -861,29 +877,172 @@ static void     usa49_outcont_callback(struc
+       dbg ("%s", __FUNCTION__);
+ }
++static void   usa90_indat_callback(struct urb *urb, struct pt_regs *regs)
++{
++      int                     i, err;
++      int                     endpoint;
++      struct usb_serial_port  *port;
++      struct keyspan_port_private             *p_priv;
++      struct tty_struct       *tty;
++      unsigned char           *data = urb->transfer_buffer;
++
++      dbg ("%s", __FUNCTION__); 
++
++      endpoint = usb_pipeendpoint(urb->pipe);
++
++
++      if (urb->status) {
++              dbg("%s - nonzero status: %x on endpoint %d.",
++                  __FUNCTION__, urb->status, endpoint);
++              return;
++      }
++
++      port = (struct usb_serial_port *) urb->context;
++      p_priv = usb_get_serial_port_data(port);
++
++      tty = port->tty;
++      if (urb->actual_length) {
++      
++              /* if current mode is DMA, looks like usa28 format
++                      otherwise looks like usa26 data format */
++
++              if (p_priv->baud > 57600) {
++                      for (i = 0; i < urb->actual_length ; ++i) 
++                              tty_insert_flip_char(tty, data[i], 0);
++              }
++              else {
++                      
++                      /* 0x80 bit is error flag */
++                      if ((data[0] & 0x80) == 0) {
++                              /* no errors on individual bytes, only possible overrun err*/
++                              if (data[0] & RXERROR_OVERRUN)
++                                              err = TTY_OVERRUN;
++                              else err = 0;
++                              for (i = 1; i < urb->actual_length ; ++i) 
++                                      tty_insert_flip_char(tty, data[i], err);
++                      
++                      } 
++                      else {
++                      /* some bytes had errors, every byte has status */
++                              dbg("%s - RX error!!!!", __FUNCTION__);
++                              for (i = 0; i + 1 < urb->actual_length; i += 2) {
++                                      int stat = data[i], flag = 0;
++                                      if (stat & RXERROR_OVERRUN)
++                                              flag |= TTY_OVERRUN;
++                                      if (stat & RXERROR_FRAMING)
++                                              flag |= TTY_FRAME;
++                                      if (stat & RXERROR_PARITY)
++                                              flag |= TTY_PARITY;
++                                      /* XXX should handle break (0x10) */
++                                      tty_insert_flip_char(tty, data[i+1], flag);
++                              }
++                      }
++              }
++              tty_flip_buffer_push(tty);
++      }
++                              
++      /* Resubmit urb so we continue receiving */
++      urb->dev = port->serial->dev;
++      if (port->open_count)
++              if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) {
++                      dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
++              }
++      return;
++}
++
++
++static void   usa90_instat_callback(struct urb *urb, struct pt_regs *regs)
++{
++      unsigned char                           *data = urb->transfer_buffer;
++      struct keyspan_usa90_portStatusMessage  *msg;
++      struct usb_serial                       *serial;
++      struct usb_serial_port                  *port;
++      struct keyspan_port_private             *p_priv;
++      int old_dcd_state, err;
++
++      serial = (struct usb_serial *) urb->context;
++
++      if (urb->status) {
++              dbg("%s - nonzero status: %x", __FUNCTION__, urb->status);
++              return;
++      }
++      if (urb->actual_length < 14) {
++              dbg("%s - %d byte report??", __FUNCTION__, urb->actual_length);
++              goto exit;
++      }
++
++      msg = (struct keyspan_usa90_portStatusMessage *)data;
++
++      /* Now do something useful with the data */
++
++      port = serial->port[0];
++      p_priv = usb_get_serial_port_data(port);
++      
++      /* Update handshaking pin state information */
++      old_dcd_state = p_priv->dcd_state;
++      p_priv->cts_state = ((msg->cts) ? 1 : 0);
++      p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
++      p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
++      p_priv->ri_state = ((msg->ri) ? 1 : 0);
++
++      if (port->tty && !C_CLOCAL(port->tty)
++          && old_dcd_state != p_priv->dcd_state) {
++              if (old_dcd_state)
++                      tty_hangup(port->tty);
++              /*  else */
++              /*      wake_up_interruptible(&p_priv->open_wait); */
++      }
++      
++      /* Resubmit urb so we continue receiving */
++      urb->dev = serial->dev;
++      if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) {
++              dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
++      }
++exit:
++      ;
++}
++
++static void   usa90_outcont_callback(struct urb *urb, struct pt_regs *regs)
++{
++      struct usb_serial_port *port;
++      struct keyspan_port_private *p_priv;
++
++      port = (struct usb_serial_port *) urb->context;
++      p_priv = usb_get_serial_port_data(port);
++      if (p_priv->resend_cont) {
++              dbg ("%s - sending setup", __FUNCTION__); 
++              keyspan_usa90_send_setup(port->serial, port, p_priv->resend_cont - 1);
++      }
++}
+ static int keyspan_write_room (struct usb_serial_port *port)
+ {
+       struct keyspan_port_private     *p_priv;
+       const struct keyspan_device_details     *d_details;
+       int                             flip;
++      int                             data_len;
+       struct urb                      *this_urb;
+       dbg("%s", __FUNCTION__);
+       p_priv = usb_get_serial_port_data(port);
+       d_details = p_priv->device_details;
++      if (d_details->msg_format == msg_usa90)
++              data_len = 64;
++      else
++              data_len = 63;
++
+       flip = p_priv->out_flip;
+       /* Check both endpoints to see if any are available. */
+       if ((this_urb = p_priv->out_urbs[flip]) != 0) {
+               if (this_urb->status != -EINPROGRESS)
+-                      return (63);
++                      return (data_len);
+               flip = (flip + 1) & d_details->outdat_endp_flip;        
+               if ((this_urb = p_priv->out_urbs[flip]) != 0) 
+                       if (this_urb->status != -EINPROGRESS)
+-                              return (63);
++                              return (data_len);
+       }
+       return (0);
+ }
+@@ -902,17 +1061,24 @@ static int keyspan_open (struct usb_seri
+       struct usb_serial               *serial = port->serial;
+       const struct keyspan_device_details     *d_details;
+       int                             i, err;
++      int                             baud_rate, device_port;
+       struct urb                      *urb;
++      unsigned int                    cflag;
+       s_priv = usb_get_serial_data(serial);
+       p_priv = usb_get_serial_port_data(port);
+-      d_details = s_priv->device_details;
++      d_details = p_priv->device_details;
+       
+       dbg("%s - port%d.", __FUNCTION__, port->number); 
+       /* Set some sane defaults */
+       p_priv->rts_state = 1;
+       p_priv->dtr_state = 1;
++      p_priv->baud = 9600;
++
++      /* force baud and lcr to be set on open */
++      p_priv->old_baud = 0;
++      p_priv->old_cflag = 0;
+       p_priv->out_flip = 0;
+       p_priv->in_flip = 0;
+@@ -922,7 +1088,10 @@ static int keyspan_open (struct usb_seri
+               if ((urb = p_priv->in_urbs[i]) == NULL)
+                       continue;
+               urb->dev = serial->dev;
+-              usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), 0);
++
++              /* make sure endpoint data toggle is synchronized with the device */
++              
++              usb_clear_halt(urb->dev, urb->pipe);
+               if ((err = usb_submit_urb(urb, GFP_KERNEL)) != 0) {
+                       dbg("%s - submit urb %d failed (%d)", __FUNCTION__, i, err);
+@@ -937,12 +1106,29 @@ static int keyspan_open (struct usb_seri
+               /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), 0); */
+       }
+-      // if the device is a USA49x, determine whether it is an W or WLC model
+-      // and set the baud clock accordingly
++      /* get the terminal config for the setup message now so we don't 
++       * need to send 2 of them */
++
++      cflag = port->tty->termios->c_cflag;
++      device_port = port->number - port->serial->minor;
++
++      /* Baud rate calculation takes baud rate as an integer
++         so other rates can be generated if desired. */
++      baud_rate = tty_get_baud_rate(port->tty);
++      /* If no match or invalid, leave as default */          
++      if (baud_rate >= 0
++          && d_details->calculate_baud_rate(baud_rate, d_details->baudclk,
++                              NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
++              p_priv->baud = baud_rate;
++      }
++
++      /* set CTS/RTS handshake etc. */
++      p_priv->cflag = cflag;
++      p_priv->flow_control = (cflag & CRTSCTS)? flow_cts: flow_none;
+       keyspan_send_setup(port, 1);
+       //mdelay(100);
+-      keyspan_set_termios(port, NULL);
++      //keyspan_set_termios(port, NULL);
+       return (0);
+ }
+@@ -977,7 +1163,7 @@ static void keyspan_close(struct usb_ser
+               keyspan_send_setup(port, 2);
+               /* pilot-xfer seems to work best with this delay */
+               mdelay(100);
+-              keyspan_set_termios(port, NULL);
++              // keyspan_set_termios(port, NULL);
+       }
+       /*while (p_priv->outcont_urb->status == -EINPROGRESS) {
+@@ -1172,6 +1358,14 @@ static struct callbacks {
+               .outdat_callback =      usa2x_outdat_callback,
+               .inack_callback =       usa49_inack_callback,
+               .outcont_callback =     usa49_outcont_callback,
++      }, {
++              /* msg_usa90 callbacks */
++              .instat_callback =      usa90_instat_callback,
++              .glocont_callback =     usa28_glocont_callback,         
++              .indat_callback =       usa90_indat_callback,
++              .outdat_callback =      usa2x_outdat_callback,
++              .inack_callback =       usa28_inack_callback,
++              .outcont_callback =     usa90_outcont_callback,
+       }
+ };
+@@ -1295,6 +1489,41 @@ static int keyspan_usa19_calc_baud(u32 b
+       return (KEYSPAN_BAUD_RATE_OK);
+ }
++/* usa19hs function doesn't require prescaler */
++static int keyspan_usa19hs_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi,
++                                 u8 *rate_low, u8 *prescaler, int portnum)
++{
++      u32     b16,    /* baud rate times 16 (actual rate used internally) */
++                      div;    /* divisor */   
++              
++      dbg ("%s - %d.", __FUNCTION__, baud_rate);
++
++              /* prevent divide by zero...  */
++      if( (b16 = (baud_rate * 16L)) == 0) 
++              return (KEYSPAN_INVALID_BAUD_RATE);
++      
++
++
++              /* calculate the divisor */
++      if( (div = (baudclk / b16)) == 0) 
++              return (KEYSPAN_INVALID_BAUD_RATE);
++
++      if(div > 0xffff) 
++              return (KEYSPAN_INVALID_BAUD_RATE);
++
++              /* return the counter values if non-null */
++      if (rate_low) 
++              *rate_low = (u8) (div & 0xff);
++      
++      if (rate_hi) 
++              *rate_hi = (u8) ((div >> 8) & 0xff);
++      
++      if (rate_low && rate_hi) 
++              dbg ("%s - %d %02x %02x.", __FUNCTION__, baud_rate, *rate_hi, *rate_low);
++      
++      return (KEYSPAN_BAUD_RATE_OK);
++}
++
+ static int keyspan_usa19w_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi,
+                                   u8 *rate_low, u8 *prescaler, int portnum)
+ {
+@@ -1447,6 +1676,7 @@ static int keyspan_usa26_send_setup(stru
+               p_priv->resend_cont = reset_port + 1;
+       if (this_urb->status == -EINPROGRESS) {
+               /*  dbg ("%s - already writing", __FUNCTION__); */
++              mdelay(5);
+               return(-1);
+       }
+@@ -1597,6 +1827,7 @@ static int keyspan_usa28_send_setup(stru
+               p_priv->resend_cont = reset_port + 1;
+       if (this_urb->status == -EINPROGRESS) {
+               dbg ("%s already writing", __FUNCTION__);
++              mdelay(5);
+               return(-1);
+       }
+@@ -1729,6 +1960,7 @@ static int keyspan_usa49_send_setup(stru
+               p_priv->resend_cont = reset_port + 1;
+       if (this_urb->status == -EINPROGRESS) {
+               /*  dbg ("%s - already writing", __FUNCTION__); */
++              mdelay(5);
+               return(-1);
+       }
+@@ -1857,6 +2089,144 @@ static int keyspan_usa49_send_setup(stru
+       return (0);
+ }
++static int keyspan_usa90_send_setup(struct usb_serial *serial,
++                                  struct usb_serial_port *port,
++                                  int reset_port)
++{
++      struct keyspan_usa90_portControlMessage msg;            
++      struct keyspan_serial_private           *s_priv;
++      struct keyspan_port_private             *p_priv;
++      const struct keyspan_device_details     *d_details;
++      struct urb                              *this_urb;
++      int                                     err;
++      u8                                              prescaler;
++
++      dbg ("%s", __FUNCTION__);
++
++      s_priv = usb_get_serial_data(serial);
++      p_priv = usb_get_serial_port_data(port);
++      d_details = s_priv->device_details;
++
++      /* only do something if we have a bulk out endpoint */
++      if ((this_urb = p_priv->outcont_urb) == NULL) {
++              dbg("%s - oops no urb.", __FUNCTION__);
++              return -1;
++      }
++
++      /* Save reset port val for resend.
++         Don't overwrite resend for open/close condition. */
++      if ((reset_port + 1) > p_priv->resend_cont)
++              p_priv->resend_cont = reset_port + 1;
++      if (this_urb->status == -EINPROGRESS) {
++              dbg ("%s already writing", __FUNCTION__);
++              mdelay(5);
++              return(-1);
++      }
++
++      memset(&msg, 0, sizeof (struct keyspan_usa90_portControlMessage));
++
++      /* Only set baud rate if it's changed */        
++      if (p_priv->old_baud != p_priv->baud) {
++              p_priv->old_baud = p_priv->baud;
++              msg.setClocking = 0x01;
++              if (d_details->calculate_baud_rate
++                  (p_priv->baud, d_details->baudclk, &msg.baudHi,
++                   &msg.baudLo, &prescaler, 0) == KEYSPAN_INVALID_BAUD_RATE ) {
++                      dbg("%s - Invalid baud rate %d requested, using 9600.", __FUNCTION__,
++                          p_priv->baud);
++                      p_priv->baud = 9600;
++                      d_details->calculate_baud_rate (p_priv->baud, d_details->baudclk, 
++                              &msg.baudHi, &msg.baudLo, &prescaler, 0);
++              }
++              msg.setRxMode = 1;
++              msg.setTxMode = 1;
++      }
++
++      /* modes must always be correctly specified */
++      if (p_priv->baud > 57600)
++      {
++              msg.rxMode = RXMODE_DMA;
++              msg.txMode = TXMODE_DMA;
++      }
++      else
++      {
++              msg.rxMode = RXMODE_BYHAND;
++              msg.txMode = TXMODE_BYHAND;
++      }
++
++      msg.lcr = (p_priv->cflag & CSTOPB)? STOPBITS_678_2: STOPBITS_5678_1;
++      switch (p_priv->cflag & CSIZE) {
++      case CS5:
++              msg.lcr |= USA_DATABITS_5;
++              break;
++      case CS6:
++              msg.lcr |= USA_DATABITS_6;
++              break;
++      case CS7:
++              msg.lcr |= USA_DATABITS_7;
++              break;
++      case CS8:
++              msg.lcr |= USA_DATABITS_8;
++              break;
++      }
++      if (p_priv->cflag & PARENB) {
++              /* note USA_PARITY_NONE == 0 */
++              msg.lcr |= (p_priv->cflag & PARODD)?
++                      USA_PARITY_ODD: USA_PARITY_EVEN;
++      }
++      if (p_priv->old_cflag != p_priv->cflag) {
++              p_priv->old_cflag = p_priv->cflag;
++              msg.setLcr = 0x01;
++      }
++
++      if (p_priv->flow_control == flow_cts)
++              msg.txFlowControl = TXFLOW_CTS;
++      msg.setTxFlowControl = 0x01;
++      msg.setRxFlowControl = 0x01;
++      
++      msg.rxForwardingLength = 16;
++      msg.rxForwardingTimeout = 16;   
++      msg.txAckSetting = 0;
++      msg.xonChar = 17;
++      msg.xoffChar = 19;
++
++      /* Opening port */ 
++      if (reset_port == 1) {
++              msg.portEnabled = 1;
++              msg.rxFlush = 1;
++              msg.txBreak = (p_priv->break_on);
++      }
++      /* Closing port */
++      else if (reset_port == 2) {
++              msg.portEnabled = 0;
++      }
++      /* Sending intermediate configs */
++      else {
++              if (port->open_count)
++                      msg.portEnabled = 1;
++              msg.txBreak = (p_priv->break_on);
++      }
++
++      /* Do handshaking outputs */    
++      msg.setRts = 0x01;
++      msg.rts = p_priv->rts_state;
++
++      msg.setDtr = 0x01;
++      msg.dtr = p_priv->dtr_state;
++              
++      p_priv->resend_cont = 0;
++      memcpy (this_urb->transfer_buffer, &msg, sizeof(msg));
++      
++      /* send the data out the device on control endpoint */
++      this_urb->transfer_buffer_length = sizeof(msg);
++
++      this_urb->dev = serial->dev;
++      if ((err = usb_submit_urb(this_urb, GFP_ATOMIC)) != 0) {
++              dbg("%s - usb_submit_urb(setup) failed (%d)", __FUNCTION__, err);
++      }
++      return (0);
++}
++
+ static void keyspan_send_setup(struct usb_serial_port *port, int reset_port)
+ {
+       struct usb_serial *serial = port->serial;
+@@ -1878,9 +2248,13 @@ static void keyspan_send_setup(struct us
+       case msg_usa49:
+               keyspan_usa49_send_setup(serial, port, reset_port);
+               break;
++      case msg_usa90:
++              keyspan_usa90_send_setup(serial, port, reset_port);
++              break;
+       }
+ }
++
+ /* Gets called by the "real" driver (ie once firmware is loaded
+    and renumeration has taken place. */
+ static int keyspan_startup (struct usb_serial *serial)
+--- linux-2.6.0-test6/drivers/usb/serial/keyspan.h     2003-06-14 12:18:25.000000000 -0700
++++ 25/drivers/usb/serial/keyspan.h    2003-10-05 00:33:24.000000000 -0700
+@@ -82,6 +82,10 @@ static int  keyspan_usa28_calc_baud (u32
+                                        u8 *rate_hi, u8 *rate_low,
+                                        u8 *prescaler, int portnum);
++static int  keyspan_usa19hs_calc_baud (u32 baud_rate, u32 baudclk,
++                                       u8 *rate_hi, u8 *rate_low,
++                                       u8 *prescaler, int portnum);
++
+ static int  keyspan_usa28_send_setup  (struct usb_serial *serial,
+                                        struct usb_serial_port *port,
+                                        int reset_port);
+@@ -92,6 +96,9 @@ static int  keyspan_usa49_send_setup (st
+                                        struct usb_serial_port *port,
+                                        int reset_port);
++static int  keyspan_usa90_send_setup  (struct usb_serial *serial,
++                                       struct usb_serial_port *port,
++                                       int reset_port);
+ /* Struct used for firmware - increased size of data section
+    to allow Keyspan's 'C' firmware struct to be used unmodified */
+@@ -183,6 +190,7 @@ struct ezusb_hex_record {
+ #define       KEYSPAN_USA18X_BAUDCLK                  (12000000L)     /* a guess */
+ #define       KEYSPAN_USA19_BAUDCLK                   (12000000L)
+ #define       KEYSPAN_USA19W_BAUDCLK                  (24000000L)
++#define       KEYSPAN_USA19HS_BAUDCLK                 (14769231L)
+ #define       KEYSPAN_USA28_BAUDCLK                   (1843200L)
+ #define       KEYSPAN_USA28X_BAUDCLK                  (12000000L)
+ #define       KEYSPAN_USA49W_BAUDCLK                  (48000000L)
+@@ -215,6 +223,7 @@ struct ezusb_hex_record {
+ #define       keyspan_usa18x_product_id               0x0112
+ #define       keyspan_usa19_product_id                0x0107
+ #define       keyspan_usa19qi_product_id              0x010c
++#define       keyspan_usa19hs_product_id              0x0121
+ #define       keyspan_mpr_product_id                  0x011c
+ #define       keyspan_usa19qw_product_id              0x0119
+ #define       keyspan_usa19w_product_id               0x0108
+@@ -230,7 +239,7 @@ struct keyspan_device_details {
+       /* product ID value */
+       int     product_id;
+-      enum    {msg_usa26, msg_usa28, msg_usa49} msg_format;
++      enum    {msg_usa26, msg_usa28, msg_usa49, msg_usa90} msg_format;
+               /* Number of physical ports */
+       int     num_ports;
+@@ -349,6 +358,22 @@ static const struct keyspan_device_detai
+       .baudclk                = KEYSPAN_USA19W_BAUDCLK,
+ };
++static const struct keyspan_device_details usa19hs_device_details = {
++      product_id:             keyspan_usa19hs_product_id,
++      msg_format:             msg_usa90,
++      num_ports:              1,
++      indat_endp_flip:        0,
++      outdat_endp_flip:       0,
++      indat_endpoints:        {0x81},
++      outdat_endpoints:       {0x01},
++      inack_endpoints:        {-1},
++      outcont_endpoints:      {0x02},
++      instat_endpoint:        0x82,
++      glocont_endpoint:       -1,
++      calculate_baud_rate:    keyspan_usa19hs_calc_baud,
++      baudclk:                KEYSPAN_USA19HS_BAUDCLK,
++};
++
+ static const struct keyspan_device_details usa28_device_details = {
+       .product_id             = keyspan_usa28_product_id,
+       .msg_format             = msg_usa28,
+@@ -437,6 +462,7 @@ static const struct keyspan_device_detai
+       &usa19qi_device_details,
+       &usa19qw_device_details,
+       &usa19w_device_details,
++      &usa19hs_device_details,
+       &usa28_device_details,
+       &usa28x_device_details,
+       &usa28xa_device_details,
+@@ -464,6 +490,7 @@ static struct usb_device_id keyspan_ids_
+       { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_product_id) },
+       { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_product_id) },
+       { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_product_id) },
++      { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19hs_product_id) },
+       { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_product_id) },
+       { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) },
+       { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) },
+@@ -544,8 +571,8 @@ static struct usb_serial_device_type key
+       .short_name             = "keyspan_1",
+       .id_table               = keyspan_1port_ids,
+       .num_interrupt_in       = NUM_DONT_CARE,
+-      .num_bulk_in            = 3,
+-      .num_bulk_out           = 4,
++      .num_bulk_in            = NUM_DONT_CARE,
++      .num_bulk_out           = NUM_DONT_CARE,
+       .num_ports              = 1,
+       .open                   = keyspan_open,
+       .close                  = keyspan_close,
+--- linux-2.6.0-test6/drivers/usb/serial/keyspan_usa26msg.h    2003-09-08 13:58:58.000000000 -0700
++++ 25/drivers/usb/serial/keyspan_usa26msg.h   2003-10-05 00:33:24.000000000 -0700
+@@ -4,7 +4,7 @@
+       Copyright (C) 1998-2000 InnoSys Incorporated.  All Rights Reserved
+       This file is available under a BSD-style copyright
+-      Keyspan USB Async Firmware to run on Anchor EZ-USB
++      Keyspan USB Async Message Formats for the USA28X
+       Redistribution and use in source and binary forms, with or without
+       modification, are permitted provided that the following conditions are
+@@ -19,11 +19,7 @@
+               This file is available under a BSD-style copyright
+-      2. Redistributions in binary form must reproduce the above copyright
+-      notice, this list of conditions and the following disclaimer in the
+-      documentation and/or other materials provided with the distribution.
+-
+-      3. The name of InnoSys Incorporated may not be used to endorse or promote
++      2. The name of InnoSys Incorporated may not be used to endorse or promote
+       products derived from this software without specific prior written
+       permission.
+--- linux-2.6.0-test6/drivers/usb/serial/keyspan_usa28msg.h    2003-09-08 13:58:58.000000000 -0700
++++ 25/drivers/usb/serial/keyspan_usa28msg.h   2003-10-05 00:33:24.000000000 -0700
+@@ -4,7 +4,7 @@
+       Copyright (C) 1998-2000 InnoSys Incorporated.  All Rights Reserved
+       This file is available under a BSD-style copyright
+-      Keyspan USB Async Firmware to run on Anchor EZ-USB
++      Keyspan USB Async Message Formats for the USA26X
+       Redistribution and use in source and binary forms, with or without
+       modification, are permitted provided that the following conditions are
+@@ -19,11 +19,7 @@
+               This file is available under a BSD-style copyright
+-      2. Redistributions in binary form must reproduce the above copyright
+-      notice, this list of conditions and the following disclaimer in the
+-      documentation and/or other materials provided with the distribution.
+-
+-      3. The name of InnoSys Incorporated may not be used to endorse or promote
++      2. The name of InnoSys Incorporated may not be used to endorse or promote
+       products derived from this software without specific prior written
+       permission.
+--- linux-2.6.0-test6/drivers/usb/serial/keyspan_usa49msg.h    2003-09-08 13:58:58.000000000 -0700
++++ 25/drivers/usb/serial/keyspan_usa49msg.h   2003-10-05 00:33:24.000000000 -0700
+@@ -4,7 +4,7 @@
+       Copyright (C) 1998-2000 InnoSys Incorporated.  All Rights Reserved
+       This file is available under a BSD-style copyright
+-      Keyspan USB Async Firmware to run on Anchor EZ-USB
++      Keyspan USB Async Message Formats for the USA49W
+       Redistribution and use in source and binary forms, with or without
+       modification, are permitted provided that the following conditions are
+@@ -19,11 +19,7 @@
+               This file is available under a BSD-style copyright
+-      2. Redistributions in binary form must reproduce the above copyright
+-      notice, this list of conditions and the following disclaimer in the
+-      documentation and/or other materials provided with the distribution.
+-
+-      3. The name of InnoSys Incorporated may not be used to endorse or promote
++      2. The name of InnoSys Incorporated may not be used to endorse or promote
+       products derived from this software without specific prior written
+       permission.
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/drivers/usb/serial/keyspan_usa90msg.h   2003-10-05 00:33:24.000000000 -0700
+@@ -0,0 +1,198 @@
++/*
++      usa90msg.h
++
++      Copyright (c) 1998-2003 InnoSys Incorporated.  All Rights Reserved
++      This file is available under a BSD-style copyright
++
++      Keyspan USB Async Message Formats for the USA19HS
++
++      Redistribution and use in source and binary forms, with or without
++      modification, are permitted provided that the following conditions are
++      met:
++
++      1. Redistributions of source code must retain this licence text
++      without modification, this list of conditions, and the following
++      disclaimer.  The following copyright notice must appear immediately at
++      the beginning of all source files:
++
++              Copyright (c) 1998-2003 InnoSys Incorporated.  All Rights Reserved
++
++              This file is available under a BSD-style copyright
++
++      2. The name of InnoSys Incorprated may not be used to endorse or promote
++      products derived from this software without specific prior written
++      permission.
++
++      THIS SOFTWARE IS PROVIDED BY INNOSYS CORP. ``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 OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
++      INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++      (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++      SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
++      CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++      LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++      OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++      SUCH DAMAGE.    
++
++      Revisions:
++
++      2003feb14               add setTxMode/txMode  and cancelRxXoff to portControl
++      2003mar21               change name of PARITY_0/1 to add MARK/SPACE
++*/
++
++#ifndef       __USA90MSG__
++#define       __USA90MSG__
++
++struct keyspan_usa90_portControlMessage
++{
++      /*
++              there are three types of "commands" sent in the control message:
++
++              1.      configuration changes which must be requested by setting
++                      the corresponding "set" flag (and should only be requested
++                      when necessary, to reduce overhead on the device):
++      */
++
++      u8      setClocking,    // host requests baud rate be set
++              baudLo,                 // host does baud divisor calculation
++              baudHi,                 // host does baud divisor calculation 
++              
++              setLcr,                 // host requests lcr be set
++              lcr,                    // use PARITY, STOPBITS, DATABITS below
++              
++              setRxMode,              // set receive mode
++              rxMode,                 // RXMODE_DMA or RXMODE_BYHAND
++
++              setTxMode,              // set transmit mode
++              txMode,                 // TXMODE_DMA or TXMODE_BYHAND
++
++              setTxFlowControl,       // host requests tx flow control be set
++              txFlowControl   ,       // use TX_FLOW... bits below
++              setRxFlowControl,       // host requests rx flow control be set
++              rxFlowControl,  // use RX_FLOW... bits below
++              sendXoff,               // host requests XOFF transmitted immediately
++              sendXon,                // host requests XON char transmitted
++              xonChar,                // specified in current character format
++              xoffChar,               // specified in current character format
++
++              sendChar,               // host requests char transmitted immediately
++              txChar,                 // character to send
++
++              setRts,                 // host requests RTS output be set
++              rts,                    // 1=on, 0=off
++              setDtr,                 // host requests DTR output be set
++              dtr;                    // 1=on, 0=off
++
++      
++      /*
++              2.      configuration data which is simply used as is 
++                      and must be specified correctly in every host message.
++      */
++
++      u8      rxForwardingLength,  // forward when this number of chars available
++              rxForwardingTimeout, // (1-31 in ms)
++              txAckSetting;      // 0=don't ack, 1=normal, 2-255 TBD...
++      /*
++              3.      Firmware states which cause actions if they change                                      
++              and must be specified correctly in every host message.
++      */
++
++      u8      portEnabled,    // 0=disabled, 1=enabled
++              txFlush,                // 0=normal, 1=toss outbound data
++              txBreak,                // 0=break off, 1=break on
++              loopbackMode;   // 0=no loopback, 1=loopback enabled
++
++      /*
++              4.      commands which are flags only; these are processed in order
++                      (so that, e.g., if rxFlush and rxForward flags are set, the
++                      port will have no data to forward); any non-zero value 
++                      is respected
++      */
++
++      u8      rxFlush,                // toss inbound data
++              rxForward,              // forward all inbound data, NOW (as if fwdLen==1)
++              cancelRxXoff,   // cancel any receive XOFF state (_txXoff)
++              returnStatus;   // return current status NOW
++};
++
++// defines for bits in lcr
++#define               USA_DATABITS_5          0x00
++#define               USA_DATABITS_6          0x01
++#define               USA_DATABITS_7          0x02
++#define               USA_DATABITS_8          0x03
++#define               STOPBITS_5678_1         0x00    // 1 stop bit for all byte sizes
++#define               STOPBITS_5_1p5          0x04    // 1.5 stop bits for 5-bit byte
++#define               STOPBITS_678_2          0x04    // 2 stop bits for 6-8 bit byte
++#define               USA_PARITY_NONE         0x00
++#define               USA_PARITY_ODD          0x08
++#define               USA_PARITY_EVEN         0x18
++#define               PARITY_MARK_1           0x28    // force parity MARK
++#define               PARITY_SPACE_0          0x38    // force parity SPACE
++
++#define               TXFLOW_CTS                      0x04    
++#define               TXFLOW_DSR                      0x08
++#define               TXFLOW_XOFF                     0x01    
++#define               TXFLOW_XOFF_ANY         0x02    
++#define               TXFLOW_XOFF_BITS        (TXFLOW_XOFF | TXFLOW_XOFF_ANY)
++
++#define               RXFLOW_XOFF                     0x10    
++#define               RXFLOW_RTS                      0x20    
++#define               RXFLOW_DTR                      0x40
++#define               RXFLOW_DSR_SENSITIVITY  0x80
++
++#define               RXMODE_BYHAND           0x00    
++#define               RXMODE_DMA                      0x02    
++
++#define               TXMODE_BYHAND           0x00    
++#define               TXMODE_DMA                      0x02    
++
++
++// all things called "StatusMessage" are sent on the status endpoint
++
++struct keyspan_usa90_portStatusMessage        
++{
++      u8      msr,                    // reports the actual MSR register
++              cts,                    // reports CTS pin
++              dcd,                    // reports DCD pin
++              dsr,                    // reports DSR pin
++              ri,                             // reports RI pin
++              _txXoff,                // port is in XOFF state (we received XOFF)
++              rxBreak,                // reports break state
++              rxOverrun,              // count of overrun errors (since last reported)
++              rxParity,               // count of parity errors (since last reported)
++              rxFrame,                // count of frame errors (since last reported)
++              portState,              // PORTSTATE_xxx bits (useful for debugging)
++              messageAck,             // message acknowledgement
++              charAck,                // character acknowledgement
++              controlResponse;        // (value = returnStatus) a control message has been processed 
++};
++
++// bits in RX data message when STAT byte is included
++
++#define       RXERROR_OVERRUN         0x02
++#define       RXERROR_PARITY          0x04
++#define       RXERROR_FRAMING         0x08
++#define       RXERROR_BREAK           0x10
++
++#define       PORTSTATE_ENABLED       0x80
++#define       PORTSTATE_TXFLUSH       0x01
++#define       PORTSTATE_TXBREAK       0x02
++#define       PORTSTATE_LOOPBACK      0x04
++
++// MSR bits
++
++#define MSR_dCTS                      0x01            // CTS has changed since last report    
++#define MSR_dDSR                      0x02
++#define MSR_dRI                               0x04
++#define MSR_dDCD                      0x08
++
++#define MSR_CTS                               0x10            // current state of CTS
++#define MSR_DSR                               0x20
++#define MSR_RI                                0x40
++#define MSR_DCD                               0x80
++
++// ie: the maximum length of an endpoint buffer
++#define               MAX_DATA_LEN                    64
++
++#endif
+--- linux-2.6.0-test6/drivers/usb/storage/freecom.c    2003-07-13 21:44:34.000000000 -0700
++++ 25/drivers/usb/storage/freecom.c   2003-10-05 00:33:24.000000000 -0700
+@@ -101,7 +101,8 @@ struct freecom_status {
+ #define FCM_PACKET_IDE_READ   0xC0
+ /* All packets (except for status) are 64 bytes long. */
+-#define FCM_PACKET_LENGTH     64
++#define FCM_PACKET_LENGTH             64
++#define FCM_STATUS_PACKET_LENGTH      4
+ static int
+ freecom_readdata (Scsi_Cmnd *srb, struct us_data *us,
+@@ -216,7 +217,7 @@ int freecom_transport(Scsi_Cmnd *srb, st
+       /* There are times we can optimize out this status read, but it
+        * doesn't hurt us to always do it now. */
+       result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
+-                      FCM_PACKET_LENGTH, &partial);
++                      FCM_STATUS_PACKET_LENGTH, &partial);
+       US_DEBUGP("foo Status result %d %u\n", result, partial);
+       if (result != USB_STOR_XFER_GOOD)
+               return USB_STOR_TRANSPORT_ERROR;
+@@ -256,10 +257,10 @@ int freecom_transport(Scsi_Cmnd *srb, st
+               /* get the data */
+               result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
+-                              FCM_PACKET_LENGTH, &partial);
++                              FCM_STATUS_PACKET_LENGTH, &partial);
+               US_DEBUGP("bar Status result %d %u\n", result, partial);
+-              if (result > USB_STOR_XFER_SHORT)
++              if (result != USB_STOR_XFER_GOOD)
+                       return USB_STOR_TRANSPORT_ERROR;
+               US_DEBUG(pdump ((void *) fst, partial));
+@@ -302,6 +303,9 @@ int freecom_transport(Scsi_Cmnd *srb, st
+       switch (us->srb->sc_data_direction) {
+       case SCSI_DATA_READ:
++              /* catch bogus "read 0 length" case */
++              if (!length)
++                      break;
+               /* Make sure that the status indicates that the device
+                * wants data as well. */
+               if ((fst->Status & DRQ_STAT) == 0 || (fst->Reason & 3) != 2) {
+@@ -331,6 +335,9 @@ int freecom_transport(Scsi_Cmnd *srb, st
+               break;
+       case SCSI_DATA_WRITE:
++              /* catch bogus "write 0 length" case */
++              if (!length)
++                      break;
+               /* Make sure the status indicates that the device wants to
+                * send us data. */
+               /* !!IMPLEMENT!! */
+@@ -362,6 +369,7 @@ int freecom_transport(Scsi_Cmnd *srb, st
+               break;
+       default:
++              /* should never hit here -- filtered in usb.c */
+               US_DEBUGP ("freecom unimplemented direction: %d\n",
+                               us->srb->sc_data_direction);
+               // Return fail, SCSI seems to handle this better.
+--- linux-2.6.0-test6/drivers/usb/storage/unusual_devs.h       2003-09-27 18:57:46.000000000 -0700
++++ 25/drivers/usb/storage/unusual_devs.h      2003-10-05 00:33:24.000000000 -0700
+@@ -394,6 +394,12 @@ UNUSUAL_DEV( 0x0686, 0x4011, 0x0001, 0x0
+               "Dimage F300",
+               US_SC_SCSI, US_PR_BULK, NULL, 0 ),
++/* Reported by Miguel A. Fosas <amn3s1a@ono.com> */
++UNUSUAL_DEV(  0x0686, 0x4017, 0x0001, 0x0001,
++                "Minolta",
++                "DIMAGE E223",
++                US_SC_SCSI, US_PR_DEVICE, NULL, 0 ),
++
+ UNUSUAL_DEV(  0x0693, 0x0002, 0x0100, 0x0100, 
+               "Hagiwara",
+               "FlashGate SmartMedia",
+@@ -542,7 +548,7 @@ UNUSUAL_DEV(  0x07c4, 0xa400, 0x0000, 0x
+  * - They don't like the INQUIRY command. So we must handle this command
+  *   of the SCSI layer ourselves.
+  */
+-UNUSUAL_DEV( 0x07cf, 0x1001, 0x1000, 0x9009,
++UNUSUAL_DEV( 0x07cf, 0x1001, 0x1000, 0x5009,
+               "Casio",
+               "QV DigitalCamera",
+               US_SC_8070, US_PR_CB, NULL,
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/drivers/video/asiliantfb.c      2003-10-05 00:34:22.000000000 -0700
+@@ -0,0 +1,619 @@
++/*
++ * drivers/video/asiliantfb.c
++ *  frame buffer driver for Asiliant 69000 chip
++ *  Copyright (C) 2001-2003 Saito.K & Jeanne
++ *
++ *  from driver/video/chipsfb.c and,
++ *
++ *  drivers/video/asiliantfb.c -- frame buffer device for
++ *  Asiliant 69030 chip (formerly Intel, formerly Chips & Technologies)
++ *  Author: apc@agelectronics.co.uk
++ *  Copyright (C) 2000 AG Electronics
++ *  Note: the data sheets don't seem to be available from Asiliant.
++ *  They are available by searching developer.intel.com, but are not otherwise
++ *  linked to.
++ *
++ *  This driver should be portable with minimal effort to the 69000 display
++ *  chip, and to the twin-display mode of the 69030.
++ *  Contains code from Thomas Hhenleitner <th@visuelle-maschinen.de> (thanks)
++ *
++ *  Derived from the CT65550 driver chipsfb.c:
++ *  Copyright (C) 1998 Paul Mackerras
++ *  ...which was derived from the Powermac "chips" driver:
++ *  Copyright (C) 1997 Fabio Riccardi.
++ *  And from the frame buffer device for Open Firmware-initialized devices:
++ *  Copyright (C) 1997 Geert Uytterhoeven.
++ *
++ *  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/errno.h>
++#include <linux/string.h>
++#include <linux/mm.h>
++#include <linux/tty.h>
++#include <linux/slab.h>
++#include <linux/vmalloc.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/fb.h>
++#include <linux/init.h>
++#include <linux/pci.h>
++#include <asm/io.h>
++
++static struct fb_info asiliantfb_info;
++
++/* Built in clock of the 69030 */
++const unsigned Fref = 14318180;
++
++static u32 pseudo_palette[17];
++
++#define mmio_base (p->screen_base + 0x400000)
++
++#define mm_write_ind(num, val, ap, dp)        do { \
++      writeb((num), mmio_base + (ap)); writeb((val), mmio_base + (dp)); \
++} while (0)
++
++static void mm_write_xr(struct fb_info *p, u8 reg, u8 data)
++{
++      mm_write_ind(reg, data, 0x7ac, 0x7ad);
++}
++#define write_xr(num, val)    mm_write_xr(p, num, val)
++
++static void mm_write_fr(struct fb_info *p, u8 reg, u8 data)
++{
++      mm_write_ind(reg, data, 0x7a0, 0x7a1);
++}
++#define write_fr(num, val)    mm_write_fr(p, num, val)
++
++static void mm_write_cr(struct fb_info *p, u8 reg, u8 data)
++{
++      mm_write_ind(reg, data, 0x7a8, 0x7a9);
++}
++#define write_cr(num, val)    mm_write_cr(p, num, val)
++
++static void mm_write_gr(struct fb_info *p, u8 reg, u8 data)
++{
++      mm_write_ind(reg, data, 0x79c, 0x79d);
++}
++#define write_gr(num, val)    mm_write_gr(p, num, val)
++
++static void mm_write_sr(struct fb_info *p, u8 reg, u8 data)
++{
++      mm_write_ind(reg, data, 0x788, 0x789);
++}
++#define write_sr(num, val)    mm_write_sr(p, num, val)
++
++static void mm_write_ar(struct fb_info *p, u8 reg, u8 data)
++{
++      readb(mmio_base + 0x7b4);
++      mm_write_ind(reg, data, 0x780, 0x780);
++}
++#define write_ar(num, val)    mm_write_ar(p, num, val)
++
++/*
++ * Exported functions
++ */
++int asiliantfb_init(void);
++
++static int asiliantfb_pci_init(struct pci_dev *dp, const struct pci_device_id *);
++static int asiliantfb_check_var(struct fb_var_screeninfo *var,
++                              struct fb_info *info);
++static int asiliantfb_set_par(struct fb_info *info);
++static int asiliantfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
++                              u_int transp, struct fb_info *info);
++
++static struct fb_ops asiliantfb_ops = {
++      .owner          = THIS_MODULE,
++      .fb_check_var   = asiliantfb_check_var,
++      .fb_set_par     = asiliantfb_set_par,
++      .fb_setcolreg   = asiliantfb_setcolreg,
++      .fb_fillrect    = cfb_fillrect,
++      .fb_copyarea    = cfb_copyarea,
++      .fb_imageblit   = cfb_imageblit,
++      .fb_cursor      = soft_cursor,
++};
++
++/* Calculate the ratios for the dot clocks without using a single long long
++ * value */
++static void asiliant_calc_dclk2(u32 *ppixclock, u8 *dclk2_m, u8 *dclk2_n, u8 *dclk2_div)
++{
++      unsigned pixclock = *ppixclock;
++      unsigned Ftarget = 1000000 * (1000000 / pixclock);
++      unsigned n;
++      unsigned best_error = 0xffffffff;
++      unsigned best_m = 0xffffffff,
++               best_n = 0xffffffff;
++      unsigned ratio;
++      unsigned remainder;
++      unsigned char divisor = 0;
++
++      /* Calculate the frequency required. This is hard enough. */
++      ratio = 1000000 / pixclock;
++      remainder = 1000000 % pixclock;
++      Ftarget = 1000000 * ratio + (1000000 * remainder) / pixclock;
++
++      while (Ftarget < 100000000) {
++              divisor += 0x10;
++              Ftarget <<= 1;
++      }
++
++      ratio = Ftarget / Fref;
++      remainder = Ftarget % Fref;
++
++      /* This expresses the constraint that 150kHz <= Fref/n <= 5Mhz,
++       * together with 3 <= n <= 257. */
++      for (n = 3; n <= 257; n++) {
++              unsigned m = n * ratio + (n * remainder) / Fref;
++
++              /* 3 <= m <= 257 */
++              if (m >= 3 && m <= 257) {
++                      unsigned new_error = ((Ftarget * n) - (Fref * m)) >= 0 ?
++                                             ((Ftarget * n) - (Fref * m)) : ((Fref * m) - (Ftarget * n));
++                      if (new_error < best_error) {
++                              best_n = n;
++                              best_m = m;
++                              best_error = new_error;
++                      }
++              }
++              /* But if VLD = 4, then 4m <= 1028 */
++              else if (m <= 1028) {
++                      /* remember there are still only 8-bits of precision in m, so
++                       * avoid over-optimistic error calculations */
++                      unsigned new_error = ((Ftarget * n) - (Fref * (m & ~3))) >= 0 ?
++                                             ((Ftarget * n) - (Fref * (m & ~3))) : ((Fref * (m & ~3)) - (Ftarget * n));
++                      if (new_error < best_error) {
++                              best_n = n;
++                              best_m = m;
++                              best_error = new_error;
++                      }
++              }
++      }
++      if (best_m > 257)
++              best_m >>= 2;   /* divide m by 4, and leave VCO loop divide at 4 */
++      else
++              divisor |= 4;   /* or set VCO loop divide to 1 */
++      *dclk2_m = best_m - 2;
++      *dclk2_n = best_n - 2;
++      *dclk2_div = divisor;
++      *ppixclock = pixclock;
++      return;
++}
++
++static void asiliant_set_timing(struct fb_info *p)
++{
++      unsigned hd = p->var.xres / 8;
++      unsigned hs = (p->var.xres + p->var.right_margin) / 8;
++              unsigned he = (p->var.xres + p->var.right_margin + p->var.hsync_len) / 8;
++      unsigned ht = (p->var.left_margin + p->var.xres + p->var.right_margin + p->var.hsync_len) / 8;
++      unsigned vd = p->var.yres;
++      unsigned vs = p->var.yres + p->var.lower_margin;
++      unsigned ve = p->var.yres + p->var.lower_margin + p->var.vsync_len;
++      unsigned vt = p->var.upper_margin + p->var.yres + p->var.lower_margin + p->var.vsync_len;
++      unsigned wd = (p->var.xres_virtual * ((p->var.bits_per_pixel+7)/8)) / 8;
++
++      if ((p->var.xres == 640) && (p->var.yres == 480) && (p->var.pixclock == 39722)) {
++        write_fr(0x01, 0x02);  /* LCD */
++      } else {
++        write_fr(0x01, 0x01);  /* CRT */
++      }
++
++      write_cr(0x11, (ve - 1) & 0x0f);
++      write_cr(0x00, (ht - 5) & 0xff);
++      write_cr(0x01, hd - 1);
++      write_cr(0x02, hd);
++      write_cr(0x03, ((ht - 1) & 0x1f) | 0x80);
++      write_cr(0x04, hs);
++      write_cr(0x05, (((ht - 1) & 0x20) <<2) | (he & 0x1f));
++      write_cr(0x3c, (ht - 1) & 0xc0);
++      write_cr(0x06, (vt - 2) & 0xff);
++      write_cr(0x30, (vt - 2) >> 8);
++      write_cr(0x07, 0x00);
++      write_cr(0x08, 0x00);
++      write_cr(0x09, 0x00);
++      write_cr(0x10, (vs - 1) & 0xff);
++      write_cr(0x32, ((vs - 1) >> 8) & 0xf);
++      write_cr(0x11, ((ve - 1) & 0x0f) | 0x80);
++      write_cr(0x12, (vd - 1) & 0xff);
++      write_cr(0x31, ((vd - 1) & 0xf00) >> 8);
++      write_cr(0x13, wd & 0xff);
++      write_cr(0x41, (wd & 0xf00) >> 8);
++      write_cr(0x15, (vs - 1) & 0xff);
++      write_cr(0x33, ((vs - 1) >> 8) & 0xf);
++      write_cr(0x38, ((ht - 5) & 0x100) >> 8);
++      write_cr(0x16, (vt - 1) & 0xff);
++      write_cr(0x18, 0x00);
++
++      if (p->var.xres == 640) {
++        writeb(0xc7, mmio_base + 0x784);      /* set misc output reg */
++      } else {
++        writeb(0x07, mmio_base + 0x784);      /* set misc output reg */
++      }
++}
++
++static int asiliantfb_check_var(struct fb_var_screeninfo *var,
++                           struct fb_info *p)
++{
++      unsigned long Ftarget, ratio, remainder;
++
++      ratio = 1000000 / var->pixclock;
++      remainder = 1000000 % var->pixclock;
++      Ftarget = 1000000 * ratio + (1000000 * remainder) / var->pixclock;
++
++      /* First check the constraint that the maximum post-VCO divisor is 32,
++       * and the maximum Fvco is 220MHz */
++      if (Ftarget > 220000000 || Ftarget < 3125000) {
++              printk(KERN_ERR "asiliantfb dotclock must be between 3.125 and 220MHz\n");
++              return -ENXIO;
++      }
++      var->xres_virtual = var->xres;
++      var->yres_virtual = var->yres;
++
++      if (var->bits_per_pixel == 24) {
++              var->red.offset = 16;
++              var->green.offset = 8;
++              var->blue.offset = 0;
++              var->red.length = var->blue.length = var->green.length = 8;
++      } else if (var->bits_per_pixel == 16) {
++              switch (var->red.offset) {
++                      case 11:
++                              var->green.length = 6;
++                              break;
++                      case 10:
++                              var->green.length = 5;
++                              break;
++                      default:
++                              return -EINVAL;
++              }
++              var->green.offset = 5;
++              var->blue.offset = 0;
++              var->red.length = var->blue.length = 5;
++      } else if (var->bits_per_pixel == 8) {
++              var->red.offset = var->green.offset = var->blue.offset = 0;
++              var->red.length = var->green.length = var->blue.length = 8;
++      }
++      return 0;
++}
++
++static int asiliantfb_set_par(struct fb_info *p)
++{
++      u8 dclk2_m;             /* Holds m-2 value for register */
++      u8 dclk2_n;             /* Holds n-2 value for register */
++      u8 dclk2_div;           /* Holds divisor bitmask */
++
++      /* Set pixclock */
++      asiliant_calc_dclk2(&p->var.pixclock, &dclk2_m, &dclk2_n, &dclk2_div);
++
++      /* Set color depth */
++      if (p->var.bits_per_pixel == 24) {
++              write_xr(0x81, 0x16);   /* 24 bit packed color mode */
++              write_xr(0x82, 0x00);   /* Disable palettes */
++              write_xr(0x20, 0x20);   /* 24 bit blitter mode */
++      } else if (p->var.bits_per_pixel == 16) {
++              if (p->var.red.offset == 11)
++                      write_xr(0x81, 0x15);   /* 16 bit color mode */
++              else
++                      write_xr(0x81, 0x14);   /* 15 bit color mode */
++              write_xr(0x82, 0x00);   /* Disable palettes */
++              write_xr(0x20, 0x10);   /* 16 bit blitter mode */
++      } else if (p->var.bits_per_pixel == 8) {
++              write_xr(0x0a, 0x02);   /* Linear */
++              write_xr(0x81, 0x12);   /* 8 bit color mode */
++              write_xr(0x82, 0x00);   /* Graphics gamma enable */
++              write_xr(0x20, 0x00);   /* 8 bit blitter mode */
++      }
++      p->fix.line_length = p->var.xres * (p->var.bits_per_pixel >> 3);
++      p->fix.visual = (p->var.bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
++      write_xr(0xc4, dclk2_m);
++      write_xr(0xc5, dclk2_n);
++      write_xr(0xc7, dclk2_div);
++      /* Set up the CR registers */
++      asiliant_set_timing(p);
++      return 0;
++}
++
++static int asiliantfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
++                           u_int transp, struct fb_info *p)
++{
++      if (regno > 255)
++              return 1;
++      red >>= 8;
++      green >>= 8;
++      blue >>= 8;
++
++        /* Set hardware palete */
++      writeb(regno, mmio_base + 0x790);
++      udelay(1);
++      writeb(red, mmio_base + 0x791);
++      writeb(green, mmio_base + 0x791);
++      writeb(blue, mmio_base + 0x791);
++
++      switch(p->var.bits_per_pixel) {
++      case 15:
++              if (regno < 16) {
++                      ((u32 *)(p->pseudo_palette))[regno] =
++                              ((red & 0xf8) << 7) |
++                              ((green & 0xf8) << 2) |
++                              ((blue & 0xf8) >> 3);
++              }
++              break;
++      case 16:
++              if (regno < 16) {
++                      ((u32 *)(p->pseudo_palette))[regno] =
++                              ((red & 0xf8) << 8) |
++                              ((green & 0xfc) << 3) |
++                              ((blue & 0xf8) >> 3);
++              }
++              break;
++      case 24:
++              if (regno < 24) {
++                      ((u32 *)(p->pseudo_palette))[regno] =
++                              (red << 16)  |
++                              (green << 8) |
++                              (blue);
++              }
++              break;
++      }
++      return 0;
++}
++
++struct chips_init_reg {
++      unsigned char addr;
++      unsigned char data;
++};
++
++#define N_ELTS(x)     (sizeof(x) / sizeof(x[0]))
++
++static struct chips_init_reg chips_init_sr[] =
++{
++      {0x00, 0x03},           /* Reset register */
++      {0x01, 0x01},           /* Clocking mode */
++      {0x02, 0x0f},           /* Plane mask */
++      {0x04, 0x0e}            /* Memory mode */
++};
++
++static struct chips_init_reg chips_init_gr[] =
++{
++        {0x03, 0x00},         /* Data rotate */
++      {0x05, 0x00},           /* Graphics mode */
++      {0x06, 0x01},           /* Miscellaneous */
++      {0x08, 0x00}            /* Bit mask */
++};
++
++static struct chips_init_reg chips_init_ar[] =
++{
++      {0x10, 0x01},           /* Mode control */
++      {0x11, 0x00},           /* Overscan */
++      {0x12, 0x0f},           /* Memory plane enable */
++      {0x13, 0x00}            /* Horizontal pixel panning */
++};
++
++static struct chips_init_reg chips_init_cr[] =
++{
++      {0x0c, 0x00},           /* Start address high */
++      {0x0d, 0x00},           /* Start address low */
++      {0x40, 0x00},           /* Extended Start Address */
++      {0x41, 0x00},           /* Extended Start Address */
++      {0x14, 0x00},           /* Underline location */
++      {0x17, 0xe3},           /* CRT mode control */
++      {0x70, 0x00}            /* Interlace control */
++};
++
++
++static struct chips_init_reg chips_init_fr[] =
++{
++      {0x01, 0x02},
++      {0x03, 0x08},
++      {0x08, 0xcc},
++      {0x0a, 0x08},
++      {0x18, 0x00},
++      {0x1e, 0x80},
++      {0x40, 0x83},
++      {0x41, 0x00},
++      {0x48, 0x13},
++      {0x4d, 0x60},
++      {0x4e, 0x0f},
++
++      {0x0b, 0x01},
++
++      {0x21, 0x51},
++      {0x22, 0x1d},
++      {0x23, 0x5f},
++      {0x20, 0x4f},
++      {0x34, 0x00},
++      {0x24, 0x51},
++      {0x25, 0x00},
++      {0x27, 0x0b},
++      {0x26, 0x00},
++      {0x37, 0x80},
++      {0x33, 0x0b},
++      {0x35, 0x11},
++      {0x36, 0x02},
++      {0x31, 0xea},
++      {0x32, 0x0c},
++      {0x30, 0xdf},
++      {0x10, 0x0c},
++      {0x11, 0xe0},
++      {0x12, 0x50},
++      {0x13, 0x00},
++      {0x16, 0x03},
++      {0x17, 0xbd},
++      {0x1a, 0x00},
++};
++
++
++static struct chips_init_reg chips_init_xr[] =
++{
++      {0xce, 0x00},           /* set default memory clock */
++      {0xcc, 200 },           /* MCLK ratio M */
++      {0xcd, 18  },           /* MCLK ratio N */
++      {0xce, 0x90},           /* MCLK divisor = 2 */
++
++      {0xc4, 209 },
++      {0xc5, 118 },
++      {0xc7, 32  },
++      {0xcf, 0x06},
++      {0x09, 0x01},           /* IO Control - CRT controller extensions */
++      {0x0a, 0x02},           /* Frame buffer mapping */
++      {0x0b, 0x01},           /* PCI burst write */
++      {0x40, 0x03},           /* Memory access control */
++      {0x80, 0x82},           /* Pixel pipeline configuration 0 */
++      {0x81, 0x12},           /* Pixel pipeline configuration 1 */
++      {0x82, 0x08},           /* Pixel pipeline configuration 2 */
++
++      {0xd0, 0x0f},
++      {0xd1, 0x01},
++};
++
++static void __init chips_hw_init(struct fb_info *p)
++{
++      int i;
++
++      for (i = 0; i < N_ELTS(chips_init_xr); ++i)
++              write_xr(chips_init_xr[i].addr, chips_init_xr[i].data);
++      write_xr(0x81, 0x12);
++      write_xr(0x82, 0x08);
++      write_xr(0x20, 0x00);
++      for (i = 0; i < N_ELTS(chips_init_sr); ++i)
++              write_sr(chips_init_sr[i].addr, chips_init_sr[i].data);
++      for (i = 0; i < N_ELTS(chips_init_gr); ++i)
++              write_gr(chips_init_gr[i].addr, chips_init_gr[i].data);
++      for (i = 0; i < N_ELTS(chips_init_ar); ++i)
++              write_ar(chips_init_ar[i].addr, chips_init_ar[i].data);
++      /* Enable video output in attribute index register */
++      writeb(0x20, mmio_base + 0x780);
++      for (i = 0; i < N_ELTS(chips_init_cr); ++i)
++              write_cr(chips_init_cr[i].addr, chips_init_cr[i].data);
++      for (i = 0; i < N_ELTS(chips_init_fr); ++i)
++              write_fr(chips_init_fr[i].addr, chips_init_fr[i].data);
++}
++
++static struct fb_fix_screeninfo asiliantfb_fix __initdata = {
++      .id =           "Asiliant 69000",
++      .type =         FB_TYPE_PACKED_PIXELS,
++      .visual =       FB_VISUAL_PSEUDOCOLOR,
++      .accel =        FB_ACCEL_NONE,
++      .line_length =  640,
++      .smem_len =     0x200000,       /* 2MB */
++};
++
++static struct fb_var_screeninfo asiliantfb_var __initdata = {
++      .xres           = 640,
++      .yres           = 480,
++      .xres_virtual   = 640,
++      .yres_virtual   = 480,
++      .bits_per_pixel = 8,
++      .red            = { .length = 8 },
++      .green          = { .length = 8 },
++      .blue           = { .length = 8 },
++      .height         = -1,
++      .width          = -1,
++      .vmode          = FB_VMODE_NONINTERLACED,
++      .pixclock       = 39722,
++      .left_margin    = 48,
++      .right_margin   = 16,
++      .upper_margin   = 33,
++      .lower_margin   = 10,
++      .hsync_len      = 96,
++      .vsync_len      = 2,
++};
++
++static void __init init_asiliant(struct fb_info *p, unsigned long addr)
++{
++      p->fix                  = asiliantfb_fix;
++      p->fix.smem_start       = addr;
++      p->var                  = asiliantfb_var;
++      p->fbops                = &asiliantfb_ops;
++      p->pseudo_palette       = pseudo_palette;
++      p->flags                = FBINFO_FLAG_DEFAULT;
++
++      fb_alloc_cmap(&p->cmap, 256, 0);
++
++      if (register_framebuffer(p) < 0) {
++              printk(KERN_ERR "C&T 69000 framebuffer failed to register\n");
++              return;
++      }
++
++      printk(KERN_INFO "fb%d: Asiliant 69000 frame buffer (%dK RAM detected)\n",
++              p->node, p->fix.smem_len / 1024);
++
++      writeb(0xff, mmio_base + 0x78c);
++      chips_hw_init(p);
++}
++
++static int __devinit
++asiliantfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent)
++{
++      struct fb_info *p = &asiliantfb_info;
++      unsigned long addr, size;
++
++      if ((dp->resource[0].flags & IORESOURCE_MEM) == 0)
++              return -ENODEV;
++      addr = pci_resource_start(dp, 0);
++      size = pci_resource_len(dp, 0);
++      if (addr == 0)
++              return -ENODEV;
++      if (p->screen_base != 0)
++              return -EBUSY;
++      if (!request_mem_region(addr, size, "asiliantfb"))
++              return -EBUSY;
++
++      p->screen_base = ioremap(addr, 0x800000);
++      if (p->screen_base == NULL) {
++              release_mem_region(addr, size);
++              return -ENOMEM;
++      }
++
++      pci_write_config_dword(dp, 4, 0x02800083);
++      writeb(3, addr + 0x400784);
++
++      init_asiliant(p, addr);
++
++      /* Clear the entire framebuffer */
++      memset(p->screen_base, 0, 0x200000);
++
++      pci_set_drvdata(dp, p);
++      return 0;
++}
++
++static void __devexit asiliantfb_remove(struct pci_dev *dp)
++{
++      struct fb_info *p = pci_get_drvdata(dp);
++
++      if (p != &asiliantfb_info || p->screen_base == NULL)
++              return;
++      unregister_framebuffer(p);
++      iounmap(p->screen_base);
++      p->screen_base = NULL;
++      release_mem_region(pci_resource_start(dp, 0), pci_resource_len(dp, 0));
++}
++
++static struct pci_device_id asiliantfb_pci_tbl[] __devinitdata = {
++      { PCI_VENDOR_ID_CT, PCI_DEVICE_ID_CT_69000, PCI_ANY_ID, PCI_ANY_ID },
++      { 0 }
++};
++
++MODULE_DEVICE_TABLE(pci, asiliantfb_pci_tbl);
++
++static struct pci_driver asiliantfb_driver = {
++      .name =         "asiliantfb",
++      .id_table =     asiliantfb_pci_tbl,
++      .probe =        asiliantfb_pci_init,
++      .remove =       __devexit_p(asiliantfb_remove),
++};
++
++int __init asiliantfb_init(void)
++{
++      return pci_module_init(&asiliantfb_driver);
++}
++
++static void __exit asiliantfb_exit(void)
++{
++      pci_unregister_driver(&asiliantfb_driver);
++}
++
++MODULE_LICENSE("GPL");
+--- linux-2.6.0-test6/drivers/video/aty/aty128fb.c     2003-08-08 22:55:13.000000000 -0700
++++ 25/drivers/video/aty/aty128fb.c    2003-10-05 00:34:46.000000000 -0700
+@@ -2041,9 +2041,9 @@ aty128fb_setcolreg(u_int regno, u_int re
+ #define ATY_MIRROR_CRT_ON     0x00000002
+ /* out param: u32*    backlight value: 0 to 15 */
+-#define FBIO_ATY128_GET_MIRROR        _IOR('@', 1, sizeof(__u32*))
++#define FBIO_ATY128_GET_MIRROR        _IOR('@', 1, __u32*)
+ /* in param: u32*     backlight value: 0 to 15 */
+-#define FBIO_ATY128_SET_MIRROR        _IOW('@', 2, sizeof(__u32*))
++#define FBIO_ATY128_SET_MIRROR        _IOW('@', 2, __u32*)
+ static int aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+                         u_long arg, struct fb_info *info)
+--- linux-2.6.0-test6/drivers/video/aty/Makefile       2003-06-14 12:18:06.000000000 -0700
++++ 25/drivers/video/aty/Makefile      2003-10-05 00:34:22.000000000 -0700
+@@ -4,4 +4,3 @@ obj-$(CONFIG_FB_ATY128) += aty128fb.o
+ atyfb-y                               := atyfb_base.o mach64_accel.o
+ atyfb-$(CONFIG_FB_ATY_GX)     += mach64_gx.o
+ atyfb-$(CONFIG_FB_ATY_CT)     += mach64_ct.o mach64_cursor.o
+-atyfb-objs                    := $(atyfb-y)
+--- linux-2.6.0-test6/drivers/video/chipsfb.c  2003-08-08 22:55:13.000000000 -0700
++++ 25/drivers/video/chipsfb.c 2003-10-05 00:34:22.000000000 -0700
+@@ -85,7 +85,7 @@ static struct pmu_sleep_notifier chips_s
+ /*
+  * Exported functions
+  */
+-int chips_init(void);
++int chipsfb_init(void);
+ static int chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *);
+ static int chipsfb_check_var(struct fb_var_screeninfo *var,
+@@ -460,7 +460,7 @@ static struct pci_driver chipsfb_driver 
+       .remove =       __devexit_p(chipsfb_remove),
+ };
+-int __init chips_init(void)
++int __init chipsfb_init(void)
+ {
+       return pci_module_init(&chipsfb_driver);
+ }
+--- linux-2.6.0-test6/drivers/video/console/fbcon.c    2003-06-14 12:18:25.000000000 -0700
++++ 25/drivers/video/console/fbcon.c   2003-10-05 00:34:22.000000000 -0700
+@@ -195,8 +195,7 @@ static void fb_flashcursor(void *private
+ {
+       struct fb_info *info = (struct fb_info *) private;
+-      /* Test to see if the cursor is erased but still on */
+-      if (!info || (info->cursor.rop == ROP_COPY))
++      if (!info)
+               return;
+       info->cursor.enable ^= 1;
+       info->fbops->fb_cursor(info, &info->cursor);
+@@ -226,8 +225,7 @@ static void cursor_timer_handler(unsigne
+       struct fb_info *info = (struct fb_info *) dev_addr;
+       
+       schedule_work(&info->queue);    
+-      cursor_timer.expires = jiffies + HZ / 5;
+-      add_timer(&cursor_timer);
++      mod_timer(&cursor_timer, jiffies + HZ/5);
+ }
+ int __init fb_console_setup(char *this_opt)
+@@ -308,97 +306,6 @@ int set_con2fb_map(int unit, int newidx)
+ }
+ /*
+- * drawing helpers
+- */
+-static void putcs_unaligned(struct vc_data *vc, struct fb_info *info,
+-                          struct fb_image *image, int count,
+-                          const unsigned short *s)
+-{
+-      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 shift_low = 0, mod = vc->vc_font.width % 8;
+-      unsigned int shift_high = 8, size, pitch, cnt, k;
+-      unsigned int buf_align = info->pixmap.buf_align - 1;
+-      unsigned int scan_align = info->pixmap.scan_align - 1;
+-      unsigned int idx = vc->vc_font.width >> 3;
+-      u8 mask, *src, *dst, *dst0;
+-
+-      while (count) {
+-              if (count > maxcnt)
+-                      cnt = k = maxcnt;
+-              else
+-                      cnt = k = count;
+-
+-              image->width = vc->vc_font.width * cnt;
+-              pitch = ((image->width + 7) >> 3) + scan_align;
+-              pitch &= ~scan_align;
+-              size = pitch * vc->vc_font.height + buf_align;
+-              size &= ~buf_align;
+-              dst0 = info->pixmap.addr + fb_get_buffer_offset(info, size);
+-              image->data = dst0;
+-              while (k--) {
+-                      src = vc->vc_font.data + (scr_readw(s++) & charmask)*
+-                      cellsize;
+-                      dst = dst0;
+-                      mask = (u8) (0xfff << shift_high);
+-                      move_buf_unaligned(info, dst, src, pitch, image->height,
+-                                      mask, shift_high, shift_low, mod, idx);
+-                      shift_low += mod;
+-                      dst0 += (shift_low >= 8) ? width : width - 1;
+-                      shift_low &= 7;
+-                      shift_high = 8 - shift_low;
+-              }
+-              info->fbops->fb_imageblit(info, image);
+-              image->dx += cnt * vc->vc_font.width;
+-              count -= cnt;
+-              atomic_dec(&info->pixmap.count);
+-              smp_mb__after_atomic_dec();
+-      }
+-}
+-
+-static void putcs_aligned(struct vc_data *vc, struct fb_info *info,
+-                        struct fb_image *image, int count,
+-                        const unsigned short *s)
+-{
+-      unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+-      unsigned int width = vc->vc_font.width >> 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 pitch, cnt, size, k;
+-      u8 *src, *dst, *dst0;
+-
+-      while (count) {
+-              if (count > maxcnt)
+-                      cnt = k = maxcnt;
+-              else
+-                      cnt = k = count;
+-              
+-              pitch = width * cnt + scan_align;
+-              pitch &= ~scan_align;
+-              size = pitch * vc->vc_font.height + buf_align;
+-              size &= ~buf_align;
+-              image->width = vc->vc_font.width * cnt;
+-              dst0 = info->pixmap.addr + fb_get_buffer_offset(info, size);
+-              image->data = dst0;
+-              while (k--) {
+-                      src = vc->vc_font.data + (scr_readw(s++)&charmask)*cellsize;
+-                      dst = dst0;
+-                      move_buf_aligned(info, dst, src, pitch, width, image->height);
+-                      dst0 += width;
+-              }
+-              info->fbops->fb_imageblit(info, image);
+-              image->dx += cnt * vc->vc_font.width;
+-              count -= cnt;
+-              atomic_dec(&info->pixmap.count);
+-              smp_mb__after_atomic_dec();
+-      }
+-}
+-
+-/*
+  * Accelerated handlers.
+  */
+ void accel_bmove(struct vc_data *vc, struct fb_info *info, int sy, 
+@@ -432,48 +339,21 @@ void accel_clear(struct vc_data *vc, str
+       info->fbops->fb_fillrect(info, &region);
+ }     
+-static void accel_putc(struct vc_data *vc, struct fb_info *info,
+-                      int c, int ypos, int xpos)
++void accel_putcs(struct vc_data *vc, struct fb_info *info,
++                      const unsigned short *s, int count, int yy, int xx)
+ {
+       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, k;
+       int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
+       int fgshift = (vc->vc_hi_font_mask) ? 9 : 8;
+-      unsigned int size, pitch;
+-      struct fb_image image;
+-      u8 *src, *dst;
+-
+-      image.dx = xpos * vc->vc_font.width;
+-      image.dy = ypos * vc->vc_font.height;
+-      image.width = vc->vc_font.width;
+-      image.height = vc->vc_font.height;
+-      image.fg_color = attr_fgcol(fgshift, c);
+-      image.bg_color = attr_bgcol(bgshift, c);
+-      image.depth = 1;
+-
+-      pitch = width + scan_align;
+-      pitch &= ~scan_align;
+-      size = pitch * vc->vc_font.height;
+-      size += buf_align;
+-      size &= ~buf_align;
+-      dst = info->pixmap.addr + fb_get_buffer_offset(info, size);
+-      image.data = dst;
+-      src = vc->vc_font.data + (c & charmask) * vc->vc_font.height * width;
+-
+-      move_buf_aligned(info, dst, src, pitch, width, image.height);
+-
+-      info->fbops->fb_imageblit(info, &image);
+-      atomic_dec(&info->pixmap.count);
+-      smp_mb__after_atomic_dec();
+-}
+-
+-void accel_putcs(struct vc_data *vc, struct fb_info *info,
+-                      const unsigned short *s, int count, int yy, int xx)
+-{
+-      int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
+-      int fgshift = (vc->vc_hi_font_mask) ? 9 : 8;
++      unsigned int idx = vc->vc_font.width >> 3;
++      u8 *src, *dst, *dst0, mask;
+       struct fb_image image;
+       u16 c = scr_readw(s);
+@@ -484,10 +364,44 @@ void accel_putcs(struct vc_data *vc, str
+       image.height = vc->vc_font.height;
+       image.depth = 1;
+-      if (!(vc->vc_font.width & 7))
+-               putcs_aligned(vc, info, &image, count, s);
+-        else
+-               putcs_unaligned(vc, info, &image, count, s);
++      while (count) {
++              if (count > maxcnt)
++                      cnt = k = maxcnt;
++              else
++                      cnt = k = count;
++
++              image.width = vc->vc_font.width * cnt;
++              pitch = ((image.width + 7) >> 3) + scan_align;
++              pitch &= ~scan_align;
++              size = pitch * vc->vc_font.height + buf_align;
++              size &= ~buf_align;
++              dst0 = fb_get_buffer_offset(info, &info->pixmap, size);
++              image.data = dst0;
++              while (k--) {
++                      src = vc->vc_font.data + (scr_readw(s++) & charmask)*cellsize;
++                      dst = dst0;
++
++                      if (mod) {
++                              mask = (u8) (0xfff << shift_high);
++                              move_buf_unaligned(info, &info->pixmap, dst, src, pitch,
++                                                 image.height, mask, shift_high,
++                                                 shift_low, mod, idx);
++                              shift_low += mod;
++                              dst0 += (shift_low >= 8) ? width : width - 1;
++                              shift_low &= 7;
++                              shift_high = 8 - shift_low;
++                      } else {
++                              move_buf_aligned(info, &info->pixmap, dst, src, pitch, idx,
++                                               image.height);
++                              dst0 += width;
++                      }
++              }
++              info->fbops->fb_imageblit(info, &image);
++              image.dx += cnt * vc->vc_font.width;
++              count -= cnt;
++              atomic_dec(&info->pixmap.count);
++              smp_mb__after_atomic_dec();
++      }
+ }
+ void accel_clear_margins(struct vc_data *vc, struct fb_info *info,
+@@ -676,7 +590,7 @@ static const char *fbcon_startup(void)
+       if (!info->queue.func) {
+               INIT_WORK(&info->queue, fb_flashcursor, info);
+               
+-              cursor_timer.expires = jiffies + HZ / 50;
++              cursor_timer.expires = jiffies + HZ / 5;
+               cursor_timer.data = (unsigned long ) info;
+               add_timer(&cursor_timer);
+       }
+@@ -728,15 +642,13 @@ static __inline__ void updatescrollmode(
+ static void fbcon_set_display(struct vc_data *vc, int init, int logo)
+ {
+       struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]];
++      int nr_rows, nr_cols, old_rows, old_cols, i, charcnt = 256;
+       struct display *p = &fb_display[vc->vc_num];
+-      int nr_rows, nr_cols;
+-      int old_rows, old_cols;
+       unsigned short *save = NULL, *r, *q;
+-      int i, charcnt = 256;
+       struct font_desc *font;
+       if (vc->vc_num != fg_console || (info->flags & FBINFO_FLAG_MODULE) ||
+-          info->fix.type == FB_TYPE_TEXT)
++          (info->fix.type == FB_TYPE_TEXT))
+               logo = 0;
+       info->var.xoffset = info->var.yoffset = p->yscroll = 0; /* reset wrap/pan */
+@@ -960,11 +872,19 @@ static void fbcon_clear(struct vc_data *
+               accel_clear(vc, info, real_y(p, sy), sx, height, width);
+ }
+-
+ static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos)
+ {
+       struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]];
++      unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
++      unsigned int scan_align = info->pixmap.scan_align - 1;
++      unsigned int buf_align = info->pixmap.buf_align - 1;
++      unsigned int width = (vc->vc_font.width + 7) >> 3;
++      int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
++      int fgshift = (vc->vc_hi_font_mask) ? 9 : 8;
+       struct display *p = &fb_display[vc->vc_num];
++      unsigned int size, pitch;
++      struct fb_image image;
++      u8 *src, *dst;
+       if (!info->fbops->fb_blank && console_blanked)
+               return;
+@@ -972,7 +892,31 @@ static void fbcon_putc(struct vc_data *v
+       if (vt_cons[vc->vc_num]->vc_mode != KD_TEXT)
+               return;
+-      accel_putc(vc, info, c, real_y(p, ypos), xpos);
++      image.dx = xpos * vc->vc_font.width;
++      image.dy = real_y(p, ypos) * vc->vc_font.height;
++      image.width = vc->vc_font.width;
++      image.height = vc->vc_font.height;
++      image.fg_color = attr_fgcol(fgshift, c);
++      image.bg_color = attr_bgcol(bgshift, c);
++      image.depth = 1;
++
++      src = vc->vc_font.data + (c & charmask) * vc->vc_font.height * width;
++
++      pitch = width + scan_align;
++      pitch &= ~scan_align;
++      size = pitch * vc->vc_font.height;
++      size += buf_align;
++      size &= ~buf_align;
++
++      dst = fb_get_buffer_offset(info, &info->pixmap, size);
++      image.data = dst;
++
++      move_buf_aligned(info, &info->pixmap, dst, src, pitch, width,
++                      image.height);
++
++      info->fbops->fb_imageblit(info, &image);
++      atomic_dec(&info->pixmap.count);
++      smp_mb__after_atomic_dec();
+ }
+ static void fbcon_putcs(struct vc_data *vc, const unsigned short *s,
+@@ -994,12 +938,16 @@ static void fbcon_cursor(struct vc_data 
+ {
+       struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]];
+       unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
++      unsigned int scan_align = info->sprite.scan_align - 1;
++      unsigned int buf_align = info->sprite.buf_align - 1;
+       int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
+       int fgshift = (vc->vc_hi_font_mask) ? 9 : 8;
+       struct display *p = &fb_display[vc->vc_num];
+-      int w = (vc->vc_font.width + 7) >> 3, c;
+-      int y = real_y(p, vc->vc_y);
++      int y = real_y(p, vc->vc_y), d_pitch, dsize;
++      int s_pitch = (vc->vc_font.width + 7) >> 3;
++      int size = s_pitch * vc->vc_font.height, c;
+       struct fb_cursor cursor;
++      u8 *src, *dst;
+       
+       if (mode & CM_SOFTBACK) {
+               mode &= ~CM_SOFTBACK;
+@@ -1012,28 +960,24 @@ static void fbcon_cursor(struct vc_data 
+       } else if (softback_lines)
+               fbcon_set_origin(vc);
+-      c = scr_readw((u16 *) vc->vc_pos);
++      del_timer(&cursor_timer);
++      if (info->cursor.enable) {
++              info->cursor.enable = 0;
++              info->fbops->fb_cursor(info, &info->cursor);
++      }
+-      cursor.image.data = vc->vc_font.data + ((c & charmask) * (w * vc->vc_font.height));
+-      cursor.set = FB_CUR_SETCUR;
+-      cursor.image.depth = 1;
+-      
+-      switch (mode) {
+-      case CM_ERASE:
+-              if (info->cursor.rop == ROP_XOR) {
+-                      info->cursor.enable = 0;
+-                      info->cursor.rop = ROP_COPY;
+-                      info->fbops->fb_cursor(info, &cursor);
+-              }       
+-              break;
+-      case CM_MOVE:
+-      case CM_DRAW:
++      if (mode != CM_ERASE) {
++              memset(&cursor, 0, sizeof(struct fb_cursor));
+               info->cursor.enable = 1;
+-              
++
++              c = scr_readw((u16 *) vc->vc_pos);
++
++              src = vc->vc_font.data + ((c & charmask) * size);
+               if (info->cursor.image.fg_color != attr_fgcol(fgshift, c) ||
+                   info->cursor.image.bg_color != attr_bgcol(bgshift, c)) {
+                       cursor.image.fg_color = attr_fgcol(fgshift, c);
+                       cursor.image.bg_color = attr_bgcol(bgshift, c);
++                      cursor.image.depth = 1;
+                       cursor.set |= FB_CUR_SETCMAP;
+               }
+               
+@@ -1056,18 +1000,29 @@ static void fbcon_cursor(struct vc_data 
+                       cursor.set |= FB_CUR_SETHOT;
+               }
++              src = vc->vc_font.data + ((c & charmask) * size);
++
++              d_pitch = (s_pitch + scan_align) & ~scan_align;
++              dsize = d_pitch * vc->vc_font.height + buf_align;
++              dsize &= ~buf_align;
++              dst = fb_get_buffer_offset(info, &info->sprite, dsize);
++              move_buf_aligned(info, &info->sprite, dst, src, d_pitch, s_pitch, vc->vc_font.height);
++              info->cursor.image.data = dst;
++              cursor.set |= FB_CUR_SETSHAPE;
++
+               if ((cursor.set & FB_CUR_SETSIZE) || ((vc->vc_cursor_type & 0x0f) != p->cursor_shape)) {
+-                      char *mask = kmalloc(w*vc->vc_font.height, GFP_ATOMIC);
+-                      int cur_height, size, i = 0;
++                      char *mask = kmalloc(dsize, GFP_ATOMIC);
++                      int cur_height, i, j, k;
+                       if (!mask)      return; 
+-              
++
++                      memset(mask, 0, dsize);
++
+                       if (info->cursor.mask)
+                               kfree(info->cursor.mask);
+                       info->cursor.mask = mask;
+       
+                       p->cursor_shape = vc->vc_cursor_type & 0x0f;
+-                      cursor.set |= FB_CUR_SETSHAPE;
+                       switch (vc->vc_cursor_type & 0x0f) {
+                       case CUR_NONE:
+@@ -1090,17 +1045,19 @@ static void fbcon_cursor(struct vc_data 
+                               cur_height = vc->vc_font.height;
+                               break;
+                       }
+-                      size = (vc->vc_font.height - cur_height) * w;
+-                      while (size--)
+-                              mask[i++] = 0;
+-                      size = cur_height * w;
+-                      while (size--)
+-                              mask[i++] = 0xff;
++                      i = (vc->vc_font.height - cur_height) * d_pitch;
++                      for (j = 0; j < cur_height; j++) {
++                              for (k = 0; k < s_pitch; k++)
++                                      mask[i++] = 0xff;
++                              i += (d_pitch - s_pitch);
++                      }
+               }
+               info->cursor.rop = ROP_XOR;
+               info->fbops->fb_cursor(info, &cursor);
++              atomic_dec(&info->sprite.count);
++              smp_mb__after_atomic_dec();
++              mod_timer(&cursor_timer, jiffies + HZ/5);
+               vbl_cursor_cnt = CURSOR_DRAW_DELAY;
+-              break;
+       }
+ }
+@@ -1826,8 +1783,10 @@ static int fbcon_do_set_font(struct vc_d
+       vc->vc_font.height = h;
+       if (vc->vc_hi_font_mask && cnt == 256) {
+               vc->vc_hi_font_mask = 0;
+-              if (vc->vc_can_do_color)
++              if (vc->vc_can_do_color) {
+                       vc->vc_complement_mask >>= 1;
++                      vc->vc_s_complement_mask >>= 1;
++              }
+               /* ++Edmund: reorder the attribute bits */
+               if (vc->vc_can_do_color) {
+@@ -1847,8 +1806,10 @@ static int fbcon_do_set_font(struct vc_d
+               }
+       } else if (!vc->vc_hi_font_mask && cnt == 512) {
+               vc->vc_hi_font_mask = 0x100;
+-              if (vc->vc_can_do_color)
++              if (vc->vc_can_do_color) {
+                       vc->vc_complement_mask <<= 1;
++                      vc->vc_s_complement_mask <<= 1;
++              }
+               /* ++Edmund: reorder the attribute bits */
+               {
+--- linux-2.6.0-test6/drivers/video/console/Makefile   2003-06-14 12:18:09.000000000 -0700
++++ 25/drivers/video/console/Makefile  2003-10-05 00:34:22.000000000 -0700
+@@ -3,18 +3,16 @@
+ # Rewritten to use lists instead of if-statements.
+ # Font handling
+-font-objs := fonts.o
++font-y := fonts.o
+-font-objs-$(CONFIG_FONT_SUN8x16)   += font_sun8x16.o
+-font-objs-$(CONFIG_FONT_SUN12x22)  += font_sun12x22.o
+-font-objs-$(CONFIG_FONT_8x8)       += font_8x8.o
+-font-objs-$(CONFIG_FONT_8x16)      += font_8x16.o
+-font-objs-$(CONFIG_FONT_6x11)      += font_6x11.o
+-font-objs-$(CONFIG_FONT_PEARL_8x8) += font_pearl_8x8.o
+-font-objs-$(CONFIG_FONT_ACORN_8x8) += font_acorn_8x8.o
+-font-objs-$(CONFIG_FONT_MINI_4x6)  += font_mini_4x6.o
+-
+-font-objs += $(font-objs-y)
++font-$(CONFIG_FONT_SUN8x16)   += font_sun8x16.o
++font-$(CONFIG_FONT_SUN12x22)  += font_sun12x22.o
++font-$(CONFIG_FONT_8x8)       += font_8x8.o
++font-$(CONFIG_FONT_8x16)      += font_8x16.o
++font-$(CONFIG_FONT_6x11)      += font_6x11.o
++font-$(CONFIG_FONT_PEARL_8x8) += font_pearl_8x8.o
++font-$(CONFIG_FONT_ACORN_8x8) += font_acorn_8x8.o
++font-$(CONFIG_FONT_MINI_4x6)  += font_mini_4x6.o
+ # Each configuration option enables a list of files.
+@@ -31,8 +29,11 @@ obj-$(CONFIG_FB_STI)              += sti
+ # Files generated that shall be removed upon make clean
+ clean-files := promcon_tbl.c
+-$(obj)/promcon_tbl.c: $(src)/prom.uni
+-      $(objtree)/scripts/conmakehash $< | \
++quiet_cmd_promtbl = GEN       $@
++      cmd_promtbl = scripts/conmakehash $< | \
+       sed -e '/#include <[^>]*>/p' -e 's/types/init/' \
+           -e 's/dfont\(_uni.*\]\)/promfont\1 __initdata/' > $@
++$(obj)/promcon_tbl.c: $(src)/prom.uni
++      $(call cmd,promtbl)
++
+--- linux-2.6.0-test6/drivers/video/console/sticore.c  2003-08-08 22:55:13.000000000 -0700
++++ 25/drivers/video/console/sticore.c 2003-10-05 00:33:24.000000000 -0700
+@@ -988,7 +988,7 @@ static int __devinit sticore_pci_init(st
+       
+       if (!sti) {
+               printk(KERN_WARNING "Unable to handle STI device '%s'\n",
+-                      pd->dev.name);
++                      pci_name(pd));
+               return -ENODEV;
+       }
+ #endif /* CONFIG_PCI */
+--- linux-2.6.0-test6/drivers/video/controlfb.c        2003-09-08 13:58:58.000000000 -0700
++++ 25/drivers/video/controlfb.c       2003-10-05 00:34:22.000000000 -0700
+@@ -136,8 +136,8 @@ static int controlfb_check_var (struct f
+ /*
+  * inititialization
+  */
+-int control_init(void);
+-void control_setup(char *);
++int controlfb_init(void);
++void controlfb_setup(char *);
+ /******************** Prototypes for internal functions **********************/
+@@ -553,7 +553,7 @@ static void control_set_hardware(struct 
+ /*
+  * Called from fbmem.c for probing & initializing
+  */
+-int __init control_init(void)
++int __init controlfb_init(void)
+ {
+       struct device_node *dp;
+@@ -1057,7 +1057,7 @@ static void control_cleanup(void)
+ /*
+  * Parse user speficied options (`video=controlfb:')
+  */
+-void __init control_setup(char *options)
++void __init controlfb_setup(char *options)
+ {
+       char *this_opt;
+--- linux-2.6.0-test6/drivers/video/epson1355fb.c      2003-06-14 12:17:57.000000000 -0700
++++ 25/drivers/video/epson1355fb.c     2003-10-05 00:34:22.000000000 -0700
+@@ -1,541 +1,714 @@
+ /*
+- * linux/drivers/video/epson1355fb.c
+- *    -- Support for the Epson SED1355 LCD/CRT controller
++ * linux/drivers/video/epson1355fb.c -- Epson S1D13505 frame buffer for 2.5.
+  *
+- * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
++ * Epson Research S1D13505 Embedded RAMDAC LCD/CRT Controller
++ *   (previously known as SED1355)
+  *
+- * based on linux/drivers/video/skeletonfb.c, which was
++ * Cf. http://www.erd.epson.com/vdc/html/S1D13505.html
++ *
++ *
++ * Copyright (C) Hewlett-Packard Company.  All rights reserved.
++ *
++ * Written by Christopher Hoover <ch@hpl.hp.com>
++ *
++ * Adapted from:
++ *
++ *  linux/drivers/video/skeletonfb.c
++ *  Modified to new api Jan 2001 by James Simmons (jsimmons@transvirtual.com)
+  *  Created 28 Dec 1997 by Geert Uytterhoeven
+  *
++ *  linux/drivers/video/epson1355fb.c (2.4 driver)
++ *  Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
++ *
+  * 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.
+- */
+-/* TODO (roughly in order of priority):
+- * 16 bpp support
+- * crt support
+- * hw cursor support
+- * SwivelView
++ * License. See the file COPYING in the main directory of this archive for
++ * more details.
++ *
++ *
++ * Noteworthy Issues
++ * -----------------
++ *
++ * This driver is complicated by the fact that this is a 16-bit chip
++ * and, on at least one platform (ceiva), we can only do 16-bit reads
++ * and writes to the framebuffer.  We hide this from user space
++ * except in the case of mmap().
++ *
++ *
++ * To Do
++ * -----
++ *
++ * - Test 8-bit pseudocolor mode
++ * - Allow setting bpp, virtual resolution
++ * - Implement horizontal panning
++ * - (maybe) Implement hardware cursor
+  */
+-#include <asm/io.h>
+-#include <linux/config.h>
+-#include <linux/delay.h>
+-#include <linux/errno.h>
+-#include <linux/fb.h>
+-#include <linux/init.h>
+-#include <linux/kernel.h>
+-#include <linux/slab.h>
+-#include <linux/mm.h>
+ #include <linux/module.h>
+-#include <linux/sched.h>
++#include <linux/kernel.h>
++#include <linux/errno.h>
+ #include <linux/string.h>
++#include <linux/mm.h>
+ #include <linux/tty.h>
+-#include <video/fbcon-cfb8.h>
+-#include <video/fbcon-mfb.h>
+-#include <video/fbcon.h>
+-
+-/* Register defines.  The docs don't seem to provide nice mnemonic names
+- * so I made them up myself ... */
+-
+-#define E1355_PANEL   0x02
+-#define E1355_DISPLAY 0x0D
+-#define E1355_MISC    0x1B
+-#define E1355_GPIO    0x20
+-#define E1355_LUT_INDEX 0x24
+-#define E1355_LUT_DATA        0x26
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <linux/fb.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <asm/types.h>
++#include <asm/io.h>
++#include <asm/uaccess.h>
++
++#include <video/epson1355.h>
++
++static struct fb_info info;
++
++static struct epson1355fb_par {
++      unsigned long reg_addr;
++} par;
++
++static u32 pseudo_palette[16];
++
++/* ------------------------------------------------------------------------- */
+ #ifdef CONFIG_SUPERH
+-#define E1355_REG_BASE        CONFIG_E1355_REG_BASE
+-#define E1355_FB_BASE CONFIG_E1355_FB_BASE
+-static inline u8 e1355_read_reg(int index)
++static inline u8 epson1355_read_reg(int index)
+ {
+-      return ctrl_inb(E1355_REG_BASE + index);
++      return ctrl_inb(par.reg_addr + index);
+ }
+-static inline void e1355_write_reg(u8 data, int index)
++static inline void epson1355_write_reg(u8 data, int index)
+ {
+-      ctrl_outb(data, E1355_REG_BASE + index);
++      ctrl_outb(data, par.reg_addr + index);
+ }
+-static inline u16 e1355_read_reg16(int index)
++#elif defined(CONFIG_ARM)
++
++# ifdef CONFIG_ARCH_CEIVA
++#  include <asm/arch/hardware.h>
++#  define EPSON1355FB_BASE_PHYS       (CEIVA_PHYS_SED1355)
++# endif
++
++static inline u8 epson1355_read_reg(int index)
+ {
+-      return e1355_read_reg(index) + (e1355_read_reg(index+1) << 8);
++      return __raw_readb(par.reg_addr + index);
+ }
+-static inline void e1355_write_reg16(u16 data, int index)
++static inline void epson1355_write_reg(u8 data, int index)
+ {
+-      e1355_write_reg((data&0xff), index);
+-      e1355_write_reg(((data>>8)&0xff), index + 1);
++      __raw_writeb(data, par.reg_addr + index);
+ }
++
+ #else
+-#error unknown architecture
++# error "no architecture-specific epson1355_{read,write}_reg"
+ #endif
+-struct e1355fb_info {
+-      struct fb_info_gen gen;
+-};
+-
+-static int current_par_valid = 0;
+-static struct display disp;
++#ifndef EPSON1355FB_BASE_PHYS
++# error  "EPSON1355FB_BASE_PHYS is not defined"
++#endif
+-static struct fb_var_screeninfo default_var;
++#define EPSON1355FB_REGS_OFS  (0)
++#define EPSON1355FB_REGS_PHYS (EPSON1355FB_BASE_PHYS + EPSON1355FB_REGS_OFS)
++#define EPSON1355FB_REGS_LEN  (64)
+-int e1355fb_init(void);
+-int e1355fb_setup(char*);
+-static int e1355_encode_var(struct fb_var_screeninfo *var, const void *par,
+-                          struct fb_info_gen *info);
+-/* ------------------- chipset specific functions -------------------------- */
++#define EPSON1355FB_FB_OFS    (0x00200000)
++#define EPSON1355FB_FB_PHYS   (EPSON1355FB_BASE_PHYS + EPSON1355FB_FB_OFS)
++#define EPSON1355FB_FB_LEN    (2 * 1024 * 1024)
++/* ------------------------------------------------------------------------- */
+-static void disable_hw_cursor(void)
++static inline u16 epson1355_read_reg16(int index)
+ {
+-      u8 curs;
++      u8 lo = epson1355_read_reg(index);
++      u8 hi = epson1355_read_reg(index + 1);
+-      curs = e1355_read_reg(0x27);
+-      curs &= ~0xc0;
+-      e1355_write_reg(curs, 0x27);
++      return (hi << 8) | lo;
+ }
+-static void e1355_detect(void)
++static inline void epson1355_write_reg16(u16 data, int index)
+ {
+-      u8 rev;
++      u8 lo = data & 0xff;
++      u8 hi = (data >> 8) & 0xff;
+-      e1355_write_reg(0x00, E1355_MISC);
++      epson1355_write_reg(lo, index);
++      epson1355_write_reg(hi, index + 1);
++}
+-      rev = e1355_read_reg(0x00);
++static inline u32 epson1355_read_reg20(int index)
++{
++      u8 b0 = epson1355_read_reg(index);
++      u8 b1 = epson1355_read_reg(index + 1);
++      u8 b2 = epson1355_read_reg(index + 2);
+-      if ((rev & 0xfc) != 0x0c) {
+-              printk(KERN_WARNING "Epson 1355 not detected\n");
+-      }
++      return (b2 & 0x0f) << 16 | (b1 << 8) | b0;
++}
+-      /* XXX */
+-      disable_hw_cursor();
++static inline void epson1355_write_reg20(u32 data, int index)
++{
++      u8 b0 = data & 0xff;
++      u8 b1 = (data >> 8) & 0xff;
++      u8 b2 = (data >> 16) & 0x0f;
+-      e1355_encode_var(&default_var, NULL, NULL);
++      epson1355_write_reg(b0, index);
++      epson1355_write_reg(b1, index + 1);
++      epson1355_write_reg(b2, index + 2);
+ }
+-struct e1355_par {
+-      u32 xres;
+-      u32 yres;
++/* ------------------------------------------------------------------------- */
+-      int bpp;
+-      int mem_bpp;
++static void set_lut(u8 index, u8 r, u8 g, u8 b)
++{
++      epson1355_write_reg(index, REG_LUT_ADDR);
++      epson1355_write_reg(r, REG_LUT_DATA);
++      epson1355_write_reg(g, REG_LUT_DATA);
++      epson1355_write_reg(b, REG_LUT_DATA);
++}
+-      u32 panel_xres;
+-      u32 panel_yres;
+-      
+-      int panel_width;
+-      int panel_ymul;
+-};
+-static int e1355_encode_fix(struct fb_fix_screeninfo *fix,
+-                          const void *raw_par,
+-                          struct fb_info_gen *info)
+-{
+-      const struct e1355_par *par = raw_par;
+-      
+-      memset(fix, 0, sizeof *fix);
+-      
+-      fix->type= FB_TYPE_PACKED_PIXELS;
++/**
++ *    epson1355fb_setcolreg - sets a color register.
++ *      @regno: Which register in the CLUT we are programming
++ *      @red: The red value which can be up to 16 bits wide
++ *    @green: The green value which can be up to 16 bits wide
++ *    @blue:  The blue value which can be up to 16 bits wide.
++ *    @transp: If supported the alpha value which can be up to 16 bits wide.
++ *      @info: frame buffer info structure
++ *
++ *    Returns negative errno on error, or zero on success.
++ */
++static int epson1355fb_setcolreg(unsigned regno, unsigned r, unsigned g,
++                               unsigned b, unsigned transp,
++                               struct fb_info *info)
++{
++      if (info->var.grayscale)
++              r = g = b = (19595 * r + 38470 * g + 7471 * b) >> 16;
++
++      switch (info->fix.visual) {
++      case FB_VISUAL_TRUECOLOR:
++              if (regno >= 16)
++                      return -EINVAL;
+-      if (!par)
+-              BUG();
++              ((u32 *) info->pseudo_palette)[regno] =
++                  (r & 0xf800) | (g & 0xfc00) >> 5 | (b & 0xf800) >> 11;
+-      if (par->bpp == 1) {
+-              fix->visual = FB_VISUAL_MONO10;
+-      } else if (par->bpp <= 8) {
+-              fix->visual = FB_VISUAL_PSEUDOCOLOR;
+-      } else {
+-              fix->visual = FB_VISUAL_TRUECOLOR;
+-      }
++              break;
++      case FB_VISUAL_PSEUDOCOLOR:
++              if (regno >= 256)
++                      return -EINVAL;
+-      return 0;
+-}
++              set_lut(regno, r >> 8, g >> 8, b >> 8);
+-static int e1355_set_bpp(struct e1355_par *par, int bpp)
+-{
+-      int code;
+-      u8 disp;
+-      u16 bytes_per_line;
+-
+-      switch(bpp) {
+-      case 1:
+-              code = 0; break;
+-      case 2:
+-              code = 1; break;
+-      case 4:
+-              code = 2; break;
+-      case 8:
+-              code = 3; break;
+-      case 16:
+-              code = 5; break;
++              break;
+       default:
+-              return -EINVAL; break;
++              return -ENOSYS;
+       }
+-
+-      disp = e1355_read_reg(E1355_DISPLAY);
+-      disp &= ~0x1c;
+-      disp |= code << 2;
+-      e1355_write_reg(disp, E1355_DISPLAY);
+-      
+-      bytes_per_line = (par->xres * bpp) >> 3;
+-      
+-      e1355_write_reg16(bytes_per_line, 0x16);
+-
+-      par->bpp = bpp;
+-
+       return 0;
+ }
+-              
+-static int e1355_decode_var(const struct fb_var_screeninfo *var,
+-                          void *raw_par,
+-                          struct fb_info_gen *info)
++
++/* ------------------------------------------------------------------------- */
++
++/**
++ *      epson1355fb_pan_display - Pans the display.
++ *      @var: frame buffer variable screen structure
++ *      @info: frame buffer structure that represents a single frame buffer
++ *
++ *    Pan (or wrap, depending on the `vmode' field) the display using the
++ *    `xoffset' and `yoffset' fields of the `var' structure.
++ *    If the values don't fit, return -EINVAL.
++ *
++ *      Returns negative errno on error, or zero on success.
++ */
++static int epson1355fb_pan_display(struct fb_var_screeninfo *var,
++                                 struct fb_info *info)
+ {
+-      struct e1355_par *par = raw_par;
+-      int ret;
++      u32 start;
+-      if (!par)
+-              BUG();
++      if (var->xoffset != 0)  /* not yet ... */
++              return -EINVAL;
+-      /*
+-       * Don't allow setting any of these yet: xres and yres don't
+-       * make sense for LCD panels; xres_virtual and yres_virtual
+-       * should be supported fine by our hardware though.
+-       */
+-      if (var->xres != par->xres ||
+-          var->yres != par->yres ||
+-          var->xres != var->xres_virtual ||
+-          var->yres != var->yres_virtual ||
+-          var->xoffset != 0 ||
+-          var->yoffset != 0)
++      if (var->yoffset + info->var.yres > info->var.yres_virtual)
+               return -EINVAL;
+-      if(var->bits_per_pixel != par->bpp) {
+-              ret = e1355_set_bpp(par, var->bits_per_pixel);
++      start = (info->fix.line_length >> 1) * var->yoffset;
+-              if (ret)
+-                      goto out_err;
+-      }
+-              
+-      return 0;
++      epson1355_write_reg20(start, REG_SCRN1_DISP_START_ADDR0);
+- out_err:
+-      return ret;
++      return 0;
+ }
+-static void dump_panel_data(void)
++/* ------------------------------------------------------------------------- */
++
++static void lcd_enable(int enable)
+ {
+-      u8 panel = e1355_read_reg(E1355_PANEL);
+-      int width[2][4] = { { 4, 8, 16, -1 }, { 9, 12, 16, -1 } };
++      u8 mode = epson1355_read_reg(REG_DISPLAY_MODE);
+-      printk("%s %s %s panel, width %d bits\n",
+-             panel & 2 ? "dual" : "single",
+-             panel & 4 ? "color" : "mono",
+-             panel & 1 ? "TFT" : "passive",
+-             width[panel&1][(panel>>4)&3]);
++      if (enable)
++              mode |= 1;
++      else
++              mode &= ~1;
+-      printk("resolution %d x %d\n",
+-             (e1355_read_reg(0x04) + 1) * 8,
+-             ((e1355_read_reg16(0x08) + 1) * (1 + ((panel & 3) == 2))));
++      epson1355_write_reg(mode, REG_DISPLAY_MODE);
+ }
+-static int e1355_bpp_to_var(int bpp, struct fb_var_screeninfo *var)
++#if defined(CONFIG_ARCH_CEIVA)
++static void backlight_enable(int enable)
+ {
+-      switch(bpp) {
+-      case 1:
+-      case 2:
+-      case 4:
+-      case 8:
+-              var->bits_per_pixel = bpp;
+-              var->red.offset = var->green.offset = var->blue.offset = 0;
+-              var->red.length = var->green.length = var->blue.length = bpp;
++      /* ### this should be protected by a spinlock ... */
++      u8 pddr = clps_readb(PDDR);
++      if (enable)
++              pddr |= (1 << 5);
++      else
++              pddr &= ~(1 << 5);
++      clps_writeb(pddr, PDDR);
++}
++#else
++static void backlight_enable(int enable)
++{
++}
++#endif
++
++
++/**
++ *      epson1355fb_blank - blanks the display.
++ *      @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 epson1355fb_blank(int blank_mode, struct fb_info *info)
++{
++      switch (blank_mode) {
++      case VESA_NO_BLANKING:
++              lcd_enable(1);
++              backlight_enable(1);
+               break;
+-      case 16:
+-              var->bits_per_pixel = 16;
+-              var->red.offset = 11;
+-              var->red.length = 5;
+-              var->green.offset = 5;
+-              var->green.length = 6;
+-              var->blue.offset = 0;
+-              var->blue.length = 5;
++      case VESA_VSYNC_SUSPEND:
++      case VESA_HSYNC_SUSPEND:
++              backlight_enable(0);
+               break;
++      case VESA_POWERDOWN:
++              backlight_enable(0);
++              lcd_enable(0);
++              break;
++      default:
++              return -EINVAL;
+       }
+-
+       return 0;
+ }
+-static int e1355_encode_var(struct fb_var_screeninfo *var, const void *raw_par,
+-                          struct fb_info_gen *info)
++/* ------------------------------------------------------------------------- */
++
++/*
++ * We can't use the cfb generic routines, as we have to limit
++ * ourselves to 16-bit or 8-bit loads and stores to this 16-bit
++ * chip.
++ */
++
++static inline void epson1355fb_fb_writel(unsigned long v, unsigned long *a)
+ {
+-      u8 panel, display;
+-      u32 xres, xres_virtual, yres;
+-      static int width[2][4] = { { 4, 8, 16, -1 }, { 9, 12, 16, -1 } };
+-      static int bpp_tab[8] = { 1, 2, 4, 8, 15, 16 };
+-      int bpp, hw_bpp;
+-      int is_color, is_dual, is_tft;
+-      int lcd_enabled, crt_enabled;
++      u16 *p = (u16 *) a;
++      u16 l = v & 0xffff;
++      u16 h = v >> 16;
+-      panel = e1355_read_reg(E1355_PANEL);
+-      display = e1355_read_reg(E1355_DISPLAY);
++      fb_writew(l, p);
++      fb_writew(h, p + 1);
++}
+-      is_color = (panel & 0x04) != 0;
+-      is_dual  = (panel & 0x02) != 0;
+-      is_tft   = (panel & 0x01) != 0;
++static inline unsigned long epson1355fb_fb_readl(const unsigned long *a)
++{
++      const u16 *p = (u16 *) a;
++      u16 l = fb_readw(p);
++      u16 h = fb_readw(p + 1);
+-      bpp = bpp_tab[(display>>2)&7]; 
+-      e1355_bpp_to_var(bpp, var);
++      return (h << 16) | l;
++}
+-      crt_enabled = (display & 0x02) != 0;
+-      lcd_enabled = (display & 0x02) != 0;
++#define FB_READL epson1355fb_fb_readl
++#define FB_WRITEL epson1355fb_fb_writel
+-      hw_bpp = width[is_tft][(panel>>4)&3];
++/* ------------------------------------------------------------------------- */
+-      xres = e1355_read_reg(0x04) + 1;
+-      yres = e1355_read_reg16(0x08) + 1;
+-      
+-      xres *= 8;
+-      /* talk about weird hardware .. */
+-      yres *= (is_dual && !crt_enabled) ? 2 : 1;
+-
+-      xres_virtual = e1355_read_reg16(0x16);
+-      /* it's in 2-byte words initially */
+-      xres_virtual *= 16;
+-      xres_virtual /= var->bits_per_pixel;
++static inline unsigned long copy_from_user16(void *to, const void *from,
++                                           unsigned long n)
++{
++      u16 *dst = (u16 *) to;
++      u16 *src = (u16 *) from;
+-      var->xres = xres;
+-      var->yres = yres;
+-      var->xres_virtual = xres_virtual;
+-      var->yres_virtual = yres;
++      if (!access_ok(VERIFY_READ, from, n))
++              return n;
+-      var->xoffset = var->yoffset = 0;
++      while (n > 1) {
++              u16 v;
++              if (__get_user(v, src))
++                      return n;
+-      var->grayscale = !is_color;
+-      
+-      return 0;
+-}
++              fb_writew(v, dst);
+-#define is_dual(panel) (((panel)&3)==2)
++              src++, dst++;
++              n -= 2;
++      }
+-static void get_panel_data(struct e1355_par *par)
+-{
+-      u8 panel;
+-      int width[2][4] = { { 4, 8, 16, -1 }, { 9, 12, 16, -1 } };
++      if (n) {
++              u8 v;
+-      panel = e1355_read_reg(E1355_PANEL);
++              if (__get_user(v, ((u8 *) src)))
++                      return n;
+-      par->panel_width = width[panel&1][(panel>>4)&3];
+-      par->panel_xres = (e1355_read_reg(0x04) + 1) * 8;
+-      par->panel_ymul = is_dual(panel) ? 2 : 1;
+-      par->panel_yres = ((e1355_read_reg16(0x08) + 1)
+-                         * par->panel_ymul);
++              fb_writeb(v, dst);
++      }
++      return 0;
+ }
+-static void e1355_get_par(void *raw_par, struct fb_info_gen *info)
++static inline unsigned long copy_to_user16(void *to, const void *from,
++                                         unsigned long n)
+ {
+-      struct e1355_par *par = raw_par;
++      u16 *dst = (u16 *) to;
++      u16 *src = (u16 *) from;
+-      get_panel_data(par);
+-}
++      if (!access_ok(VERIFY_WRITE, to, n))
++              return n;
+-static void e1355_set_par(const void *par, struct fb_info_gen *info)
+-{
+-}
++      while (n > 1) {
++              u16 v = fb_readw(src);
+-static int e1355_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+-                         unsigned *blue, unsigned *transp,
+-                         struct fb_info *info)
+-{
+-      u8 r, g, b;
++              if (__put_user(v, dst))
++                      return n;
+-      e1355_write_reg(regno, E1355_LUT_INDEX);
+-      r = e1355_read_reg(E1355_LUT_DATA);
+-      g = e1355_read_reg(E1355_LUT_DATA);
+-      b = e1355_read_reg(E1355_LUT_DATA);
++              src++, dst++;
++              n -= 2;
++      }
+-      *red = r << 8;
+-      *green = g << 8;
+-      *blue = b << 8;
++      if (n) {
++              u8 v = fb_readb(src);
++              if (__put_user(v, ((u8 *) dst)))
++                      return n;
++      }
+       return 0;
+ }
+-static int e1355fb_setcolreg(unsigned regno, unsigned red, unsigned green,
+-                           unsigned blue, unsigned transp,
+-                           struct fb_info *info)
+-{
+-      u8 r = (red >> 8) & 0xf0;
+-      u8 g = (green>>8) & 0xf0;
+-      u8 b = (blue>> 8) & 0xf0;
+-
+-      e1355_write_reg(regno, E1355_LUT_INDEX);
+-      e1355_write_reg(r, E1355_LUT_DATA);
+-      e1355_write_reg(g, E1355_LUT_DATA);
+-      e1355_write_reg(b, E1355_LUT_DATA);
+-      
+-      return 0;
+-}
+-static int e1355_pan_display(const struct fb_var_screeninfo *var,
+-                           struct fb_info_gen *info)
++static ssize_t
++epson1355fb_read(struct file *file, char *buf, size_t count, loff_t * ppos)
+ {
+-      BUG();
+-      
+-      return -EINVAL;
++      unsigned long p = *ppos;
++
++      /* from fbmem.c except for our own copy_*_user */
++      if (p >= info.fix.smem_len)
++              return 0;
++      if (count >= info.fix.smem_len)
++              count = info.fix.smem_len;
++      if (count + p > info.fix.smem_len)
++              count = info.fix.smem_len - p;
++
++      if (count) {
++              char *base_addr;
++
++              base_addr = info.screen_base;
++              count -= copy_to_user16(buf, base_addr + p, count);
++              if (!count)
++                      return -EFAULT;
++              *ppos += count;
++      }
++      return count;
+ }
+-/*
+- * The AERO_HACKS parts disable/enable the backlight on the Compaq Aero 8000.
+- * I'm not sure they aren't dangerous to the hardware, so be warned.
+- */
+-#undef AERO_HACKS
++static ssize_t
++epson1355fb_write(struct file *file, const char *buf,
++                size_t count, loff_t * ppos)
++{
++      unsigned long p = *ppos;
++      int err;
++
++      /* from fbmem.c except for our own copy_*_user */
++      if (p > info.fix.smem_len)
++              return -ENOSPC;
++      if (count >= info.fix.smem_len)
++              count = info.fix.smem_len;
++      err = 0;
++      if (count + p > info.fix.smem_len) {
++              count = info.fix.smem_len - p;
++              err = -ENOSPC;
++      }
+-static int e1355_blank(int blank_mode, struct fb_info_gen *info)
+-{
+-      u8 disp;
++      if (count) {
++              char *base_addr;
+-      switch (blank_mode) {
+-      case VESA_NO_BLANKING:
+-              disp = e1355_read_reg(E1355_DISPLAY);
+-              disp |= 1;
+-              e1355_write_reg(disp, E1355_DISPLAY);
+-              
+-#ifdef AERO_HACKS
+-              e1355_write_reg(0x6, 0x20);
+-#endif
+-              break;
++              base_addr = info.screen_base;
++              count -= copy_from_user16(base_addr + p, buf, count);
++              *ppos += count;
++              err = -EFAULT;
++      }
++      if (count)
++              return count;
++      return err;
++}
++
++/* ------------------------------------------------------------------------- */
++
++static struct fb_ops epson1355fb_fbops = {
++      .owner          = THIS_MODULE,
++      .fb_setcolreg   = epson1355fb_setcolreg,
++      .fb_pan_display = epson1355fb_pan_display,
++      .fb_blank       = epson1355fb_blank,
++      .fb_fillrect    = cfb_fillrect,
++      .fb_copyarea    = cfb_copyarea,
++      .fb_imageblit   = cfb_imageblit,
++      .fb_read        = epson1355fb_read,
++      .fb_write       = epson1355fb_write,
++      .fb_cursor      = soft_cursor,
++};
+-      case VESA_VSYNC_SUSPEND:
+-      case VESA_HSYNC_SUSPEND:
+-      case VESA_POWERDOWN:
+-              disp = e1355_read_reg(E1355_DISPLAY);
+-              disp &= ~1;
+-              e1355_write_reg(disp, E1355_DISPLAY);
++/* ------------------------------------------------------------------------- */
+-#ifdef AERO_HACKS
+-              e1355_write_reg(0x0, 0x20);
+-#endif
+-              break;
++static __init unsigned int get_fb_size(struct fb_info *info)
++{
++      unsigned int size = 2 * 1024 * 1024;
++      char *p = info->screen_base;
+-      default:
+-              return -EINVAL;
+-      }
++      /* the 512k framebuffer is aliased at start + 0x80000 * n */
++      fb_writeb(1, p);
++      fb_writeb(0, p + 0x80000);
++      if (!fb_readb(p))
++              size = 512 * 1024;
+-      return 0;
++      fb_writeb(0, p);
++
++      return size;
+ }
+-static struct display_switch e1355_dispsw;
++static int epson1355_width_tab[2][4] __initdata =
++    { {4, 8, 16, -1}, {9, 12, 16, -1} };
++static int epson1355_bpp_tab[8] __initdata = { 1, 2, 4, 8, 15, 16 };
+-static void e1355_set_disp(const void *unused, struct display *disp,
+-                         struct fb_info_gen *info)
++static void __init fetch_hw_state(struct fb_info *info)
+ {
+-      struct display_switch *d;
++      struct fb_var_screeninfo *var = &info->var;
++      struct fb_fix_screeninfo *fix = &info->fix;
++      u8 panel, display;
++      u16 offset;
++      u32 xres, yres;
++      u32 xres_virtual, yres_virtual;
++      int bpp, lcd_bpp;
++      int is_color, is_dual, is_tft;
++      int lcd_enabled, crt_enabled;
++
++      fix->type = FB_TYPE_PACKED_PIXELS;
+-      disp->dispsw = &e1355_dispsw;
+-      
+-      switch(disp->var.bits_per_pixel) {
+-#ifdef FBCON_HAS_MFB
+-      case 1:
+-              d = &fbcon_mfb; break;
+-#endif               
+-#ifdef FBCON_HAS_CFB8
++      display = epson1355_read_reg(REG_DISPLAY_MODE);
++      bpp = epson1355_bpp_tab[(display >> 2) & 7];
++
++      switch (bpp) {
+       case 8:
+-              d = &fbcon_cfb8; break;
+-#endif
++              fix->visual = FB_VISUAL_PSEUDOCOLOR;
++              var->bits_per_pixel = 8;
++              var->red.offset = var->green.offset = var->blue.offset = 0;
++              var->red.length = var->green.length = var->blue.length = 8;
++              break;
++      case 16:
++              /* 5-6-5 RGB */
++              fix->visual = FB_VISUAL_TRUECOLOR;
++              var->bits_per_pixel = 16;
++              var->red.offset = 11;
++              var->red.length = 5;
++              var->green.offset = 5;
++              var->green.length = 6;
++              var->blue.offset = 0;
++              var->blue.length = 5;
++              break;
+       default:
+-              BUG(); break;
++              BUG();
+       }
+-      memcpy(&e1355_dispsw, d, sizeof *d);
++      if (fix->visual == FB_VISUAL_TRUECOLOR) {
++              info->pseudo_palette = &pseudo_palette;
++              fb_alloc_cmap(&(info->cmap), 16, 0);
++      } else
++              fb_alloc_cmap(&(info->cmap), 1 << bpp, 0);
++
++      panel = epson1355_read_reg(REG_PANEL_TYPE);
++      is_color = (panel & 0x04) != 0;
++      is_dual = (panel & 0x02) != 0;
++      is_tft = (panel & 0x01) != 0;
++      crt_enabled = (display & 0x02) != 0;
++      lcd_enabled = (display & 0x01) != 0;
++      lcd_bpp = epson1355_width_tab[is_tft][(panel >> 4) & 3];
++
++      xres = (epson1355_read_reg(REG_HORZ_DISP_WIDTH) + 1) * 8;
++      yres = (epson1355_read_reg16(REG_VERT_DISP_HEIGHT0) + 1) *
++          ((is_dual && !crt_enabled) ? 2 : 1);
++      offset = epson1355_read_reg16(REG_MEM_ADDR_OFFSET0) & 0x7ff;
++      xres_virtual = offset * 16 / bpp;
++      yres_virtual = fix->smem_len / (offset * 2);
++
++      var->xres = xres;
++      var->yres = yres;
++      var->xres_virtual = xres_virtual;
++      var->yres_virtual = yres_virtual;
++      var->xoffset = var->yoffset = 0;
+-      /* reading is terribly slow for us */
+-#if 0 /* XXX: need to work out why this doesn't work */
+-      e1355_dispsw.bmove = fbcon_redraw_bmove;
++      fix->line_length = offset * 2;
++
++      fix->xpanstep = 0;      /* no pan yet */
++      fix->ypanstep = 1;
++      fix->ywrapstep = 0;
++      fix->accel = FB_ACCEL_NONE;
++
++      var->grayscale = !is_color;
++
++#ifdef DEBUG
++      printk(KERN_INFO
++             "epson1355fb: xres=%d, yres=%d, "
++             "is_color=%d, is_dual=%d, is_tft=%d\n",
++             xres, yres, is_color, is_dual, is_tft);
++      printk(KERN_INFO
++             "epson1355fb: bpp=%d, lcd_bpp=%d, "
++             "crt_enabled=%d, lcd_enabled=%d\n",
++             bpp, lcd_bpp, crt_enabled, lcd_enabled);
+ #endif
+ }
+-/* ------------ Interfaces to hardware functions ------------ */
++static void clearfb16(struct fb_info *info)
++{
++      u16 *dst = (u16 *) info->screen_base;
++      unsigned long n = info->fix.smem_len;
+-struct fbgen_hwswitch e1355_switch = {
+-      .detect =       e1355_detect,
+-      .encode_fix =   e1355_encode_fix,
+-      .decode_var =   e1355_decode_var,
+-      .encode_var =   e1355_encode_var,
+-      .get_par =      e1355_get_par,
+-      .set_par =      e1355_set_par,
+-      .getcolreg =    e1355_getcolreg,
+-      .pan_display =  e1355_pan_display,
+-      .blank =        e1355_blank,
+-      .set_disp =     e1355_set_disp,
+-};
++      while (n > 1) {
++              fb_writew(0, dst);
++              dst++, n -= 2;
++      }
++      if (n)
++              fb_writeb(0, dst);
++}
+-/* ------------ Hardware Independent Functions ------------ */
++static void epson1355fb_deinit(void);
++int __init epson1355fb_init(void)
++{
++      u8 revision;
++      int rc = 0;
+-static struct fb_ops e1355fb_ops = {
+-      .owner =        THIS_MODULE,
+-      .fb_get_fix =   fbgen_get_fix,
+-      .fb_get_var =   fbgen_get_var,
+-      .fb_set_var =   fbgen_set_var,
+-      .fb_get_cmap =  fbgen_get_cmap,
+-      .fb_set_cmap =  gen_set_cmap,
+-      .fb_setcolreg = e1355fb_setcolreg,
+-      .fb_pan_display =fbgen_pan_display,
+-      .fb_blank =     fbgen_blank,
+-};
++      if (!request_mem_region
++          (EPSON1355FB_REGS_PHYS, EPSON1355FB_REGS_LEN,
++           "S1D13505 registers")) {
++              printk(KERN_ERR "epson1355fb: unable to reserve "
++                     "registers at 0x%0x\n", EPSON1355FB_REGS_PHYS);
++              rc = -EBUSY;
++              goto bail;
++      }
+-static struct e1355fb_info fb_info;
++      if (!request_mem_region(EPSON1355FB_FB_PHYS, EPSON1355FB_FB_LEN,
++                              "S1D13505 framebuffer")) {
++              printk(KERN_ERR "epson1355fb: unable to reserve "
++                     "framebuffer at 0x%0x\n", EPSON1355FB_FB_PHYS);
++              rc = -EBUSY;
++              goto bail;
++      }
++
++      par.reg_addr = (unsigned long)
++          ioremap(EPSON1355FB_REGS_PHYS, EPSON1355FB_REGS_LEN);
++      if (!par.reg_addr) {
++              printk(KERN_ERR "epson1355fb: unable to map registers\n");
++              rc = -ENOMEM;
++              goto bail;
++      }
++
++      info.screen_base =
++          ioremap(EPSON1355FB_FB_PHYS, EPSON1355FB_FB_LEN);
++      if (!info.screen_base) {
++              printk(KERN_ERR
++                     "epson1355fb: unable to map framebuffer\n");
++              rc = -ENOMEM;
++              goto bail;
++      }
++
++      revision = epson1355_read_reg(REG_REVISION_CODE);
++      if ((revision >> 2) != 3) {
++              printk(KERN_INFO "epson1355fb: epson1355 not found\n");
++              rc = -ENODEV;
++              goto bail;
++      }
++
++      info.fix.mmio_start = EPSON1355FB_REGS_PHYS;
++      info.fix.mmio_len = EPSON1355FB_REGS_LEN;
++      info.fix.smem_start = EPSON1355FB_FB_PHYS;
++      info.fix.smem_len = get_fb_size(&info);
++
++      printk(KERN_INFO
++             "epson1355fb: regs mapped at 0x%lx, fb %d KiB mapped at 0x%p\n",
++             par.reg_addr, info.fix.smem_len / 1024, info.screen_base);
++
++      strcpy(info.fix.id, "S1D13505");
++      info.par = &par;
++      info.node = NODEV;
++      info.fbops = &epson1355fb_fbops;
++      info.flags = FBINFO_FLAG_DEFAULT;
++
++      /* we expect the boot loader to have initialized the chip
++         with appropriate parameters from which we can determinte
++         the flavor of lcd panel attached */
++      fetch_hw_state(&info);
++
++      /* turn this puppy on ... */
++      clearfb16(&info);
++      backlight_enable(1);
++      lcd_enable(1);
++
++      if (register_framebuffer(&info) < 0) {
++              rc = -EINVAL;
++              goto bail;
++      }
++
++      printk(KERN_INFO "fb%d: %s frame buffer device\n",
++             minor(info.node), info.fix.id);
+-int __init e1355fb_setup(char *str)
+-{
+       return 0;
++
++      bail:
++      epson1355fb_deinit();
++      return rc;
+ }
+-int __init e1355fb_init(void)
++static void epson1355fb_deinit(void)
+ {
+-      fb_info.gen.fbhw = &e1355_switch;
+-      fb_info.gen.fbhw->detect();
+-      strcpy(fb_info.gen.info.modename, "SED1355");
+-      fb_info.gen.info.changevar = NULL;
+-      fb_info.gen.info.fbops = &e1355fb_ops;
+-      fb_info.gen.info.screen_base = (void *)E1355_FB_BASE;
+-      fb_info.gen.currcon = -1;
+-      fb_info.gen.info.disp = &disp;
+-      fb_info.gen.parsize = sizeof(struct e1355_par);
+-      fb_info.gen.info.switch_con = &fbgen_switch;
+-      fb_info.gen.info.updatevar = &fbgen_update_var;
+-      fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
+-      /* This should give a reasonable default video mode */
+-      fbgen_get_var(&disp.var, -1, &fb_info.gen.info);
+-      fbgen_do_set_var(&disp.var, 1, &fb_info.gen);
+-      fbgen_set_disp(-1, &fb_info.gen);
+-      if (disp.var.bits_per_pixel > 1) 
+-              do_install_cmap(0, &fb_info.gen);
+-      if (register_framebuffer(&fb_info.gen.info) < 0)
+-              return -EINVAL;
+-      printk(KERN_INFO "fb%d: %s frame buffer device\n", fb_info.gen.info.node,
+-             fb_info.gen.info.modename);
++      fb_dealloc_cmap(&info.cmap);
+-      return 0;
++      if (info.screen_base)
++              iounmap(info.screen_base);
++      if (par.reg_addr)
++              iounmap((void *) par.reg_addr);
++
++      release_mem_region(EPSON1355FB_FB_PHYS, EPSON1355FB_FB_LEN);
++      release_mem_region(EPSON1355FB_REGS_PHYS, EPSON1355FB_REGS_LEN);
+ }
++static void __exit epson1355fb_cleanup(void)
++{
++      backlight_enable(0);
++      lcd_enable(0);
+-    /*
+-     *  Cleanup
+-     */
+-
+-void e1355fb_cleanup(struct fb_info *info)
+-{
+-      /*
+-       *  If your driver supports multiple boards, you should unregister and
+-       *  clean up all instances.
+-       */
+-      
+-      unregister_framebuffer(info);
+-      /* ... */
++      unregister_framebuffer(&info);
++      epson1355fb_deinit();
+ }
++/* ------------------------------------------------------------------------- */
++
++#ifdef MODULE
++module_init(epson1355fb_init);
++#endif
++module_exit(epson1355fb_cleanup);
++
++MODULE_AUTHOR("Christopher Hoover <ch@hpl.hp.com>");
++MODULE_DESCRIPTION("Framebuffer driver for Epson S1D13505");
+ MODULE_LICENSE("GPL");
+--- linux-2.6.0-test6/drivers/video/fbmem.c    2003-09-08 13:58:58.000000000 -0700
++++ 25/drivers/video/fbmem.c   2003-10-05 00:34:22.000000000 -0700
+@@ -25,7 +25,6 @@
+ #include <linux/mman.h>
+ #include <linux/tty.h>
+ #include <linux/init.h>
+-#include <linux/linux_logo.h>
+ #include <linux/proc_fs.h>
+ #ifdef CONFIG_KMOD
+ #include <linux/kmod.h>
+@@ -102,13 +101,13 @@ extern int hgafb_setup(char*);
+ extern int matroxfb_init(void);
+ extern int matroxfb_setup(char*);
+ extern int hpfb_init(void);
+-extern int control_init(void);
+-extern int control_setup(char*);
+-extern int platinum_init(void);
+-extern int platinum_setup(char*);
++extern int controlfb_init(void);
++extern int controlfb_setup(char*);
++extern int platinumfb_init(void);
++extern int platinumfb_setup(char*);
+ extern int valkyriefb_init(void);
+ extern int valkyriefb_setup(char*);
+-extern int chips_init(void);
++extern int chipsfb_init(void);
+ extern int g364fb_init(void);
+ extern int sa1100fb_init(void);
+ extern int fm2fb_init(void);
+@@ -135,14 +134,14 @@ extern int tx3912fb_init(void);
+ extern int tx3912fb_setup(char*);
+ extern int radeonfb_init(void);
+ extern int radeonfb_setup(char*);
+-extern int e1355fb_init(void);
+-extern int e1355fb_setup(char*);
++extern int epson1355fb_init(void);
+ extern int pvr2fb_init(void);
+ extern int pvr2fb_setup(char*);
+ extern int sstfb_init(void);
+ extern int sstfb_setup(char*);
+ extern int i810fb_init(void);
+ extern int i810fb_setup(char*);
++extern int asiliantfb_init(void);
+ extern int ffb_init(void);
+ extern int ffb_setup(char*);
+ extern int cg6_init(void);
+@@ -221,16 +220,16 @@ static struct {
+       { "radeonfb", radeonfb_init, radeonfb_setup },
+ #endif
+ #ifdef CONFIG_FB_CONTROL
+-      { "controlfb", control_init, control_setup },
++      { "controlfb", controlfb_init, controlfb_setup },
+ #endif
+ #ifdef CONFIG_FB_PLATINUM
+-      { "platinumfb", platinum_init, platinum_setup },
++      { "platinumfb", platinumfb_init, platinumfb_setup },
+ #endif
+ #ifdef CONFIG_FB_VALKYRIE
+       { "valkyriefb", valkyriefb_init, valkyriefb_setup },
+ #endif
+ #ifdef CONFIG_FB_CT65550
+-      { "chipsfb", chips_init, NULL },
++      { "chipsfb", chipsfb_init, NULL },
+ #endif
+ #ifdef CONFIG_FB_IMSTT
+       { "imsttfb", imsttfb_init, imsttfb_setup },
+@@ -342,8 +341,8 @@ static struct {
+ #ifdef CONFIG_FB_TX3912
+       { "tx3912fb", tx3912fb_init, tx3912fb_setup },
+ #endif
+-#ifdef CONFIG_FB_E1355
+-      { "e1355fb", e1355fb_init, e1355fb_setup },
++#ifdef CONFIG_FB_EPSON1355
++      { "s1d1355fb", epson1355fb_init, NULL },
+ #endif
+ #ifdef CONFIG_FB_PVR2
+       { "pvr2fb", pvr2fb_init, pvr2fb_setup },
+@@ -360,6 +359,10 @@ static struct {
+ #ifdef CONFIG_FB_VOODOO1
+       { "sstfb", sstfb_init, sstfb_setup },
+ #endif
++#ifdef CONFIG_FB_ASILIANT
++      { "asiliantfb", asiliantfb_init, NULL },
++#endif
++
+       /*
+        * Generic drivers that don't use resource management (yet)
+        */
+@@ -409,20 +412,20 @@ void sys_outbuf(u8 *src, u8 *dst, unsign
+       memcpy(dst, src, size);
+ }     
+-void move_buf_aligned(struct fb_info *info, u8 *dst, u8 *src, u32 d_pitch, 
+-                      u32 s_pitch, u32 height)
++void move_buf_aligned(struct fb_info *info, struct fb_pixmap *buf, u8 *dst, u8 *src,
++                      u32 d_pitch, u32 s_pitch, u32 height)
+ {
+       int i;
+       for (i = height; i--; ) {
+-              info->pixmap.outbuf(src, dst, s_pitch);
++              buf->outbuf(src, dst, s_pitch);
+               src += s_pitch;
+               dst += d_pitch;
+       }
+ }
+-void move_buf_unaligned(struct fb_info *info, u8 *dst, u8 *src, u32 d_pitch, 
+-                      u32 height, u32 mask, u32 shift_high, u32 shift_low,
++void move_buf_unaligned(struct fb_info *info, struct fb_pixmap *buf, u8 *dst, u8 *src,
++                      u32 d_pitch, u32 height, u32 mask, u32 shift_high, u32 shift_low,
+                       u32 mod, u32 idx)
+ {
+       int i, j;
+@@ -430,21 +433,21 @@ void move_buf_unaligned(struct fb_info *
+       for (i = height; i--; ) {
+               for (j = 0; j < idx; j++) {
+-                      tmp = info->pixmap.inbuf(dst+j);
++                      tmp = buf->inbuf(dst+j);
+                       tmp &= mask;
+                       tmp |= *src >> shift_low;
+-                      info->pixmap.outbuf(&tmp, dst+j, 1);
++                      buf->outbuf(&tmp, dst+j, 1);
+                       tmp = *src << shift_high;
+-                      info->pixmap.outbuf(&tmp, dst+j+1, 1);
++                      buf->outbuf(&tmp, dst+j+1, 1);
+                       src++;
+               }
+-              tmp = info->pixmap.inbuf(dst+idx);
++              tmp = buf->inbuf(dst+idx);
+               tmp &= mask;
+               tmp |= *src >> shift_low;
+-              info->pixmap.outbuf(&tmp, dst+idx, 1);
++              buf->outbuf(&tmp, dst+idx, 1);
+               if (shift_high < mod) {
+                       tmp = *src << shift_high;
+-                      info->pixmap.outbuf(&tmp, dst+idx+1, 1);
++                      buf->outbuf(&tmp, dst+idx+1, 1);
+               }       
+               src++;
+               dst += d_pitch;
+@@ -455,26 +458,29 @@ void move_buf_unaligned(struct fb_info *
+  * we need to lock this section since fb_cursor
+  * may use fb_imageblit()
+  */
+-u32 fb_get_buffer_offset(struct fb_info *info, u32 size)
++char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size)
+ {
+-      u32 align = info->pixmap.buf_align - 1;
++      u32 align = buf->buf_align - 1;
+       u32 offset, count = 1000;
++      char *addr = buf->addr;
+-      spin_lock(&info->pixmap.lock);
+-      offset = info->pixmap.offset + align;
+-      offset &= ~align;
+-      if (offset + size > info->pixmap.size) {
+-              while (atomic_read(&info->pixmap.count) && count--);
+-              if (info->fbops->fb_sync && 
+-                  info->pixmap.flags & FB_PIXMAP_SYNC)
+-                      info->fbops->fb_sync(info);
+-              offset = 0;
++      spin_lock(&buf->lock);
++      if (!(buf->flags & FB_PIXMAP_IO)) {
++              offset = buf->offset + align;
++              offset &= ~align;
++              if (offset + size > buf->size) {
++                      while (atomic_read(&buf->count) && count--);
++                      if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC))
++                              info->fbops->fb_sync(info);
++                      offset = 0;
++              }
++              buf->offset = offset + size;
++              addr += offset;
+       }
+-      info->pixmap.offset = offset + size;
+-      atomic_inc(&info->pixmap.count);        
++      atomic_inc(&buf->count);
+       smp_mb__after_atomic_inc();
+-      spin_unlock(&info->pixmap.lock);
+-      return offset;
++      spin_unlock(&buf->lock);
++      return addr;
+ }
+ #ifdef CONFIG_LOGO
+@@ -656,7 +662,7 @@ int fb_prepare_logo(struct fb_info *info
+       }
+       /* Return if no suitable logo was found */
+-      fb_logo.logo = fb_find_logo(info->var.bits_per_pixel);
++      fb_logo.logo = find_logo(info->var.bits_per_pixel);
+       
+       if (!fb_logo.logo || fb_logo.logo->height > info->var.yres) {
+               fb_logo.logo = NULL;
+@@ -726,8 +732,6 @@ int fb_show_logo(struct fb_info *info)
+            x <= info->var.xres-fb_logo.logo->width; x += (fb_logo.logo->width + 8)) {
+               image.dx = x;
+               info->fbops->fb_imageblit(info, &image);
+-              //atomic_dec(&info->pixmap.count);
+-              //smp_mb__after_atomic_dec();
+       }
+       
+       if (palette != NULL)
+@@ -1238,6 +1242,22 @@ register_framebuffer(struct fb_info *fb_
+               fb_info->pixmap.inbuf = sys_inbuf;
+       spin_lock_init(&fb_info->pixmap.lock);
++      if (fb_info->sprite.addr == NULL) {
++              fb_info->sprite.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
++              if (fb_info->sprite.addr) {
++                      fb_info->sprite.size = FBPIXMAPSIZE;
++                      fb_info->sprite.buf_align = 1;
++                      fb_info->sprite.scan_align = 1;
++                      fb_info->sprite.flags = FB_PIXMAP_IO;
++              }
++      }
++      fb_info->sprite.offset = 0;
++      if (fb_info->sprite.outbuf == NULL)
++              fb_info->sprite.outbuf = sys_outbuf;
++      if (fb_info->sprite.inbuf == NULL)
++              fb_info->sprite.inbuf = sys_inbuf;
++      spin_lock_init(&fb_info->sprite.lock);
++
+       registered_fb[i] = fb_info;
+       devfs_mk_cdev(MKDEV(FB_MAJOR, i),
+@@ -1371,6 +1391,33 @@ int __init video_setup(char *options)
+ __setup("video=", video_setup);
++static int fbdev_dummy(void)
++{
++      return 0;
++}
++
++#define FBDEV_EMPTY (void *)fbdev_dummy
++
++const struct fb_ops dummy_fbdev = {
++      .fb_open        = FBDEV_EMPTY,
++      .fb_release     = FBDEV_EMPTY,
++      .fb_read        = FBDEV_EMPTY,
++      .fb_write       = FBDEV_EMPTY,
++      .fb_check_var   = FBDEV_EMPTY,
++      .fb_set_par     = FBDEV_EMPTY,
++      .fb_setcolreg   = FBDEV_EMPTY,
++      .fb_blank       = FBDEV_EMPTY,
++      .fb_pan_display = FBDEV_EMPTY,
++      .fb_fillrect    = FBDEV_EMPTY,
++      .fb_copyarea    = FBDEV_EMPTY,
++      .fb_imageblit   = FBDEV_EMPTY,
++      .fb_cursor      = FBDEV_EMPTY,
++      .fb_rotate      = FBDEV_EMPTY,
++      .fb_sync        = FBDEV_EMPTY,
++      .fb_ioctl       = FBDEV_EMPTY,
++      .fb_mmap        = FBDEV_EMPTY,
++};
++
+     /*
+      *  Visible symbols for modules
+      */
+--- linux-2.6.0-test6/drivers/video/g364fb.c   2003-06-14 12:17:58.000000000 -0700
++++ 25/drivers/video/g364fb.c  2003-10-05 00:34:22.000000000 -0700
+@@ -127,20 +127,55 @@ static struct fb_ops g364fb_ops = {
+ int g364fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+ {
++
++      /* Turn the cursor off before we start changing it. */
++      *(unsigned int *) CTLA_REG |= CURS_TOGGLE;
++
++      if (cursor->set & FB_CUR_SETHOT)
++              info->cursor.hot = cursor->hot;
+       
+-      switch (cursor->enable) {
+-      case CM_ERASE:
+-              *(unsigned int *) CTLA_REG |= CURS_TOGGLE;
+-              break;
++      if (cursor->set & FB_CUR_SETPOS) {
++              unsigned int tmp;
+-      case CM_MOVE:
+-      case CM_DRAW:
+-              *(unsigned int *) CTLA_REG &= ~CURS_TOGGLE;
+-              *(unsigned int *) CURS_POS_REG =
+-                  ((x * fontwidth(p)) << 12) | ((y * fontheight(p)) -
+-                                                info->var.yoffset);
+-              break;
++              info->cursor.image.dx = cursor->image.dx;
++              info->cursor.image.dy = cursor->image.dy;
++
++              tmp = cursor->image.dy - info->var.yoffset;
++              tmp |= (cursor->image.dx - info->var.xoffset) << 12;
++
++              *(unsigned int *) CURS_POS_REG = tmp;
++      }
++
++      if (cursor->set & FB_CUR_SETSIZE) {
++              info->cursor.image.height = cursor->image.height;
++              info->cursor.image.width = cursor->image.width;
++
++              /* set the whole cursor to transparent */
++              for (i = 0; i < 512; i++)
++                      *(unsigned short *) (CURS_PAT_REG + i * 8) = 0;
+       }
++
++      if (cursor->set & FB_CUR_SETCMAP) {
++              volatile unsigned int *curs_pal_ptr =
++                              (volatile unsigned int *) CURS_PAL_REG;
++
++              /* setup cursor */
++              curs_pal_ptr[0] |= 0x00ffffff;
++              curs_pal_ptr[2] |= 0x00ffffff;
++              curs_pal_ptr[4] |= 0x00ffffff;
++      }
++
++      if (cursor->set & FB_CUR_SETSHAPE) {
++              /*
++               * switch the last two lines to cursor palette 3
++               * we assume here, that FONTSIZE_X is 8
++               */
++              *(unsigned short *) (CURS_PAT_REG + 14 * 64) = 0xffff;
++              *(unsigned short *) (CURS_PAT_REG + 15 * 64) = 0xffff;
++      }
++
++      if (info->cursor.enable)
++              *(unsigned int *) CTLA_REG &= ~CURS_TOGGLE;
+       return 0;
+ }
+@@ -196,10 +231,6 @@ static int g364fb_setcolreg(u_int regno,
+  */
+ int __init g364fb_init(void)
+ {
+-      volatile unsigned int *pal_ptr =
+-          (volatile unsigned int *) CLR_PAL_REG;
+-      volatile unsigned int *curs_pal_ptr =
+-          (volatile unsigned int *) CURS_PAL_REG;
+       int mem, i, j;
+       /* TBD: G364 detection */
+@@ -212,23 +243,6 @@ int __init g364fb_init(void)
+           (*((volatile unsigned int *) VDISPLAY_REG) & 0x00ffffff) / 2;
+       *(volatile unsigned int *) CTLA_REG |= ENABLE_VTG;
+-      /* setup cursor */
+-      curs_pal_ptr[0] |= 0x00ffffff;
+-      curs_pal_ptr[2] |= 0x00ffffff;
+-      curs_pal_ptr[4] |= 0x00ffffff;
+-
+-      /*
+-       * first set the whole cursor to transparent
+-       */
+-      for (i = 0; i < 512; i++)
+-              *(unsigned short *) (CURS_PAT_REG + i * 8) = 0;
+-
+-      /*
+-       * switch the last two lines to cursor palette 3
+-       * we assume here, that FONTSIZE_X is 8
+-       */
+-      *(unsigned short *) (CURS_PAT_REG + 14 * 64) = 0xffff;
+-      *(unsigned short *) (CURS_PAT_REG + 15 * 64) = 0xffff;
+       fb_var.xres_virtual = fbvar.xres;
+       fb_fix.line_length = (xres / 8) * fb_var.bits_per_pixel;
+       fb_fix.smem_start = 0x40000000; /* physical address */
+--- linux-2.6.0-test6/drivers/video/i810/Makefile      2003-06-14 12:18:06.000000000 -0700
++++ 25/drivers/video/i810/Makefile     2003-10-05 00:34:22.000000000 -0700
+@@ -1,16 +1,9 @@
+ #
+ # Makefile for the Intel 810/815 framebuffer driver
+ #
+-# Note! Dependencies are done automagically by 'make dep', which also
+-# removes any old dependencies. DON'T put your own dependencies here
+-# unless it's something special (ie not a .c file).
+-#
+-# Note 2! The CFLAGS definitions are now in the main makefile...
+-
+ obj-$(CONFIG_FB_I810)         += i810fb.o
+-
+ i810fb-objs                     := i810_main.o i810_accel.o
+ ifdef CONFIG_FB_I810_GTF
+--- linux-2.6.0-test6/drivers/video/imsttfb.c  2003-08-08 22:55:13.000000000 -0700
++++ 25/drivers/video/imsttfb.c 2003-10-05 00:34:22.000000000 -0700
+@@ -1495,6 +1495,8 @@ imsttfb_probe(struct pci_dev *pdev, cons
+               default:
+                       printk(KERN_INFO "imsttfb: Device 0x%x unknown, "
+                                        "contact maintainer.\n", pdev->device);
++                      release_mem_region(addr, size);
++                      kfree(info);
+                       return -ENODEV;
+       }
+--- linux-2.6.0-test6/drivers/video/Kconfig    2003-09-27 18:57:46.000000000 -0700
++++ 25/drivers/video/Kconfig   2003-10-05 00:34:22.000000000 -0700
+@@ -188,19 +188,19 @@ config FB_AMIGA_AGA
+         otherwise say N.
+ config FB_CYBER
+-      tristate "Amiga CyberVision support"
+-      depends on FB && ZORRO
++      tristate "Amiga CyberVision 64 support"
++      depends on FB && ZORRO && BROKEN
+       help
+         This enables support for the Cybervision 64 graphics card from
+         Phase5. Please note that its use is not all that intuitive (i.e. if
+         you have any questions, be sure to ask!). Say N unless you have a
+         Cybervision 64 or plan to get one before you next recompile the
+         kernel. Please note that this driver DOES NOT support the
+-        Cybervision 64 3D card, as they use incompatible video chips.
++        Cybervision 64/3D card, as they use incompatible video chips.
+ config FB_VIRGE
+-      bool "Amiga CyberVision3D support "
+-      depends on FB && ZORRO
++      bool "Amiga CyberVision 64/3D support "
++      depends on FB && ZORRO && BROKEN
+       help
+         This enables support for the Cybervision 64/3D graphics card from
+         Phase5. Please note that its use is not all that intuitive (i.e. if
+@@ -210,8 +210,8 @@ config FB_VIRGE
+         Cybervision 64 card, as they use incompatible video chips.
+ config FB_RETINAZ3
+-      tristate "Amiga RetinaZ3 support"
+-      depends on FB && ZORRO
++      tristate "Amiga Retina Z3 support"
++      depends on FB && ZORRO && BROKEN
+       help
+         This enables support for the Retina Z3 graphics card. Say N unless
+         you have a Retina Z3 or plan to get one before you next recompile
+@@ -226,7 +226,7 @@ config FB_FM2
+ config FB_ATARI
+       bool "Atari native chipset support"
+-      depends on FB && ATARI
++      depends on FB && ATARI && BROKEN
+       help
+         This is the frame buffer device driver for the builtin graphics
+         chipset found in Ataris.
+@@ -266,6 +266,10 @@ config FB_CT65550
+         This is the frame buffer device driver for the Chips & Technologies
+         65550 graphics chip in PowerBooks.
++config FB_ASILIANT
++      bool "Chips 69000 display support"
++      depends on FB && PCI
++
+ config FB_IMSTT
+       bool "IMS Twin Turbo display support"
+       depends on FB && PCI
+@@ -367,7 +371,7 @@ config BUS_I2C
+ config FB_SUN3
+       bool "Sun3 framebuffer support"
+-      depends on FB && (SUN3 || SUN3X)
++      depends on FB && (SUN3 || SUN3X) && BROKEN
+ config FB_BW2
+       bool "BWtwo support"
+@@ -414,35 +418,15 @@ config FB_PVR2_DEBUG
+         messages. Most people will want to say N here. If unsure, you will
+         also want to say N.
+-config FB_E1355
++config FB_EPSON1355
+       bool "Epson 1355 framebuffer support"
+-      depends on FB && SUPERH
++      depends on FB && (SUPERH || ARCH_CEIVA)
+       help
+         Build in support for the SED1355 Epson Research Embedded RAMDAC
+         LCD/CRT Controller (since redesignated as the S1D13505) as a
+         framebuffer.  Product specs at
+         <http://www.erd.epson.com/vdc/html/products.htm>.
+-config E1355_REG_BASE
+-      hex "Register Base Address"
+-      depends on FB_E1355
+-      default "a8000000"
+-      help
+-        Epson SED1355/S1D13505 LCD/CRT controller register base address.
+-        See the manuals at
+-        <http://www.erd.epson.com/vdc/html/contents/S1D13505.htm> for
+-        discussion.
+-
+-config E1355_FB_BASE
+-      hex "Framebuffer Base Address"
+-      depends on FB_E1355
+-      default "a8200000"
+-      help
+-        Epson SED1355/S1D13505 LCD/CRT controller memory base address.  See
+-        the manuals at
+-        <http://www.erd.epson.com/vdc/html/contents/S1D13505.htm> for
+-        discussion.
+-
+ config FB_RIVA
+       tristate "nVidia Riva support"
+       depends on FB && PCI
+@@ -703,26 +687,40 @@ config FB_ATY_XL_INIT
+         Say Y here to support booting a Rage XL without BIOS support.
+ config FB_SIS
+-      tristate "SIS acceleration"
++      tristate "SiS acceleration"
+       depends on FB && PCI
+       help
+-        This is the frame buffer device driver for the SiS 630 and 640 Super
+-        Socket 7 UMA cards.  Specs available at <http://www.sis.com.tw/>.
++        This is the frame buffer device driver for the SiS 300, 315 and Xabre
++        series VGA controller.
++
++        Specs available at <http://www.sis.com.tw/>.
++
++        See <http://www.winischhofer.net/linuxsisvga.shtml> for
++        documentation and updates.
++
++        The 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 sisfb. If you want to compile it as a
++        module, say M here and read Documentation/modules.txt.
+ config FB_SIS_300
+-      bool "SIS 630/540/730 support"
++      bool "SIS 300 series support"
+       depends on FB_SIS
+       help
+-        This is the frame buffer device driver for the SiS 630 and related
+-        Super Socket 7 UMA cards.  Specs available at
+-        <http://www.sis.com.tw/>.
++        This is the frame buffer device driver for the SiS 300 series VGA
++        controllers. This includes the 300, 540, 630, 730.
++        Documentation and updates available at
++        http://www.winischhofer.net/linuxsisvga.shtml
+ config FB_SIS_315
+-      bool "SIS 315H/315 support"
++      bool "SIS 315/Xabre support"
+       depends on FB_SIS
+       help
+-        This is the frame buffer device driver for the SiS 315 graphics
+-        card.  Specs available at <http://www.sis.com.tw/>.
++        This is the frame buffer device driver for the SiS 315 and Xabre
++        series VGA controllers. This includes the 315, 315H, 315PRO, 650,
++        651, M650, 652, M652, 740, 330 (Xabre), 660, M660, 760, M760.
++        Documentation and updates available at
++        http://www.winischhofer.net/linuxsisvga.shtml
+ config FB_NEOMAGIC
+       tristate "NeoMagic display support"
+--- linux-2.6.0-test6/drivers/video/logo/logo.c        2003-07-27 12:14:40.000000000 -0700
++++ 25/drivers/video/logo/logo.c       2003-10-05 00:34:22.000000000 -0700
+@@ -32,8 +32,7 @@ extern const struct linux_logo logo_supe
+ extern const struct linux_logo logo_superh_vga16;
+ extern const struct linux_logo logo_superh_clut224;
+-
+-const struct linux_logo *fb_find_logo(int depth)
++const struct linux_logo *find_logo(int depth)
+ {
+       const struct linux_logo *logo = 0;
+--- linux-2.6.0-test6/drivers/video/Makefile   2003-09-08 13:58:58.000000000 -0700
++++ 25/drivers/video/Makefile  2003-10-05 00:34:22.000000000 -0700
+@@ -22,7 +22,7 @@ obj-$(CONFIG_FB_Q40)              += q40
+ obj-$(CONFIG_FB_ATARI)            += atafb.o
+ obj-$(CONFIG_FB_68328)            += 68328fb.o
+ obj-$(CONFIG_FB_RADEON)                 += radeonfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
+-obj-$(CONFIG_FB_NEOMAGIC)         += neofb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
++obj-$(CONFIG_FB_NEOMAGIC)         += neofb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o vgastate.o
+ obj-$(CONFIG_FB_IGA)              += igafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
+ obj-$(CONFIG_FB_CONTROL)          += controlfb.o macmodes.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
+ obj-$(CONFIG_FB_PLATINUM)         += platinumfb.o macmodes.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
+@@ -68,9 +68,10 @@ obj-$(CONFIG_FB_HGA)              += hga
+ obj-$(CONFIG_FB_SA1100)           += sa1100fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
+ obj-$(CONFIG_FB_VIRTUAL)          += vfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o 
+ obj-$(CONFIG_FB_HIT)              += hitfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
+-obj-$(CONFIG_FB_E1355)            += epson1355fb.o
+-obj-$(CONFIG_FB_PVR2)             += pvr2fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
++obj-$(CONFIG_FB_EPSON1355)        += epson1355fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
++obj-$(CONFIG_FB_PVR2)             += pvr2fb.o cfbcillrect.o cfbcopyarea.o cfbimgblt.o
+ obj-$(CONFIG_FB_VOODOO1)          += sstfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
++obj-$(CONFIG_FB_ASILIANT)         += asiliantfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
+ obj-$(CONFIG_FB_FFB)               += ffb.o sbuslib.o cfbimgblt.o cfbcopyarea.o
+ obj-$(CONFIG_FB_CG6)               += cg6.o sbuslib.o cfbimgblt.o cfbcopyarea.o
+--- linux-2.6.0-test6/drivers/video/neofb.c    2003-08-08 22:55:13.000000000 -0700
++++ 25/drivers/video/neofb.c   2003-10-05 00:34:22.000000000 -0700
+@@ -81,9 +81,10 @@ extern int tosh_smm(SMMRegisters *regs);
+ #include <asm/mtrr.h>
+ #endif
++#include <video/vga.h>
+ #include <video/neomagic.h>
+-#define NEOFB_VERSION "0.4.1"
++#define NEOFB_VERSION "0.4.2"
+ /* --------------------------------------------------------------------- */
+@@ -152,6 +153,16 @@ static biosMode bios32[] = {
+ };
+ #endif
++static inline u32 read_le32(int regindex, const struct neofb_par *par)
++{
++      return readl(par->neo2200 + par->cursorOff + regindex);
++}
++
++static inline void write_le32(int regindex, u32 val, const struct neofb_par *par)
++{
++      writel(val, par->neo2200 + par->cursorOff + regindex);
++}
++
+ static int neoFindMode(int xres, int yres, int depth)
+ {
+       int xres_s;
+@@ -363,44 +374,61 @@ static int vgaHWInit(const struct fb_var
+       par->Attribute[18] = 0x0F;
+       par->Attribute[19] = 0x00;
+       par->Attribute[20] = 0x00;
+-
+       return 0;
+ }
+-static void vgaHWLock(void)
++static void vgaHWLock(struct vgastate *state)
+ {
+       /* Protect CRTC[0-7] */
+-      VGAwCR(0x11, VGArCR(0x11) | 0x80);
++      vga_wcrt(state->vgabase, 0x11, vga_rcrt(state->vgabase, 0x11) | 0x80);
+ }
+ static void vgaHWUnlock(void)
+ {
+       /* Unprotect CRTC[0-7] */
+-      VGAwCR(0x11, VGArCR(0x11) & ~0x80);
++      vga_wcrt(NULL, 0x11, vga_rcrt(NULL, 0x11) & ~0x80);
+ }
+-static void neoLock(void)
++static void neoLock(struct vgastate *state)
+ {
+-      VGAwGR(0x09, 0x00);
+-      vgaHWLock();
++      vga_wgfx(state->vgabase, 0x09, 0x00);
++      vgaHWLock(state);
+ }
+ static void neoUnlock(void)
+ {
+       vgaHWUnlock();
+-      VGAwGR(0x09, 0x26);
++      vga_wgfx(NULL, 0x09, 0x26);
+ }
+ /*
+- * vgaHWSeqReset
+- *      perform a sequencer reset.
++ * VGA Palette management
+  */
+-void vgaHWSeqReset(int start)
++static int paletteEnabled = 0;
++
++inline void VGAenablePalette(void)
+ {
+-      if (start)
+-              VGAwSEQ(0x00, 0x01);    /* Synchronous Reset */
++      vga_r(NULL, VGA_IS1_RC);
++      vga_w(NULL, VGA_ATT_W, 0x00);
++      paletteEnabled = 1;
++}
++
++inline void VGAdisablePalette(void)
++{
++      vga_r(NULL, VGA_IS1_RC);
++      vga_w(NULL, VGA_ATT_W, 0x20);
++      paletteEnabled = 0;
++}
++
++inline void VGAwATTR(u8 index, u8 value)
++{
++      if (paletteEnabled)
++              index &= ~0x20;
+       else
+-              VGAwSEQ(0x00, 0x03);    /* End Reset */
++              index |= 0x20;
++
++      vga_r(NULL, VGA_IS1_RC);
++      vga_wattr(NULL, index, value);
+ }
+ void vgaHWProtect(int on)
+@@ -411,21 +439,18 @@ void vgaHWProtect(int on)
+               /*
+                * Turn off screen and disable sequencer.
+                */
+-              tmp = VGArSEQ(0x01);
+-
+-              vgaHWSeqReset(1);       /* start synchronous reset */
+-              VGAwSEQ(0x01, tmp | 0x20);      /* disable the display */
++              tmp = vga_rseq(NULL, 0x01);
++              vga_wseq(NULL, 0x00, 0x01);             /* Synchronous Reset */
++              vga_wseq(NULL, 0x01, tmp | 0x20);       /* disable the display */
+               VGAenablePalette();
+       } else {
+               /*
+                * Reenable sequencer, then turn on screen.
+                */
+-
+-              tmp = VGArSEQ(0x01);
+-
+-              VGAwSEQ(0x01, tmp & ~0x20);     /* reenable display */
+-              vgaHWSeqReset(0);       /* clear synchronousreset */
++              tmp = vga_rseq(NULL, 0x01);
++              vga_wseq(NULL, 0x01, tmp & ~0x20);      /* reenable display */
++              vga_wseq(NULL, 0x00, 0x03);             /* clear synchronousreset */
+               VGAdisablePalette();
+       }
+@@ -436,19 +461,19 @@ static void vgaHWRestore(const struct fb
+ {
+       int i;
+-      VGAwMISC(par->MiscOutReg);
++      vga_w(NULL, VGA_MIS_W, par->MiscOutReg);
+       for (i = 1; i < 5; i++)
+-              VGAwSEQ(i, par->Sequencer[i]);
++              vga_wseq(NULL, i, par->Sequencer[i]);
+       /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or CRTC[17] */
+-      VGAwCR(17, par->CRTC[17] & ~0x80);
++      vga_wcrt(NULL, 17, par->CRTC[17] & ~0x80);
+       for (i = 0; i < 25; i++)
+-              VGAwCR(i, par->CRTC[i]);
++              vga_wcrt(NULL, i, par->CRTC[i]);
+       for (i = 0; i < 9; i++)
+-              VGAwGR(i, par->Graphics[i]);
++              vga_wgfx(NULL, i, par->Graphics[i]);
+       VGAenablePalette();
+@@ -535,6 +560,36 @@ static inline void neo2200_accel_init(st
+ /* --------------------------------------------------------------------- */
+ static int
++neofb_open(struct fb_info *info, int user)
++{
++      struct neofb_par *par = (struct neofb_par *) info->par;
++      int cnt = atomic_read(&par->ref_count);
++
++      if (cnt) {
++              memset(&par->state, 0, sizeof(struct vgastate));
++              par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS;
++              save_vga(&par->state);
++      }
++      atomic_inc(&par->ref_count);
++      return 0;
++}
++
++static int
++neofb_release(struct fb_info *info, int user)
++{
++      struct neofb_par *par = (struct neofb_par *) info->par;
++      int cnt = atomic_read(&par->ref_count);
++
++      if (!cnt)
++              return -EINVAL;
++      if (cnt == 1) {
++              restore_vga(&par->state);
++      }
++      atomic_dec(&par->ref_count);
++      return 0;
++}
++
++static int
+ neofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+ {
+       struct neofb_par *par = (struct neofb_par *) info->par;
+@@ -981,13 +1036,13 @@ static int neofb_set_par(struct fb_info 
+       }
+       /* alread unlocked above */
+-      /* BOGUS  VGAwGR (0x09, 0x26); */
++      /* BOGUS  vga_wgfx(NULL, 0x09, 0x26); */
+       /* don't know what this is, but it's 0 from bootup anyway */
+-      VGAwGR(0x15, 0x00);
++      vga_wgfx(NULL, 0x15, 0x00);
+       /* was set to 0x01 by my bios in text and vesa modes */
+-      VGAwGR(0x0A, par->GeneralLockReg);
++      vga_wgfx(NULL, 0x0A, par->GeneralLockReg);
+       /*
+        * The color mode needs to be set before calling vgaHWRestore
+@@ -996,7 +1051,7 @@ static int neofb_set_par(struct fb_info 
+        * NOTE: Make sure we don't change bits make sure we don't change
+        * any reserved bits.
+        */
+-      temp = VGArGR(0x90);
++      temp = vga_rgfx(NULL, 0x90);
+       switch (info->fix.accel) {
+       case FB_ACCEL_NEOMAGIC_NM2070:
+               temp &= 0xF0;   /* Save bits 7:4 */
+@@ -1015,7 +1070,7 @@ static int neofb_set_par(struct fb_info 
+               break;
+       }
+-      VGAwGR(0x90, temp);
++      vga_wgfx(NULL, 0x90, temp);
+       /*
+        * In some rare cases a lockup might occur if we don't delay
+@@ -1027,9 +1082,9 @@ static int neofb_set_par(struct fb_info 
+        * Disable horizontal and vertical graphics and text expansions so
+        * that vgaHWRestore works properly.
+        */
+-      temp = VGArGR(0x25);
++      temp = vga_rgfx(NULL, 0x25);
+       temp &= 0x39;
+-      VGAwGR(0x25, temp);
++      vga_wgfx(NULL, 0x25, temp);
+       /*
+        * Sleep for 200ms to make sure that the two operations above have
+@@ -1041,19 +1096,18 @@ static int neofb_set_par(struct fb_info 
+        * This function handles restoring the generic VGA registers.  */
+       vgaHWRestore(info, par);
+-
+-      VGAwGR(0x0E, par->ExtCRTDispAddr);
+-      VGAwGR(0x0F, par->ExtCRTOffset);
+-      temp = VGArGR(0x10);
++      vga_wgfx(NULL, 0x0E, par->ExtCRTDispAddr);
++      vga_wgfx(NULL, 0x0F, par->ExtCRTOffset);
++      temp = vga_rgfx(NULL, 0x10);
+       temp &= 0x0F;           /* Save bits 3:0 */
+       temp |= (par->SysIfaceCntl1 & ~0x0F);   /* VESA Bios sets bit 1! */
+-      VGAwGR(0x10, temp);
++      vga_wgfx(NULL, 0x10, temp);
+-      VGAwGR(0x11, par->SysIfaceCntl2);
+-      VGAwGR(0x15, 0 /*par->SingleAddrPage */ );
+-      VGAwGR(0x16, 0 /*par->DualAddrPage */ );
++      vga_wgfx(NULL, 0x11, par->SysIfaceCntl2);
++      vga_wgfx(NULL, 0x15, 0 /*par->SingleAddrPage */ );
++      vga_wgfx(NULL, 0x16, 0 /*par->DualAddrPage */ );
+-      temp = VGArGR(0x20);
++      temp = vga_rgfx(NULL, 0x20);
+       switch (info->fix.accel) {
+       case FB_ACCEL_NEOMAGIC_NM2070:
+               temp &= 0xFC;   /* Save bits 7:2 */
+@@ -1074,79 +1128,78 @@ static int neofb_set_par(struct fb_info 
+               temp |= (par->PanelDispCntlReg1 & ~0x98);
+               break;
+       }
+-      VGAwGR(0x20, temp);
++      vga_wgfx(NULL, 0x20, temp);
+-      temp = VGArGR(0x25);
++      temp = vga_rgfx(NULL, 0x25);
+       temp &= 0x38;           /* Save bits 5:3 */
+       temp |= (par->PanelDispCntlReg2 & ~0x38);
+-      VGAwGR(0x25, temp);
++      vga_wgfx(NULL, 0x25, temp);
+       if (info->fix.accel != FB_ACCEL_NEOMAGIC_NM2070) {
+-              temp = VGArGR(0x30);
++              temp = vga_rgfx(NULL, 0x30);
+               temp &= 0xEF;   /* Save bits 7:5 and bits 3:0 */
+               temp |= (par->PanelDispCntlReg3 & ~0xEF);
+-              VGAwGR(0x30, temp);
++              vga_wgfx(NULL, 0x30, temp);
+       }
+-      VGAwGR(0x28, par->PanelVertCenterReg1);
+-      VGAwGR(0x29, par->PanelVertCenterReg2);
+-      VGAwGR(0x2a, par->PanelVertCenterReg3);
++      vga_wgfx(NULL, 0x28, par->PanelVertCenterReg1);
++      vga_wgfx(NULL, 0x29, par->PanelVertCenterReg2);
++      vga_wgfx(NULL, 0x2a, par->PanelVertCenterReg3);
+       if (info->fix.accel != FB_ACCEL_NEOMAGIC_NM2070) {
+-              VGAwGR(0x32, par->PanelVertCenterReg4);
+-              VGAwGR(0x33, par->PanelHorizCenterReg1);
+-              VGAwGR(0x34, par->PanelHorizCenterReg2);
+-              VGAwGR(0x35, par->PanelHorizCenterReg3);
++              vga_wgfx(NULL, 0x32, par->PanelVertCenterReg4);
++              vga_wgfx(NULL, 0x33, par->PanelHorizCenterReg1);
++              vga_wgfx(NULL, 0x34, par->PanelHorizCenterReg2);
++              vga_wgfx(NULL, 0x35, par->PanelHorizCenterReg3);
+       }
+       if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2160)
+-              VGAwGR(0x36, par->PanelHorizCenterReg4);
++              vga_wgfx(NULL, 0x36, par->PanelHorizCenterReg4);
+       if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2200 ||
+           info->fix.accel == FB_ACCEL_NEOMAGIC_NM2230 ||
+           info->fix.accel == FB_ACCEL_NEOMAGIC_NM2360 ||
+           info->fix.accel == FB_ACCEL_NEOMAGIC_NM2380) {
+-              VGAwGR(0x36, par->PanelHorizCenterReg4);
+-              VGAwGR(0x37, par->PanelVertCenterReg5);
+-              VGAwGR(0x38, par->PanelHorizCenterReg5);
++              vga_wgfx(NULL, 0x36, par->PanelHorizCenterReg4);
++              vga_wgfx(NULL, 0x37, par->PanelVertCenterReg5);
++              vga_wgfx(NULL, 0x38, par->PanelHorizCenterReg5);
+               clock_hi = 1;
+       }
+       /* Program VCLK3 if needed. */
+-      if (par->ProgramVCLK && ((VGArGR(0x9B) != par->VCLK3NumeratorLow)
+-                               || (VGArGR(0x9F) != par->VCLK3Denominator)
+-                               || (clock_hi && ((VGArGR(0x8F) & ~0x0f)
+-                                                != (par->
+-                                                    VCLK3NumeratorHigh &
++      if (par->ProgramVCLK && ((vga_rgfx(NULL, 0x9B) != par->VCLK3NumeratorLow)
++                               || (vga_rgfx(NULL, 0x9F) != par->VCLK3Denominator)
++                               || (clock_hi && ((vga_rgfx(NULL, 0x8F) & ~0x0f)
++                                                != (par->VCLK3NumeratorHigh &
+                                                     ~0x0F))))) {
+-              VGAwGR(0x9B, par->VCLK3NumeratorLow);
++              vga_wgfx(NULL, 0x9B, par->VCLK3NumeratorLow);
+               if (clock_hi) {
+-                      temp = VGArGR(0x8F);
++                      temp = vga_rgfx(NULL, 0x8F);
+                       temp &= 0x0F;   /* Save bits 3:0 */
+                       temp |= (par->VCLK3NumeratorHigh & ~0x0F);
+-                      VGAwGR(0x8F, temp);
++                      vga_wgfx(NULL, 0x8F, temp);
+               }
+-              VGAwGR(0x9F, par->VCLK3Denominator);
++              vga_wgfx(NULL, 0x9F, par->VCLK3Denominator);
+       }
+       if (par->biosMode)
+-              VGAwCR(0x23, par->biosMode);
++              vga_wcrt(NULL, 0x23, par->biosMode);
+-      VGAwGR(0x93, 0xc0);     /* Gives 5x faster framebuffer writes !!! */
++      vga_wgfx(NULL, 0x93, 0xc0);     /* Gives 5x faster framebuffer writes !!! */
+       /* Program vertical extension register */
+       if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2200 ||
+           info->fix.accel == FB_ACCEL_NEOMAGIC_NM2230 ||
+           info->fix.accel == FB_ACCEL_NEOMAGIC_NM2360 ||
+           info->fix.accel == FB_ACCEL_NEOMAGIC_NM2380) {
+-              VGAwCR(0x70, par->VerticalExt);
++              vga_wcrt(NULL, 0x70, par->VerticalExt);
+       }
+       vgaHWProtect(0);        /* Turn on screen */
+       /* Calling this also locks offset registers required in update_start */
+-      neoLock();
++      neoLock(&par->state);
+       info->fix.line_length =
+           info->var.xres_virtual * (info->var.bits_per_pixel >> 3);
+@@ -1167,6 +1220,8 @@ static int neofb_set_par(struct fb_info 
+ static void neofb_update_start(struct fb_info *info,
+                              struct fb_var_screeninfo *var)
+ {
++      struct neofb_par *par = (struct neofb_par *) info->par;
++      struct vgastate *state = &par->state;
+       int oldExtCRTDispAddr;
+       int Base;
+@@ -1180,18 +1235,18 @@ static void neofb_update_start(struct fb
+       /*
+        * These are the generic starting address registers.
+        */
+-      VGAwCR(0x0C, (Base & 0x00FF00) >> 8);
+-      VGAwCR(0x0D, (Base & 0x00FF));
++      vga_wcrt(state->vgabase, 0x0C, (Base & 0x00FF00) >> 8);
++      vga_wcrt(state->vgabase, 0x0D, (Base & 0x00FF));
+       /*
+        * Make sure we don't clobber some other bits that might already
+        * have been set. NOTE: NM2200 has a writable bit 3, but it shouldn't
+        * be needed.
+        */
+-      oldExtCRTDispAddr = VGArGR(0x0E);
+-      VGAwGR(0x0E, (((Base >> 16) & 0x0f) | (oldExtCRTDispAddr & 0xf0)));
++      oldExtCRTDispAddr = vga_rgfx(NULL, 0x0E);
++      vga_wgfx(state->vgabase, 0x0E, (((Base >> 16) & 0x0f) | (oldExtCRTDispAddr & 0xf0)));
+-      neoLock();
++      neoLock(state);
+ }
+ /*
+@@ -1353,7 +1408,7 @@ neo2200_fillrect(struct fb_info *info, c
+       }
+       par->neo2200->dstStart =
+-          dst * ((info->var.bits_per_pixel + 7) / 8);
++          dst * ((info->var.bits_per_pixel + 7) >> 3);
+       par->neo2200->xyExt =
+           (rect->height << 16) | (rect->width & 0xffff);
+ }
+@@ -1361,24 +1416,20 @@ neo2200_fillrect(struct fb_info *info, c
+ static void
+ neo2200_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+ {
+-      struct neofb_par *par = (struct neofb_par *) info->par;
+       u32 sx = area->sx, sy = area->sy, dx = area->dx, dy = area->dy;
++      struct neofb_par *par = (struct neofb_par *) info->par;
+       u_long src, dst, bltCntl;
+       bltCntl = NEO_BC3_FIFO_EN | NEO_BC3_SKIP_MAPPING | 0x0C0000;
+-      if (sy < dy) {
++      if ((dy > sy) || ((dy == sy) && (dx > sx))) {
++              /* Start with the lower right corner */
+               sy += (area->height - 1);
+               dy += (area->height - 1);
+-
+-              bltCntl |= NEO_BC0_DST_Y_DEC | NEO_BC0_SRC_Y_DEC;
+-      }
+-
+-      if (area->sx < area->dx) {
+               sx += (area->width - 1);
+               dx += (area->width - 1);
+-              bltCntl |= NEO_BC0_X_DEC;
++              bltCntl |= NEO_BC0_X_DEC | NEO_BC0_DST_Y_DEC | NEO_BC0_SRC_Y_DEC;
+       }
+       src = sx * (info->var.bits_per_pixel >> 3) + sy*info->fix.line_length;
+@@ -1496,8 +1547,60 @@ neofb_sync(struct fb_info *info)
+       return 0;               
+ }
++static int
++neofb_cursor(struct fb_info *info, struct fb_cursor *cursor)
++{
++      struct neofb_par *par = (struct neofb_par *) info->par;
++
++      /* Disable cursor */
++      write_le32(NEOREG_CURSCNTL, ~NEO_CURS_ENABLE, par);
++
++      if (cursor->set & FB_CUR_SETPOS) {
++              u32 x = cursor->image.dx;
++              u32 y = cursor->image.dy;
++
++              info->cursor.image.dx = x;
++              info->cursor.image.dy = y;
++              write_le32(NEOREG_CURSX, x, par);
++              write_le32(NEOREG_CURSY, y, par);
++      }
++
++      if (cursor->set & FB_CUR_SETSIZE) {
++      }
++
++      if (cursor->set & FB_CUR_SETCMAP) {
++              if (cursor->image.depth == 1) {
++                      u32 fg = cursor->image.fg_color;
++                      u32 bg = cursor->image.bg_color;
++
++                      info->cursor.image.fg_color = fg;
++                      info->cursor.image.bg_color = bg;
++
++                      fg = ((fg & 0xff0000) >> 16) | ((fg & 0xff) << 16) | (fg & 0xff00);
++                      bg = ((bg & 0xff0000) >> 16) | ((bg & 0xff) << 16) | (bg & 0xff00);
++                      write_le32(NEOREG_CURSFGCOLOR, fg, par);
++                      write_le32(NEOREG_CURSBGCOLOR, bg, par);
++              }
++      }
++
++      if (cursor->set & FB_CUR_SETSHAPE) {
++              unsigned long dest = (unsigned long) par->cursorPad;
++              int i, j;
++
++              //memset_io(par->cursorPad, 0xff, 1);
++              //write_le32(NEOREG_CURSMEMPOS, ((0x000f & (dest >> 10)) << 8) |
++              //              ((0x0ff0 & (dest >> 10)) >> 4), par);
++      }
++
++      if (info->cursor.enable)
++              write_le32(NEOREG_CURSCNTL, NEO_CURS_ENABLE, par);
++      return 0;
++}
++
+ static struct fb_ops neofb_ops = {
+       .owner          = THIS_MODULE,
++      .fb_open        = neofb_open,
++      .fb_release     = neofb_release,
+       .fb_check_var   = neofb_check_var,
+       .fb_set_par     = neofb_set_par,
+       .fb_setcolreg   = neofb_setcolreg,
+@@ -1507,7 +1610,7 @@ static struct fb_ops neofb_ops = {
+       .fb_fillrect    = neofb_fillrect,
+       .fb_copyarea    = neofb_copyarea,
+       .fb_imageblit   = neofb_imageblit,
+-      .fb_cursor      = soft_cursor,
++      .fb_cursor      = neofb_cursor,
+ };
+ /* --------------------------------------------------------------------- */
+@@ -1650,6 +1753,7 @@ static int __devinit neo_map_video(struc
+                                  struct pci_dev *dev, int video_len)
+ {
+       struct neofb_par *par = (struct neofb_par *) info->par;
++      unsigned long addr;
+       DBG("neo_map_video");
+@@ -1681,6 +1785,10 @@ static int __devinit neo_map_video(struc
+       /* Clear framebuffer, it's all white in memory after boot */
+       memset(info->screen_base, 0, info->fix.smem_len);
++
++      /* Allocate Cursor drawing pad. */
++      addr = info->fix.smem_start + info->fix.smem_len;
++      par->cursorPad = (u8 *) ioremap(addr, info->sprite.size);
+       return 0;
+ }
+@@ -1725,16 +1833,16 @@ static int __devinit neo_init_hw(struct 
+       printk(KERN_DEBUG "--- Neo extended register dump ---\n");
+       for (w = 0; w < 0x85; w++)
+               printk(KERN_DEBUG "CR %p: %p\n", (void *) w,
+-                     (void *) VGArCR(w));
++                     (void *) vga_rcrt(NULL, w);
+       for (w = 0; w < 0xC7; w++)
+               printk(KERN_DEBUG "GR %p: %p\n", (void *) w,
+-                     (void *) VGArGR(w));
++                     (void *) vga_rgfx(NULL, w));
+ #endif
+       /* Determine the panel type */
+-      VGAwGR(0x09, 0x26);
+-      type = VGArGR(0x21);
+-      display = VGArGR(0x20);
++      vga_wgfx(NULL, 0x09, 0x26);
++      type = vga_rgfx(NULL, 0x21);
++      display = vga_rgfx(NULL, 0x20);
+       if (!par->internal_display && !par->external_display) {
+               par->internal_display = display & 2 || !(display & 3) ? 1 : 0;
+               par->external_display = display & 1;
+@@ -1744,8 +1852,8 @@ static int __devinit neo_init_hw(struct 
+       }
+       /* Determine panel width -- used in NeoValidMode. */
+-      w = VGArGR(0x20);
+-      VGAwGR(0x09, 0x00);
++      w = vga_rgfx(NULL, 0x20);
++      vga_wgfx(NULL, 0x09, 0x00);
+       switch ((w & 0x18) >> 3) {
+       case 0x00:
+               par->NeoPanelWidth = 640;
+@@ -1870,10 +1978,20 @@ static int __devinit neo_init_hw(struct 
+               par->neo2200 = (Neo2200 *) par->mmio_vbase;
+               break;
+       }
+-
++      info->sprite.size = CursorMem;
++      info->sprite.addr = kmalloc(CursorMem, GFP_KERNEL);
++      info->sprite.scan_align = 1;
++      info->sprite.buf_align = 1;
++      info->sprite.flags = FB_PIXMAP_IO;
+       par->maxClock = maxClock;
+-
+-      return videoRam * 1024;
++      par->cursorOff = CursorOff;
++      /*
++       * We decrease the size of the framebuffer by a page
++       * instead of the size of the cursor pad to avoid
++       * userland being able to page fault the cursor
++       * region and start drawing in it.
++       */
++      return ((videoRam * 1024) - PAGE_SIZE);
+ }
+--- linux-2.6.0-test6/drivers/video/platinumfb.c       2003-09-08 13:58:58.000000000 -0700
++++ 25/drivers/video/platinumfb.c      2003-10-05 00:34:22.000000000 -0700
+@@ -104,9 +104,6 @@ static int platinum_var_to_par(const str
+  * Interface used by the world
+  */
+-int platinum_init(void);
+-int platinum_setup(char*);
+-
+ static struct fb_ops platinumfb_ops = {
+       .owner =        THIS_MODULE,
+       .fb_check_var   = platinumfb_check_var,
+@@ -492,7 +489,7 @@ static int platinum_par_to_var(struct fb
+ /* 
+  * Parse user speficied options (`video=platinumfb:')
+  */
+-int __init platinum_setup(char *options)
++int __init platinumfb_setup(char *options)
+ {
+       char *this_opt;
+@@ -672,7 +669,7 @@ static struct of_platform_driver platinu
+       .remove         = platinumfb_remove,
+ };
+-int __init platinum_init(void)
++int __init platinumfb_init(void)
+ {
+       of_register_driver(&platinum_driver);
+--- linux-2.6.0-test6/drivers/video/pm3fb.c    2003-06-14 12:18:02.000000000 -0700
++++ 25/drivers/video/pm3fb.c   2003-10-05 00:33:24.000000000 -0700
+@@ -54,7 +54,6 @@
+ #include <linux/config.h>
+ #include <linux/module.h>
+-#include <linux/version.h>
+ #include <linux/kernel.h>
+ #include <linux/errno.h>
+ #include <linux/string.h>
+--- linux-2.6.0-test6/drivers/video/pvr2fb.c   2003-07-27 12:14:40.000000000 -0700
++++ 25/drivers/video/pvr2fb.c  2003-10-05 00:34:22.000000000 -0700
+@@ -166,6 +166,11 @@ static u_long videomemory = 0xa5000000, 
+ static int cable_type = -1;
+ static int video_output = -1;
++#ifdef CONFIG_MTRR
++static int enable_mtrr = 1;
++static int mtrr_handle;
++#endif
++
+ static int nopan = 0;
+ static int nowrap = 1;
+@@ -385,6 +390,7 @@ static int pvr2fb_set_par(struct fb_info
+ static int pvr2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+ {
++      struct pvr2fb_par *par = (struct pvr2fb_par *)info->par;
+       u_short vtotal, hsync_total;
+       u_long line_length;
+@@ -413,7 +419,7 @@ static int pvr2fb_check_var(struct fb_va
+       if (var->vmode & FB_VMODE_YWRAP) {
+               if (var->xoffset || var->yoffset < 0 || 
+-                  var->yoffset >= var->yres_virtual) {
++                  var->yoffset >= var->yres_virtual)
+                       var->xoffset = var->yoffset = 0;
+               } else {
+                       if (var->xoffset > var->xres_virtual - var->xres ||
+@@ -421,9 +427,8 @@ static int pvr2fb_check_var(struct fb_va
+                           var->xoffset < 0 || var->yoffset < 0)
+                               var->xoffset = var->yoffset = 0;
+               }
+-      } else {
++      } else
+               var->xoffset = var->yoffset = 0;
+-      }
+       /* 
+        * XXX: Need to be more creative with this (i.e. allow doublecan for
+@@ -456,7 +461,6 @@ static int pvr2fb_check_var(struct fb_va
+                               DPRINTK("invalid hsync total for NTSC\n");
+                               return -EINVAL;
+                       }
+-              }
+       }
+       /* Check memory sizes */
+       line_length = get_line_length(var->xres_virtual, var->bits_per_pixel);
+@@ -599,10 +603,10 @@ static int pvr2_init_cable(void)
+ int __init pvr2fb_init(void)
+ {
++      struct fb_var_screeninfo var;
+       u_long modememused;
+-      int err = -EINVAL;
+-      if (!mach_is_dreamcast())
++      if (!MACH_DREAMCAST)
+               return -ENXIO;
+       fb_info = kmalloc(sizeof(struct fb_info) + sizeof(struct pvr2fb_par) +
+@@ -650,8 +654,8 @@ int __init pvr2fb_init(void)
+       
+       if (!fb_info->screen_base) {
+               printk("Failed to remap MMIO space\n");
+-              err = -ENXIO;
+-              goto out_err;
++              kfree(fb_info);
++              return -ENXIO;
+       }
+       memset_io((unsigned long)fb_info->screen_base, 0, pvr2_fix.smem_len);
+@@ -665,6 +669,8 @@ int __init pvr2fb_init(void)
+       fb_info->pseudo_palette = (void *)(fb_info->par + 1);
+       fb_info->flags          = FBINFO_FLAG_DEFAULT;
++      memset(&var, 0, sizeof(var));
++
+       if (video_output == VO_VGA)
+               defmode = DEFMODE_VGA;
+@@ -677,41 +683,46 @@ int __init pvr2fb_init(void)
+       if (request_irq(HW_EVENT_VSYNC, pvr2fb_interrupt, 0,
+                       "pvr2 VBL handler", fb_info)) {
+-              err = -EBUSY;
+-              goto out_err;
++              DPRINTK("couldn't register VBL int\n");
++              kfree(fb_info);
++              return  -EBUSY;
+       }
+-      if (register_framebuffer(fb_info) < 0)
+-              goto reg_failed;
++#ifdef CONFIG_MTRR
++      if (enable_mtrr) {
++              mtrr_handle = mtrr_add(videomemory, videomemorysize, MTRR_TYPE_WRCOMB, 1);
++              printk("pvr2fb: MTRR turned on\n");
++      }
++#endif
+-      modememused = get_line_length(fb_info->var.xres_virtual,
+-                                    fb_info->var.bits_per_pixel);
+-      modememused *= fb_info->var.yres_virtual;
++      if (register_framebuffer(fb_info) < 0) {
++              kfree(fb_info);
++              return -EINVAL;
++      }
++      modememused = get_line_length(var.xres_virtual, var.bits_per_pixel);
++      modememused *= var.yres_virtual;
+       printk("fb%d: %s frame buffer device, using %ldk/%ldk of video memory\n",
+              fb_info->node, fb_info->fix.id, modememused>>10,
+              videomemorysize>>10);
+       printk("fb%d: Mode %dx%d-%d pitch = %ld cable: %s video output: %s\n", 
+-             fb_info->node, fb_info->var.xres, fb_info->var.yres,
+-             fb_info->var.bits_per_pixel, 
+-             get_line_length(fb_info->var.xres, fb_info->var.bits_per_pixel),
++             fb_info->node, var.xres, var.yres, var.bits_per_pixel,
++             get_line_length(var.xres, var.bits_per_pixel),
+              (char *)pvr2_get_param(cables, NULL, cable_type, 3),
+              (char *)pvr2_get_param(outputs, NULL, video_output, 3));
+       return 0;
+-
+-reg_failed:
+-      free_irq(HW_EVENT_VSYNC, 0);
+-out_err:
+-      kfree(fb_info);
+-
+-      return err;
+ }
+ static void __exit pvr2fb_exit(void)
+ {
++#ifdef CONFIG_MTRR
++      if (enable_mtrr) {
++              mtrr_del(mtrr_handle, videomemory, videomemorysize);
++              printk("pvr2fb: MTRR turned off\n");
++      }
++#endif
+       unregister_framebuffer(fb_info);
+-      free_irq(HW_EVENT_VSYNC, 0);
+       kfree(fb_info);
+ }
+@@ -767,6 +778,10 @@ int __init pvr2fb_setup(char *options)
+                       nopan = 1;
+               } else if (!strncmp(this_opt, "nowrap", 6)) {
+                       nowrap = 1;
++#ifdef CONFIG_MTRR
++              } else if (!strncmp(this_opt, "nomtrr", 6)) {
++                      enable_mtrr = 0;
++#endif
+               } else {
+                       mode_option = this_opt;
+               }
+--- linux-2.6.0-test6/drivers/video/radeonfb.c 2003-08-08 22:55:13.000000000 -0700
++++ 25/drivers/video/radeonfb.c        2003-10-05 00:34:47.000000000 -0700
+@@ -1099,7 +1099,7 @@ static int radeon_get_dfpinfo_BIOS(struc
+       printk("radeonfb: detected DFP panel size from BIOS: %dx%d\n",
+               rinfo->panel_xres, rinfo->panel_yres);
+-      for(i=0; i<20; i++) {
++      for(i=0; i<21; i++) {
+               tmp0 = rinfo->bios_seg + readw(tmp+64+i*2);
+               if (tmp0 == 0)
+                       break;
+@@ -2090,7 +2090,7 @@ static int radeonfb_set_par (struct fb_i
+       
+       }
+       /* Update fix */
+-        info->fix.line_length = rinfo->pitch*64;
++        info->fix.line_length = mode->xres_virtual*(mode->bits_per_pixel/8);
+         info->fix.visual = rinfo->depth == 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
+ #ifdef CONFIG_BOOTX_TEXT
+--- linux-2.6.0-test6/drivers/video/riva/fbdev.c       2003-09-27 18:57:46.000000000 -0700
++++ 25/drivers/video/riva/fbdev.c      2003-10-05 00:34:22.000000000 -0700
+@@ -143,7 +143,17 @@ enum riva_chips {
+       CH_GEFORCE4_TI_4200,
+       CH_QUADRO4_900XGL,
+       CH_QUADRO4_750XGL,
+-      CH_QUADRO4_700XGL
++      CH_QUADRO4_700XGL,
++      CH_GEFORCE4_TI_4800,
++      CH_GEFORCE4_TI_4280,
++      CH_GEFORCE4_TI_4800SE,
++      CH_GEFORCE4_4200_GO,
++      CH_GEFORCE_FX_5800_U,
++      CH_GEFORCE_FX_5800,
++      CH_GEFORCE_FX_5600_U,
++      CH_GEFORCE_FX_5600,
++      CH_GEFORCE_FX_5200_U,
++      CH_GEFORCE_FX_5200
+ };
+ /* directly indexed by riva_chips enum, above */
+@@ -190,7 +200,17 @@ static struct riva_chip_info {
+       { "GeForce4 Ti 4200", NV_ARCH_20 },
+       { "Quadro4-900-XGL", NV_ARCH_20 },
+       { "Quadro4-750-XGL", NV_ARCH_20 },
+-      { "Quadro4-700-XGL", NV_ARCH_20 }
++      { "Quadro4-700-XGL", NV_ARCH_20 },
++      { "GeForce4 Ti 4800", NV_ARCH_20 },
++      { "GeForce4 Ti 4280", NV_ARCH_20},
++      { "GeForce4 Ti 4800 SE", NV_ARCH_20},
++      { "GeForce4 4200 GO", NV_ARCH_20},
++      { "GeForce FX 5800 ULTRA", NV_ARCH_20},
++      { "GeForce FX 5800", NV_ARCH_20},
++      { "GeForce FX 5600 ULTRA", NV_ARCH_20},
++      { "GeForce FX 5600", NV_ARCH_20},
++      { "GeForce FX 5200 ULTRA", NV_ARCH_20},
++      { "GeForce FX 5200", NV_ARCH_20}
+ };
+ static struct pci_device_id rivafb_pci_tbl[] = {
+@@ -274,6 +294,26 @@ static struct pci_device_id rivafb_pci_t
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO4_750XGL },
+       { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO4_700XGL },
++      { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800,
++        PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_TI_4800 },
++      { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4280,
++        PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_TI_4280 },
++      { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800_SE,
++        PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_TI_4800SE },
++      { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_4200_GO,
++        PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_4200_GO },
++      { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5800_U,
++        PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE_FX_5800_U },
++      { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5800,
++        PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE_FX_5800 },
++      { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600_U,
++        PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE_FX_5600_U },
++      { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600,
++        PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE_FX_5600 },
++      { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200_U,
++        PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE_FX_5200_U },
++      { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200,
++        PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE_FX_5200 },
+       { 0, } /* terminate list */
+ };
+ MODULE_DEVICE_TABLE(pci, rivafb_pci_tbl);
+@@ -1469,8 +1509,6 @@ static void rivafb_imageblit(struct fb_i
+ static int rivafb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+ {
+       struct riva_par *par = (struct riva_par *) info->par;
+-      u8 data[MAX_CURS * MAX_CURS/8];
+-      u8 mask[MAX_CURS * MAX_CURS/8];
+       u16 fg, bg;
+       int i;
+@@ -1492,7 +1530,6 @@ static int rivafb_cursor(struct fb_info 
+       if (cursor->set & FB_CUR_SETSIZE) {
+               info->cursor.image.height = cursor->image.height;
+               info->cursor.image.width = cursor->image.width;
+-              memset_io(par->riva.CURSOR, 0, MAX_CURS * MAX_CURS * 2);
+       }
+       if (cursor->set & FB_CUR_SETCMAP) {
+@@ -1503,29 +1540,22 @@ static int rivafb_cursor(struct fb_info 
+       if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETCMAP)) {
+               u32 bg_idx = info->cursor.image.bg_color;
+               u32 fg_idx = info->cursor.image.fg_color;
+-              u32 s_pitch = (info->cursor.image.width+7) >> 3;
+-              u32 d_pitch = MAX_CURS/8;
+-              u8 *dat = (u8 *) cursor->image.data;
++              u8 *dat = (u8 *) info->cursor.image.data;
+               u8 *msk = (u8 *) info->cursor.mask;
+               u8 src[64];     
+               
+               switch (info->cursor.rop) {
+               case ROP_XOR:
+-                      for (i = 0; i < s_pitch * info->cursor.image.height; i++)
++                      for (i = 0; i < info->sprite.size; i++)
+                                       src[i] = dat[i] ^ msk[i];
+                       break;
+               case ROP_COPY:
+               default:
+-                      for (i = 0; i < s_pitch * info->cursor.image.height; i++)
+-                              
++                      for (i = 0; i < info->sprite.size; i++)
+                                       src[i] = dat[i] & msk[i];
+                       break;
+               }
+               
+-              move_buf_aligned(info, data, src, d_pitch, s_pitch, info->cursor.image.height);
+-
+-              move_buf_aligned(info, mask, msk, d_pitch, s_pitch, info->cursor.image.height);
+-
+               bg = ((info->cmap.red[bg_idx] & 0xf8) << 7) |
+                    ((info->cmap.green[bg_idx] & 0xf8) << 2) |
+                    ((info->cmap.blue[bg_idx] & 0xf8) >> 3);
+@@ -1536,7 +1566,7 @@ static int rivafb_cursor(struct fb_info 
+               par->riva.LockUnlock(&par->riva, 0);
+-              rivafb_load_cursor_image(par, data, mask, bg, fg,
++              rivafb_load_cursor_image(par, dat, msk, bg, fg,
+                                        info->cursor.image.width, 
+                                        info->cursor.image.height);
+       }
+@@ -1572,7 +1602,7 @@ static struct fb_ops riva_fb_ops = {
+       .fb_fillrect    = rivafb_fillrect,
+       .fb_copyarea    = rivafb_copyarea,
+       .fb_imageblit   = rivafb_imageblit,
+-      .fb_cursor      = rivafb_cursor,        
++      .fb_cursor      = soft_cursor,
+       .fb_sync        = rivafb_sync,
+ };
+@@ -1603,6 +1633,15 @@ static int __devinit riva_set_fbinfo(str
+       info->pixmap.buf_align = 4;
+       info->pixmap.scan_align = 4;
+       info->pixmap.flags = FB_PIXMAP_SYSTEM;
++/*
++      info->sprite.addr = (char *) par->riva.CURSOR;
++      info->sprite.size = MAX_CURS * MAX_CURS * 2;
++      info->sprite.buf_align = info->sprite.size;
++      info->sprite.scan_align = MAX_CURS >> 3;
++      info->sprite.access_align = 2;
++      info->sprite.flags = FB_PIXMAP_IO;
++      memset_io(par->riva.CURSOR, 0, MAX_CURS * MAX_CURS * 2);
++*/
+       return 0;
+ }
+--- linux-2.6.0-test6/drivers/video/riva/nv_type.h     2003-06-14 12:18:08.000000000 -0700
++++ 25/drivers/video/riva/nv_type.h    2003-10-05 00:34:22.000000000 -0700
+@@ -50,8 +50,16 @@
+ #define NV_CHIP_QUADRO4_900XGL      ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL)
+ #define NV_CHIP_QUADRO4_750XGL      ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL)
+ #define NV_CHIP_QUADRO4_700XGL      ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL)
+-#define NV_CHIP_0x0280              ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0280)
+-#define NV_CHIP_0x0281              ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0281)
++#define NV_CHIP_GEFORCE4_TI_4800    ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800)
++#define NV_CHIP_GEFORCE4_TI_4280    ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4280)
++#define NV_CHIP_GEFORCE4_TI_4800SE  ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800_SE)
++#define NV_CHIP_GEFORCE4_4200_GO    ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_4200_GO)
++#define NV_CHIP_GEFORCE_FX_5800_U   ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5800_U)
++#define NV_CHIP_GEFORCE_FX_5800     ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5800)
++#define NV_CHIP_GEFORCE_FX_5600_U   ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600_U)
++#define NV_CHIP_GEFORCE_FX_5600     ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600)
++#define NV_CHIP_GEFORCE_FX_5200_U   ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200_U)
++#define NV_CHIP_GEFORCE_FX_5200     ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200)
+ #define NV_CHIP_0x0288              ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0288)
+ #define NV_CHIP_0x0289              ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0289)
+--- linux-2.6.0-test6/drivers/video/sis/300vtbl.h      2003-06-14 12:17:59.000000000 -0700
++++ 25/drivers/video/sis/300vtbl.h     2003-10-05 00:34:22.000000000 -0700
+@@ -1,7 +1,37 @@
+-
+-
+-/* Register settings for SiS 300 series */
+-
++/* $XFree86$ */
++/*
++ * Register settings for SiS 300 series
++ *
++ * Copyright 2002, 2003 by Thomas Winischhofer, Vienna, Austria
++ *
++ * If distributed as part of the linux kernel, the contents of this file
++ * is entirely covered by the GPL.
++ *
++ * Otherwise, the following terms apply:
++ *
++ * Permission to use, copy, modify, distribute, and sell this software and its
++ * documentation for any purpose is hereby granted without fee, provided that
++ * the above copyright notice appear in all copies and that both that
++ * copyright notice and this permission notice appear in supporting
++ * documentation, and that the name of the copyright holder not be used in
++ * advertising or publicity pertaining to distribution of the software without
++ * specific, written prior permission.  The copyright holder makes no representations
++ * about the suitability of this software for any purpose.  It is provided
++ * "as is" without express or implied warranty.
++ *
++ * THE COPYRIGHT HOLDER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
++ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
++ * EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR
++ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
++ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
++ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ *
++ * Author:    Thomas Winischhofer <thomas@winischhofer.net>
++ *
++ * Based on code by Silicon Intergrated Systems
++ *
++ */
+ typedef struct _SiS300_StStruct
+ {
+@@ -39,470 +69,109 @@ static const SiS300_StStruct  SiS300_SMo
+       {0xff,     0,   0,   0,   0,   0,   0,   0}
+ };
+-typedef struct _SiS300_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];
+-} SiS300_StandTableStruct;
+-
+-static const SiS300_StandTableStruct  SiS300_StandTable[] =
+-{
+- {0x28,0x18,0x08,0x0800,                      /* 0x00 */
+-  {0x09,0x03,0x00,0x02},
+-  0x63,
+-  {0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f,
+-   0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00,
+-   0x9c,0x8e,0x8f,0x14,0x1f,0x96,0xb9,0xa3,
+-   0xff},
+-  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+-   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+-   0x08,0x00,0x0f,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+-   0xff} },
+- {0x28,0x18,0x08,0x0800,                      /* 0x01 */
+-  {0x09,0x03,0x00,0x02},
+-  0x63,
+-  {0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f,
+-   0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00,
+-   0x9c,0x8e,0x8f,0x14,0x1f,0x96,0xb9,0xa3,
+-   0xff},
+-  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+-   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+-   0x08,0x00,0x0f,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+-   0xff} },
+- {0x50,0x18,0x08,0x1000,                      /* 0x02 */
+-  {0x01,0x03,0x00,0x02},
+-  0x63,
+-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+-   0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00,
+-   0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,
+-   0xff},
+-  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+-   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+-   0x08,0x00,0x0f,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+-   0xff} },
+- {0x50,0x18,0x08,0x1000,                      /* 0x03 */
+-  {0x01,0x03,0x00,0x02},
+-  0x63,
+-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+-   0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00,
+-   0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,
+-   0xff},
+-  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+-   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+-   0x08,0x00,0x0f,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+-   0xff} },
+- {0x28,0x18,0x08,0x4000,                      /* 0x04 */
+-  {0x09,0x03,0x00,0x02},
+-  0x63,
+-  {0x2d,0x27,0x28,0x90,0x2b,0x80,0xbf,0x1f,
+-   0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,
+-   0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xa2,
+-   0xff},
+-  {0x00,0x13,0x15,0x17,0x02,0x04,0x06,0x07,
+-   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+-   0x01,0x00,0x03,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x30,0x0f,0x00,
+-   0xff} },
+- {0x28,0x18,0x08,0x4000,                      /* 0x05 */
+-  {0x09,0x03,0x00,0x02},
+-  0x63,
+-  {0x2d,0x27,0x28,0x90,0x2b,0x80,0xbf,0x1f,
+-   0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,
+-   0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xa2,
+-   0xff},
+-  {0x00,0x13,0x15,0x17,0x02,0x04,0x06,0x07,
+-   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+-   0x01,0x00,0x03,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x30,0x0f,0x00,
+-   0xff} },
+- {0x50,0x18,0x08,0x4000,                      /* 0x06 */
+-  {0x01,0x01,0x00,0x06},
+-  0x63,
+-  {0x5f,0x4f,0x50,0x82,0x54,0x80,0xbf,0x1f,
+-   0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,
+-   0x9c,0x8e,0x8f,0x28,0x00,0x96,0xb9,0xc2,
+-   0xff},
+-  {0x00,0x17,0x17,0x17,0x17,0x17,0x17,0x17,
+-   0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,
+-   0x01,0x00,0x01,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x00,
+-   0xff} },
+- {0x50,0x18,0x0e,0x1000,                      /* 0x07 */
+-  {0x00,0x03,0x00,0x03},
+-  0xa6,
+-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+-   0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
+-   0x83,0x85,0x5d,0x28,0x0d,0x63,0xba,0xa3,
+-   0xff},
+-  {0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
+-   0x10,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+-   0x0e,0x00,0x0f,0x08},
+-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0a,0x00,
+-   0xff} },
+-/* MDA_DAC*/
+- {0x00,0x00,0x00,0x0000,                      /* 0x08 */
+-  {0x00,0x00,0x00,0x15},
+-  0x15,
+-  {0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+-   0x15,0x15,0x15,0x15,0x15,0x15,0x3f,0x3f,
+-   0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x00,0x00,
+-   0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x15,0x15,0x15,
+-   0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+-   0x15,0x15,0x15,0x15},
+-  {0x15,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,
+-   0x3f} },
+-/* CGA_DAC*/
+- {0x00,0x10,0x04,0x0114,                      /* 0x09 */
+-  {0x11,0x09,0x15,0x00},
+-  0x10,
+-  {0x04,0x14,0x01,0x11,0x09,0x15,0x2a,0x3a,
+-   0x2e,0x3e,0x2b,0x3b,0x2f,0x3f,0x2a,0x3a,
+-   0x2e,0x3e,0x2b,0x3b,0x2f,0x3f,0x00,0x10,
+-   0x04},
+-  {0x14,0x01,0x11,0x09,0x15,0x00,0x10,0x04,
+-   0x14,0x01,0x11,0x09,0x15,0x2a,0x3a,0x2e,
+-   0x3e,0x2b,0x3b,0x2f},
+-  {0x3f,0x2a,0x3a,0x2e,0x3e,0x2b,0x3b,0x2f,
+-   0x3f} },
+-/* EGA_DAC*/
+- {0x00,0x10,0x04,0x0114,                      /* 0x0a */
+-  {0x11,0x05,0x15,0x20},
+-  0x30,
+-  {0x24,0x34,0x21,0x31,0x25,0x35,0x08,0x18,
+-   0x0c,0x1c,0x09,0x19,0x0d,0x1d,0x28,0x38,
+-   0x2c,0x3c,0x29,0x39,0x2d,0x3d,0x02,0x12,
+-   0x06},
+-  {0x16,0x03,0x13,0x07,0x17,0x22,0x32,0x26,
+-   0x36,0x23,0x33,0x27,0x37,0x0a,0x1a,0x0e,
+-   0x1e,0x0b,0x1b,0x0f},
+-  {0x1f,0x2a,0x3a,0x2e,0x3e,0x2b,0x3b,0x2f,
+-   0x3f} },
+-/* VGA_DAC*/
+- {0x00,0x10,0x04,0x0114,                      /* 0x0b */
+-  {0x11,0x09,0x15,0x2a},
+-  0x3a,
+-  {0x2e,0x3e,0x2b,0x3b,0x2f,0x3f,0x00,0x05,
+-   0x08,0x0b,0x0e,0x11,0x14,0x18,0x1c,0x20,
+-   0x24,0x28,0x2d,0x32,0x38,0x3f,0x00,0x10,
+-   0x1f},
+-  {0x2f,0x3f,0x1f,0x27,0x2f,0x37,0x3f,0x2d,
+-   0x31,0x36,0x3a,0x3f,0x00,0x07,0x0e,0x15,
+-   0x1c,0x0e,0x11,0x15},
+-  {0x18,0x1c,0x14,0x16,0x18,0x1a,0x1c,0x00,
+-   0x04} },
+- {0x08,0x0c,0x10,0x0a08,                      /* 0x0c */
+-  {0x0c,0x0e,0x10,0x0b},
+-  0x0c,
+-  {0x0d,0x0f,0x10,0x10,0x01,0x08,0x00,0x00,
+-   0x00,0x00,0x01,0x00,0x02,0x02,0x01,0x00,
+-   0x04,0x04,0x01,0x00,0x05,0x02,0x05,0x00,
+-   0x06},
+-  {0x01,0x06,0x05,0x06,0x00,0x08,0x01,0x08,
+-   0x00,0x07,0x02,0x07,0x06,0x07,0x00,0x00,
+-   0x00,0x00,0x00,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+-   0x00} },
+- {0x28,0x18,0x08,0x2000,                      /* 0x0d */
+-  {0x09,0x0f,0x00,0x06},
+-  0x63,
+-  {0x2d,0x27,0x28,0x90,0x2b,0x80,0xbf,0x1f,
+-   0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
+-   0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xe3,
+-   0xff},
+-  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+-   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+-   0x01,0x00,0x0f,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
+-   0xff} },
+- {0x50,0x18,0x08,0x4000,                      /* 0x0e */
+-  {0x01,0x0f,0x00,0x06},
+-  0x63,
+-  {0x5f,0x4f,0x50,0x82,0x54,0x80,0xbf,0x1f,
+-   0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
+-   0x9c,0x8e,0x8f,0x28,0x00,0x96,0xb9,0xe3,
+-   0xff},
+-  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+-   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+-   0x01,0x00,0x0f,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
+-   0xff} },
+- {0x00,0x00,0x00,0x0000,                      /* 0x0f */      /* TW: Standtable for VGA modes */
+-  {0x01,0x0f,0x00,0x0e},
+-  0x23,
+-  {0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
+-   0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
+-   0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
+-   0xff},
+-  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+-   0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
+-   0x01,0x00,0x00,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
+-   0xff} },
+- {0x4a,0x36,0x00,0x00c0,                      /* 0x10 */
+-  {0x00,0x00,0x00,0x00},
+-  0x00,
+-  {0x00,0x00,0x00,0x00,0x00,0x00,0x66,0x3a,
+-   0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
+-   0x00,0x00,0x1a,0x00,0x57,0x39,0x00,0xc0,
+-   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} },
+- {0x50,0x18,0x0e,0x8000,                      /* 0x11 */
+-  {0x01,0x0f,0x00,0x06},
+-  0xa2,
+-  {0x5f,0x4f,0x50,0x82,0x54,0x80,0xbf,0x1f,
+-   0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
+-   0x83,0x85,0x5d,0x28,0x0f,0x63,0xba,0xe3,
+-   0xff},
+-  {0x00,0x08,0x00,0x00,0x18,0x18,0x00,0x00,
+-   0x00,0x08,0x00,0x00,0x00,0x18,0x00,0x00,
+-   0x0b,0x00,0x05,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x05,
+-   0xff} },
+- {0x50,0x18,0x0e,0x8000,                      /* 0x12 */
+-  {0x01,0x0f,0x00,0x06},
+-  0xa3,
+-  {0x5f,0x4f,0x50,0x82,0x54,0x80,0xbf,0x1f,
+-   0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
+-   0x83,0x85,0x5d,0x28,0x0f,0x63,0xba,0xe3,
+-   0xff},
+-  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+-   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+-   0x01,0x00,0x0f,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
+-   0xff} },
+- {0x28,0x18,0x0e,0x0800,                      /* 0x13 */
+-  {0x09,0x03,0x00,0x02},
+-  0xa3,
+-  {0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f,
+-   0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
+-   0x83,0x85,0x5d,0x14,0x1f,0x63,0xba,0xa3,
+-   0xff},
+-  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+-   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+-   0x08,0x00,0x0f,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+-   0xff} },
+- {0x28,0x18,0x0e,0x0800,                      /* 0x14 */
+-  {0x09,0x03,0x00,0x02},
+-  0xa3,
+-  {0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f,
+-   0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
+-   0x83,0x85,0x5d,0x14,0x1f,0x63,0xba,0xa3,
+-   0xff},
+-  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+-   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+-   0x08,0x00,0x0f,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+-   0xff} },
+- {0x50,0x18,0x0e,0x1000,                      /* 0x15 */
+-  {0x01,0x03,0x00,0x02},
+-  0xa3,
+-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+-   0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
+-   0x83,0x85,0x5d,0x28,0x1f,0x63,0xba,0xa3,
+-   0xff},
+-  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+-   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+-   0x08,0x00,0x0f,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+-   0xff} },
+- {0x50,0x18,0x0e,0x1000,                      /* 0x16 */
+-  {0x01,0x03,0x00,0x02},
+-  0xa3,
+-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+-   0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
+-   0x83,0x85,0x5d,0x28,0x1f,0x63,0xba,0xa3,
+-   0xff},
+-  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+-   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+-   0x08,0x00,0x0f,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+-   0xff} },
+- {0x28,0x18,0x10,0x0800,                      /* 0x17 */
+-  {0x08,0x03,0x00,0x02},
+-  0x67,
+-  {0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f,
+-   0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,
+-   0x9c,0x8e,0x8f,0x14,0x1f,0x96,0xb9,0xa3,
+-   0xff},
+-  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+-   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+-   0x0c,0x00,0x0f,0x08},
+-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+-   0xff} },
+- {0x50,0x18,0x10,0x1000,                      /* 0x18 */
+-  {0x00,0x03,0x00,0x02},
+-  0x67,
+-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+-   0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,
+-   0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,
+-   0xff},
+-  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+-   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+-   0x0c,0x00,0x0f,0x08},
+-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+-   0xff} },
+- {0x50,0x18,0x10,0x1000,                      /* 0x19 */
+-  {0x00,0x03,0x00,0x02},
+-  0x66,
+-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+-   0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,
+-   0x9c,0x8e,0x8f,0x28,0x0f,0x96,0xb9,0xa3,
+-   0xff},
+-  {0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
+-   0x10,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+-   0x0e,0x00,0x0f,0x08},
+-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0a,0x00,
+-   0xff} },
+- {0x50,0x1d,0x10,0xa000,                      /* 0x1a */
+-  {0x01,0x0f,0x00,0x06},
+-  0xe3,
+-  {0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
+-   0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
+-   0xea,0x8c,0xdf,0x28,0x00,0xe7,0x04,0xc3,
+-   0xff},
+-  {0x00,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,
+-   0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,
+-   0x01,0x00,0x0f,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x01,
+-   0xff} },
+- {0x50,0x1d,0x10,0xa000,                      /* 0x1b */
+-  {0x01,0x0f,0x00,0x06},
+-  0xe3,
+-  {0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
+-   0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
+-   0xea,0x8c,0xdf,0x28,0x00,0xe7,0x04,0xe3,
+-   0xff},
+-  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+-   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+-   0x01,0x00,0x0f,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
+-   0xff} },
+- {0x28,0x18,0x08,0x2000,                      /* 0x1c */
+-  {0x01,0x0f,0x00,0x0e},
+-  0x63,
+-  {0x5f,0x4f,0x50,0x82,0x54,0x80,0xbf,0x1f,
+-   0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,
+-   0x9c,0x8e,0x8f,0x28,0x40,0x96,0xb9,0xa3,
+-   0xff},
+-  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+-   0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
+-   0x41,0x00,0x0f,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
+-   0xff} }
+-};
+-
+ typedef struct _SiS300_ExtStruct
+ {
+-      UCHAR Ext_ModeID;
++      UCHAR  Ext_ModeID;
+       USHORT Ext_ModeFlag;
+       USHORT Ext_ModeInfo;
+-      USHORT Ext_Point;
+       USHORT Ext_VESAID;
+-      UCHAR Ext_VESAMEMSize;
+-      UCHAR Ext_RESINFO;
+-      UCHAR VB_ExtTVFlickerIndex;
+-      UCHAR VB_ExtTVEdgeIndex;
+-      UCHAR VB_ExtTVYFilterIndex;
+-      UCHAR REFindex;
++      UCHAR  Ext_RESINFO;
++      UCHAR  VB_ExtTVFlickerIndex;
++      UCHAR  VB_ExtTVEdgeIndex;
++      UCHAR  VB_ExtTVYFilterIndex;
++      UCHAR  REFindex;
+ } SiS300_ExtStruct;
+ static const SiS300_ExtStruct  SiS300_EModeIDTable[] =
+ {
+-      {0x6a,0x2212,0x47,0x3563,0x0102,0x08,0x07,0x00,0x00,0x00,0x00},  /* 800x600x? */
+-      {0x2e,0x0a1b,0x36,0x3539,0x0101,0x08,0x06,0x00,0x00,0x00,0x08},
+-      {0x2f,0x021b,0x35,0x3532,0x0100,0x08,0x05,0x00,0x00,0x00,0x10},  /* 640x400x8 */
+-      {0x30,0x2a1b,0x47,0x3563,0x0103,0x08,0x07,0x00,0x00,0x00,0x00},
+-      {0x31,0x0a1b,0xad,0x3630,0x0000,0x08,0x0c,0x00,0x00,0x00,0x11},  /* 720x480x8 */
+-      {0x32,0x2a1b,0xae,0x3637,0x0000,0x08,0x0d,0x00,0x00,0x00,0x12},  /* 720x576x8 */
+-      {0x33,0x0a1d,0xad,0x3630,0x0000,0x08,0x0c,0x00,0x00,0x00,0x11},  /* 720x480x16 */
+-      {0x34,0x2a1d,0xae,0x3637,0x0000,0x08,0x0d,0x00,0x00,0x00,0x12},  /* 720x576x16 */
+-      {0x35,0x0a1f,0xad,0x3630,0x0000,0x08,0x0c,0x00,0x00,0x00,0x11},  /* 720x480x32 */
+-      {0x36,0x2a1f,0xae,0x3637,0x0000,0x08,0x0d,0x00,0x00,0x00,0x12},  /* 720x576x32 */
+-      {0x37,0x0212,0x58,0x358d,0x0104,0x08,0x08,0x00,0x00,0x00,0x13},  /* 1024x768x? */
+-      {0x38,0x0a1b,0x58,0x358d,0x0105,0x08,0x08,0x00,0x00,0x00,0x13},  /* 1024x768x8 */
+-      {0x3a,0x0e3b,0x69,0x35be,0x0107,0x08,0x09,0x00,0x00,0x00,0x1a},  /* 1280x1024x8 */
+-      {0x3c,0x063b,0x7a,0x35d4,0x0130,0x08,0x0a,0x00,0x00,0x00,0x1e},
+-      {0x3d,0x067d,0x7a,0x35d4,0x0131,0x08,0x0a,0x00,0x00,0x00,0x1e},
+-      {0x40,0x921c,0x00,0x3516,0x010d,0x08,0x00,0x00,0x00,0x00,0x23},
+-      {0x41,0x921d,0x00,0x3516,0x010e,0x08,0x00,0x00,0x00,0x00,0x23},
+-      {0x43,0x0a1c,0x36,0x3539,0x0110,0x08,0x06,0x00,0x00,0x00,0x08},
+-      {0x44,0x0a1d,0x36,0x3539,0x0111,0x08,0x06,0x00,0x00,0x00,0x08},
+-      {0x46,0x2a1c,0x47,0x3563,0x0113,0x08,0x07,0x00,0x00,0x00,0x00},  /* 800x600 */
+-      {0x47,0x2a1d,0x47,0x3563,0x0114,0x08,0x07,0x00,0x00,0x00,0x00},  /* 800x600 */
+-      {0x49,0x0a3c,0x58,0x358d,0x0116,0x08,0x08,0x00,0x00,0x00,0x13},
+-      {0x4a,0x0a3d,0x58,0x358d,0x0117,0x08,0x08,0x00,0x00,0x00,0x13},
+-      {0x4c,0x0e7c,0x69,0x35be,0x0119,0x08,0x09,0x00,0x00,0x00,0x1a},
+-      {0x4d,0x0e7d,0x69,0x35be,0x011a,0x08,0x09,0x00,0x00,0x00,0x1a},
+-      {0x50,0x921b,0x01,0x351d,0x0132,0x08,0x01,0x00,0x00,0x00,0x24},
+-      {0x51,0xb21b,0x13,0x3524,0x0133,0x08,0x03,0x00,0x00,0x00,0x25},  /* 400x300 */
+-      {0x52,0x921b,0x24,0x352b,0x0134,0x08,0x04,0x00,0x00,0x00,0x26},
+-      {0x56,0x921d,0x01,0x351d,0x0135,0x08,0x01,0x00,0x00,0x00,0x24},
+-      {0x57,0xb21d,0x13,0x3524,0x0136,0x08,0x03,0x00,0x00,0x00,0x25},  /* 400x300 */
+-      {0x58,0x921d,0x24,0x352b,0x0137,0x08,0x04,0x00,0x00,0x00,0x26},  
+-      {0x59,0x921b,0x00,0x3516,0x0138,0x08,0x00,0x00,0x00,0x00,0x23}, 
+-      {0x5c,0x921f,0x24,0x352b,0x0000,0x08,0x04,0x00,0x00,0x00,0x26},  /* TW: inserted 512x384x32 */
+-      {0x5d,0x021d,0x35,0x3532,0x0139,0x08,0x05,0x00,0x00,0x00,0x10},  /* 640x400x16 */
+-      {0x5e,0x021f,0x35,0x3532,0x0000,0x08,0x05,0x00,0x00,0x00,0x10},  /* TW: inserted 640x400x32 */
+-      {0x62,0x0a3f,0x36,0x3539,0x013a,0x08,0x06,0x00,0x00,0x00,0x08},
+-      {0x63,0x2a3f,0x47,0x3563,0x013b,0x08,0x07,0x00,0x00,0x00,0x00},  /* 800x600 */
+-      {0x64,0x0a7f,0x58,0x358d,0x013c,0x08,0x08,0x00,0x00,0x00,0x13},
+-      {0x65,0x0eff,0x69,0x35be,0x013d,0x08,0x09,0x00,0x00,0x00,0x1a},
+-      {0x66,0x06ff,0x7a,0x35d4,0x013e,0x08,0x0a,0x00,0x00,0x00,0x1e},
+-      {0x68,0x067b,0x8b,0x35ef,0x013f,0x08,0x0b,0x00,0x00,0x00,0x27},
+-      {0x69,0x06fd,0x8b,0x35ef,0x0140,0x08,0x0b,0x00,0x00,0x00,0x27},
+-      {0x6b,0x07ff,0x8b,0x35ef,0x0000,0x10,0x0b,0x00,0x00,0x00,0x27},
+-      {0x6c,0x067b,0x9c,0x35f6,0x0000,0x08,0x11,0x00,0x00,0x00,0x28},  /* TW: 2048x1536x8 - not in BIOS! */
+-      {0x6d,0x06fd,0x9c,0x35f6,0x0000,0x10,0x11,0x00,0x00,0x00,0x28},  /* TW: 2048x1536x16 - not in BIOS! */
+-      {0x6e,0x0a3b,0x6f,0x35b2,0x0000,0x08,0x0e,0x00,0x00,0x00,0x29},  /* 1280x960x8 */
+-      {0x6f,0x0a7d,0x6f,0x35b2,0x0000,0x08,0x0e,0x00,0x00,0x00,0x29},  /* 1280x960x16 */
+-      /* TW: 16:9 modes copied from 310/325 series - not in ANY BIOS */
+-      {0x70,0x2a1b,0x40,0x3b52,0x0000,0x08,0x12,0x00,0x00,0x07,0x2d},    /* 800x480x8 */
+-      {0x71,0x0a1b,0x51,0x3b63,0x0000,0x08,0x13,0x00,0x00,0x00,0x30},    /* 1024x576x8 */
+-      {0x74,0x0a1d,0x51,0x3b63,0x0000,0x08,0x13,0x00,0x00,0x00,0x30},    /* 1024x576x16 */
+-      {0x75,0x0e3d,0x62,0x3b74,0x0000,0x08,0x14,0x00,0x00,0x00,0x33},    /* 1280x720x16 */
+-      {0x76,0x2a1f,0x40,0x3b52,0x0000,0x08,0x12,0x00,0x00,0x07,0x2d},    /* 800x480x32 */
+-      {0x77,0x0a3f,0x51,0x3b63,0x0000,0x08,0x13,0x00,0x00,0x00,0x30},    /* 1024x576x32 */
+-      {0x78,0x0eff,0x62,0x3b74,0x0000,0x08,0x14,0x00,0x00,0x00,0x33},    /* 1280x720x32 */
+-      {0x79,0x0e3b,0x62,0x3b74,0x0000,0x08,0x14,0x00,0x00,0x00,0x33},    /* 1280x720x8 */
+-      {0x7a,0x2a1d,0x40,0x3b52,0x0000,0x08,0x12,0x00,0x00,0x07,0x2d},    /* 800x480x16 */
+-      /* TW: End of new 16:9 modes */
+-      {0x7b,0x0aff,0x6f,0x35b2,0x0000,0x08,0x0e,0x00,0x00,0x00,0x29},    /* 1280x960x32 */
+-      {0x20,0x0a1b,0x54,0x0000,0x0000,0x08,0x0f,0x00,0x00,0x00,0x2b},    /* 1024x600 */
+-      {0x21,0x0a3d,0x54,0x0000,0x0000,0x08,0x0f,0x00,0x00,0x00,0x2b},
+-      {0x22,0x0a7f,0x54,0x0000,0x0000,0x08,0x0f,0x00,0x00,0x00,0x2b},
+-      {0x23,0x0a1b,0xc5,0x0000,0x0000,0x08,0x10,0x00,0x00,0x00,0x2c},    /* 1152x768 */
+-      {0x24,0x0a3d,0xc5,0x431d,0x0000,0x08,0x10,0x00,0x00,0x00,0x2c},
+-      {0x25,0x0a7f,0xc5,0x431d,0x0000,0x08,0x10,0x00,0x00,0x00,0x2c},
+-      {0x29,0x0e1b,0xc5,0x0000,0x0000,0x08,0x15,0x00,0x00,0x00,0x36},    /* TW: NEW 1152x864 - not in BIOS */
+-      {0x2a,0x0e3d,0xc5,0x0000,0x0000,0x08,0x15,0x00,0x00,0x00,0x36},
+-      {0x2b,0x0e7f,0xc5,0x0000,0x0000,0x08,0x15,0x00,0x00,0x00,0x36},
+-      {0x39,0x2a1b,0xd6,0x0000,0x0000,0x08,0x16,0x00,0x00,0x00,0x38},    /* TW: NEW 848x480 - not in BIOS */
+-      {0x3b,0x2a3d,0xd6,0x0000,0x0000,0x08,0x16,0x00,0x00,0x00,0x38},
+-      {0x3e,0x2a7f,0xd6,0x0000,0x0000,0x08,0x16,0x00,0x00,0x00,0x38},
+-      {0x3f,0x2a1b,0xd7,0x0000,0x0000,0x08,0x17,0x00,0x00,0x00,0x3a},    /* TW: NEW 856x480 - not in BIOS */
+-      {0x42,0x2a3d,0xd7,0x0000,0x0000,0x08,0x17,0x00,0x00,0x00,0x3a},
+-      {0x45,0x2a7f,0xd7,0x0000,0x0000,0x08,0x17,0x00,0x00,0x00,0x3a},
+-      {0x48,0x223b,0xe8,0x0000,0x0000,0x08,0x18,0x00,0x00,0x00,0x3c},    /* TW: NEW 1360x768 - not in BIOS */
+-      {0x4b,0x227d,0xe8,0x0000,0x0000,0x08,0x18,0x00,0x00,0x00,0x3c},
+-      {0x4e,0x22ff,0xe8,0x0000,0x0000,0x08,0x18,0x00,0x00,0x00,0x3c},
+-      {0xff,0x0000,0x00,0x0000,0xffff,0x00,0x00,0x00,0x00,0x00,0x00}
++      {0x6a,0x2212,0x0407,0x0102,SIS_RI_800x600,  0x00,0x00,0x00,0x00},  /* 800x600x? */
++      {0x2e,0x0a1b,0x0306,0x0101,SIS_RI_640x480,  0x00,0x00,0x00,0x08},
++      {0x2f,0x021b,0x0305,0x0100,SIS_RI_640x400,  0x00,0x00,0x00,0x10},  /* 640x400x8 */
++      {0x30,0x2a1b,0x0407,0x0103,SIS_RI_800x600,  0x00,0x00,0x00,0x00},
++      {0x31,0x0a1b,0x0a0d,0x0000,SIS_RI_720x480,  0x00,0x00,0x00,0x11},  /* 720x480x8 */
++      {0x32,0x2a1b,0x0a0e,0x0000,SIS_RI_720x576,  0x00,0x00,0x00,0x12},  /* 720x576x8 */
++      {0x33,0x0a1d,0x0a0d,0x0000,SIS_RI_720x480,  0x00,0x00,0x00,0x11},  /* 720x480x16 */
++      {0x34,0x2a1d,0x0a0e,0x0000,SIS_RI_720x576,  0x00,0x00,0x00,0x12},  /* 720x576x16 */
++      {0x35,0x0a1f,0x0a0d,0x0000,SIS_RI_720x480,  0x00,0x00,0x00,0x11},  /* 720x480x32 */
++      {0x36,0x2a1f,0x0a0e,0x0000,SIS_RI_720x576,  0x00,0x00,0x00,0x12},  /* 720x576x32 */
++      {0x37,0x0212,0x0508,0x0104,SIS_RI_1024x768, 0x00,0x00,0x00,0x13},  /* 1024x768x? */
++      {0x38,0x0a1b,0x0508,0x0105,SIS_RI_1024x768, 0x00,0x00,0x00,0x13},  /* 1024x768x8 */
++      {0x3a,0x0e3b,0x0609,0x0107,SIS_RI_1280x1024,0x00,0x00,0x00,0x1a},  /* 1280x1024x8 */
++      {0x3c,0x063b,0x070a,0x0130,SIS_RI_1600x1200,0x00,0x00,0x00,0x1e},
++      {0x3d,0x067d,0x070a,0x0131,SIS_RI_1600x1200,0x00,0x00,0x00,0x1e},
++      {0x40,0x921c,0x0000,0x010d,SIS_RI_320x200,  0x00,0x00,0x00,0x23},  /* 320x200x15 */
++      {0x41,0x921d,0x0000,0x010e,SIS_RI_320x200,  0x00,0x00,0x00,0x23},  /* 320x200x16 */
++      {0x43,0x0a1c,0x0306,0x0110,SIS_RI_640x480,  0x00,0x00,0x00,0x08},
++      {0x44,0x0a1d,0x0306,0x0111,SIS_RI_640x480,  0x00,0x00,0x00,0x08},
++      {0x46,0x2a1c,0x0407,0x0113,SIS_RI_800x600,  0x00,0x00,0x00,0x00},  /* 800x600x15 */
++      {0x47,0x2a1d,0x0407,0x0114,SIS_RI_800x600,  0x00,0x00,0x00,0x00},  /* 800x600x16 */
++      {0x49,0x0a3c,0x0508,0x0116,SIS_RI_1024x768, 0x00,0x00,0x00,0x13},
++      {0x4a,0x0a3d,0x0508,0x0117,SIS_RI_1024x768, 0x00,0x00,0x00,0x13},
++      {0x4c,0x0e7c,0x0609,0x0119,SIS_RI_1280x1024,0x00,0x00,0x00,0x1a},
++      {0x4d,0x0e7d,0x0609,0x011a,SIS_RI_1280x1024,0x00,0x00,0x00,0x1a},
++      {0x50,0x921b,0x0001,0x0132,SIS_RI_320x240,  0x00,0x00,0x00,0x24},  /* 320x240x8  */
++      {0x51,0xb21b,0x0103,0x0133,SIS_RI_400x300,  0x00,0x00,0x00,0x25},  /* 400x300x8  */
++      {0x52,0x921b,0x0204,0x0134,SIS_RI_512x384,  0x00,0x00,0x00,0x26},  /* 512x384x8  */
++      {0x56,0x921d,0x0001,0x0135,SIS_RI_320x240,  0x00,0x00,0x00,0x24},  /* 320x240x16 */
++      {0x57,0xb21d,0x0103,0x0136,SIS_RI_400x300,  0x00,0x00,0x00,0x25},  /* 400x300x16 */
++      {0x58,0x921d,0x0204,0x0137,SIS_RI_512x384,  0x00,0x00,0x00,0x26},  /* 512x384x16 */
++      {0x59,0x921b,0x0000,0x0138,SIS_RI_320x200,  0x00,0x00,0x00,0x23},  /* 320x200x8  */
++      {0x5c,0x921f,0x0204,0x0000,SIS_RI_512x384,  0x00,0x00,0x00,0x26},  /* 512x384x32 */
++      {0x5d,0x021d,0x0305,0x0139,SIS_RI_640x400,  0x00,0x00,0x00,0x10},  /* 640x400x16 */
++      {0x5e,0x021f,0x0305,0x0000,SIS_RI_640x400,  0x00,0x00,0x00,0x10},  /* 640x400x32 */
++      {0x62,0x0a3f,0x0306,0x013a,SIS_RI_640x480,  0x00,0x00,0x00,0x08},
++      {0x63,0x2a3f,0x0407,0x013b,SIS_RI_800x600,  0x00,0x00,0x00,0x00},  /* 800x600x32 */
++      {0x64,0x0a7f,0x0508,0x013c,SIS_RI_1024x768, 0x00,0x00,0x00,0x13},
++      {0x65,0x0eff,0x0609,0x013d,SIS_RI_1280x1024,0x00,0x00,0x00,0x1a},
++      {0x66,0x06ff,0x070a,0x013e,SIS_RI_1600x1200,0x00,0x00,0x00,0x1e},
++      {0x68,0x067b,0x080b,0x013f,SIS_RI_1920x1440,0x00,0x00,0x00,0x27},
++      {0x69,0x06fd,0x080b,0x0140,SIS_RI_1920x1440,0x00,0x00,0x00,0x27},
++      {0x6b,0x07ff,0x080b,0x0000,SIS_RI_1920x1440,0x00,0x00,0x00,0x27},
++      {0x6c,0x067b,0x090c,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x28},  /* 2048x1536x8 - not in BIOS! */
++      {0x6d,0x06fd,0x090c,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x28},  /* 2048x1536x16 - not in BIOS! */
++      {0x70,0x2a1b,0x0400,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x2d},  /* 800x480x8 */
++      {0x71,0x0a1b,0x0501,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x30},  /* 1024x576x8 */
++      {0x74,0x0a1d,0x0501,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x30},  /* 1024x576x16 */
++      {0x75,0x0e3d,0x0602,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x33},  /* 1280x720x16 */
++      {0x76,0x2a1f,0x0400,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x2d},  /* 800x480x32 */
++      {0x77,0x0a3f,0x0501,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x30},  /* 1024x576x32 */
++      {0x78,0x0eff,0x0602,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x33},  /* 1280x720x32 */
++      {0x79,0x0e3b,0x0602,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x33},  /* 1280x720x8 */
++      {0x7a,0x2a1d,0x0400,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x2d},  /* 800x480x16 */
++      {0x7c,0x0a3b,0x060f,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x29},  /* 1280x960x8 */
++      {0x7d,0x0a7d,0x060f,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x29},  /* 1280x960x16 */
++      {0x7e,0x0aff,0x060f,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x29},  /* 1280x960x32 */
++      {0x20,0x0a1b,0x0504,0x0000,SIS_RI_1024x600, 0x00,0x00,0x00,0x2b},  /* 1024x600 */
++      {0x21,0x0a3d,0x0504,0x0000,SIS_RI_1024x600, 0x00,0x00,0x00,0x2b},
++      {0x22,0x0a7f,0x0504,0x0000,SIS_RI_1024x600, 0x00,0x00,0x00,0x2b},
++      {0x23,0x0a1b,0x0c05,0x0000,SIS_RI_1152x768, 0x00,0x00,0x00,0x2c},  /* 1152x768 */
++      {0x24,0x0a3d,0x0c05,0x0000,SIS_RI_1152x768, 0x00,0x00,0x00,0x2c},
++      {0x25,0x0a7f,0x0c05,0x0000,SIS_RI_1152x768, 0x00,0x00,0x00,0x2c},
++      {0x29,0x0e1b,0x0c05,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x36},  /* 1152x864 */
++      {0x2a,0x0e3d,0x0c05,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x36},
++      {0x2b,0x0e7f,0x0c05,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x36},
++      {0x39,0x2a1b,0x0d06,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x38},  /* 848x480 */
++      {0x3b,0x2a3d,0x0d06,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x38},
++      {0x3e,0x2a7f,0x0d06,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x38},
++      {0x3f,0x2a1b,0x0d07,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x3a},  /* 856x480 */
++      {0x42,0x2a3d,0x0d07,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x3a},
++      {0x45,0x2a7f,0x0d07,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x3a},
++      {0x48,0x223b,0x0e08,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x3c},  /* 1360x768 */
++      {0x4b,0x227d,0x0e08,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x3c},
++      {0x4e,0x22ff,0x0e08,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x3c},
++      {0x4f,0x921f,0x0000,0x0000,SIS_RI_320x200,  0x00,0x00,0x00,0x23},  /* 320x200x32 */
++      {0x53,0x921f,0x0001,0x0000,SIS_RI_320x240,  0x00,0x00,0x00,0x24},  /* 320x240x32 */
++      {0x54,0xb21f,0x0103,0x0000,SIS_RI_400x300,  0x00,0x00,0x00,0x25},  /* 400x300x32 */
++      {0x55,0x2e3b,0x0609,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x3d},  /* 1280x768   */
++      {0x5a,0x2e7d,0x0609,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x3d},
++      {0x5b,0x2eff,0x0609,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x3d},
++      {0x5f,0x2a1b,0x0f0e,0x0000,SIS_RI_768x576,  0x00,0x00,0x00,0x3e},  /* 768x576x8 */
++      {0x60,0x2a1d,0x0f0e,0x0000,SIS_RI_768x576,  0x00,0x00,0x00,0x3e},  /* 768x576x16 */
++      {0x61,0x2a1f,0x0f0e,0x0000,SIS_RI_768x576,  0x00,0x00,0x00,0x3e},  /* 768x576x32 */
++      {0x67,0x2e3b,0x0e08,0x0000,SIS_RI_1360x1024,0x00,0x00,0x00,0x3f},  /* 1360x1024x8 (BARCO) */
++      {0x6f,0x2e7d,0x0e08,0x0000,SIS_RI_1360x1024,0x00,0x00,0x00,0x3f},  /* 1360x1024x16 (BARCO) */
++      {0x72,0x2eff,0x0e08,0x0000,SIS_RI_1360x1024,0x00,0x00,0x00,0x3f},  /* 1360x1024x32 (BARCO) */
++      {0xff,0x0000,0x0000,0xffff,0x00,            0x00,0x00,0x00,0x00}
+ };
+ typedef struct _SiS300_Ext2Struct
+@@ -514,76 +183,77 @@ typedef struct _SiS300_Ext2Struct
+       UCHAR  ModeID;
+       USHORT XRes;
+       USHORT YRes;
+-      USHORT ROM_OFFSET;
+ } SiS300_Ext2Struct;
+ static const SiS300_Ext2Struct  SiS300_RefIndex[] =
+ { /* TW: Don't ever insert anything here, table is indexed */
+-      {0x085f,0x0d,0x03,0x05,0x6a, 800, 600,0x3563}, /* 00 */
+-      {0x0467,0x0e,0x44,0x05,0x6a, 800, 600,0x3568}, /* 01 */
+-      {0x0067,0x0f,0x07,0x48,0x6a, 800, 600,0x356d}, /* 02 - CRT1CRTC was 0x4f */
+-      {0x0067,0x10,0x06,0x8b,0x6a, 800, 600,0x3572}, /* 03 */
+-      {0x0147,0x11,0x08,0x00,0x6a, 800, 600,0x3577}, /* 04 */
+-      {0x0147,0x12,0x0c,0x00,0x6a, 800, 600,0x357c}, /* 05 */
+-      {0x0047,0x11,0x4e,0x00,0x6a, 800, 600,0x3581}, /* 06 - CRT1CRTC was 0x51 */
+-      {0x0047,0x11,0x13,0x00,0x6a, 800, 600,0x3586}, /* 07 */
+-      {0xc85f,0x05,0x00,0x04,0x2e, 640, 480,0x3539}, /* 08 */
+-      {0xc067,0x06,0x02,0x04,0x2e, 640, 480,0x353e}, /* 09 */
+-      {0xc067,0x07,0x02,0x47,0x2e, 640, 480,0x3543}, /* 0a */
+-      {0xc067,0x08,0x03,0x8a,0x2e, 640, 480,0x3548}, /* 0b */
+-      {0xc047,0x09,0x05,0x00,0x2e, 640, 480,0x354d}, /* 0c */
+-      {0xc047,0x0a,0x08,0x00,0x2e, 640, 480,0x3552}, /* 0d */
+-      {0xc047,0x0b,0x0a,0x00,0x2e, 640, 480,0x3557}, /* 0e */
+-      {0xc047,0x0c,0x10,0x00,0x2e, 640, 480,0x355c}, /* 0f */
+-      {0x487f,0x04,0x00,0x00,0x2f, 640, 400,0x3532}, /* 10 */
+-      {0xc00f,0x31,0x01,0x06,0x31, 720, 480,0x3630}, /* 11 */
+-      {0x000f,0x32,0x03,0x06,0x32, 720, 576,0x3637}, /* 12 */
+-      {0x0187,0x15,0x05,0x00,0x37,1024, 768,0x358d}, /* 13 */
+-        {0xc877,0x16,0x09,0x06,0x37,1024, 768,0x3592}, /* 14 */
+-      {0xc067,0x17,0x0b,0x49,0x37,1024, 768,0x3597}, /* 15 - CRT1CRTC was 0x97 */
+-      {0x0267,0x18,0x0d,0x00,0x37,1024, 768,0x359c}, /* 16 */
+-      {0x0047,0x19,0x11,0x8c,0x37,1024, 768,0x35a1}, /* 17 - CRT1CRTC was 0x59 */
+-      {0x0047,0x1a,0x52,0x00,0x37,1024, 768,0x35a6}, /* 18 */
+-      {0x0007,0x1b,0x16,0x00,0x37,1024, 768,0x35ab}, /* 19 - CRT1CRTC was 0x5b */
+-      {0x0387,0x1c,0x4d,0x00,0x3a,1280,1024,0x35be}, /* 1a - CRT1CRTC was 0x5c */
+-      {0x0077,0x1d,0x14,0x07,0x3a,1280,1024,0x35c3}, /* 1b */
+-      {0x0047,0x1e,0x17,0x00,0x3a,1280,1024,0x35c8}, /* 1c */
+-      {0x0007,0x1f,0x98,0x00,0x3a,1280,1024,0x35cd}, /* 1d */
+-      {0x0007,0x20,0x59,0x00,0x3c,1600,1200,0x35d4}, /* 1e - CRT1CRTC was 0x60 */
+-      {0x0007,0x21,0x5a,0x00,0x3c,1600,1200,0x35d9}, /* 1f */
+-      {0x0007,0x22,0x1b,0x00,0x3c,1600,1200,0x35de}, /* 20 */
+-      {0x0007,0x23,0x1d,0x00,0x3c,1600,1200,0x35e3}, /* 21 - CRT1CRTC was 0x63 */
+-      {0x0007,0x24,0x1e,0x00,0x3c,1600,1200,0x35e8}, /* 22 */
+-      {0x407f,0x00,0x00,0x00,0x40, 320, 200,0x3516}, /* 23 */
+-      {0xc07f,0x01,0x00,0x04,0x50, 320, 240,0x351d}, /* 24 */
+-      {0x0077,0x02,0x04,0x05,0x51, 400, 300,0x3524}, /* 25 */
+-      {0xc877,0x03,0x09,0x06,0x52, 512, 384,0x352b}, /* 26 */  /* was c077 */
+-      {0x8207,0x25,0x1f,0x00,0x68,1920,1440,0x35ef}, /* 27 */
+-      {0x0007,0x26,0x20,0x00,0x6c,2048,1536,0x35f6}, /* 28 */
+-      {0x0067,0x27,0x14,0x08,0x6e,1280, 960,0x35b7}, /* 29 - TW: 1280x960-60 */
+-      {0x0027,0x45,0x3c,0x08,0x6e,1280, 960,0x35b7}, /* 2a - TW: 1280x960-85 */
+-      {0xc077,0x33,0x09,0x06,0x20,1024, 600,0x0000}, /* 2b */
+-      {0xc077,0x34,0x0b,0x06,0x23,1152, 768,0x0000}, /* 2c */ /* VCLK 0x09 */
+-      {0x0057,0x35,0x27,0x08,0x70, 800, 480,0x3b52}, /* 2d - TW: 16:9 modes */
+-      {0x0047,0x36,0x37,0x08,0x70, 800, 480,0x3b57}, /* 2e */
+-      {0x0047,0x37,0x08,0x08,0x70, 800, 480,0x3b5c}, /* 2f */
+-      {0x0057,0x38,0x09,0x09,0x71,1024, 576,0x3b63}, /* 30 */
+-      {0x0047,0x39,0x38,0x09,0x71,1024, 576,0x3b68}, /* 31 */
+-      {0x0047,0x3a,0x11,0x09,0x71,1024, 576,0x3b6d}, /* 32 */
+-      {0x0057,0x3b,0x39,0x0a,0x75,1280, 720,0x3b74}, /* 33 */
+-      {0x0047,0x3c,0x3a,0x0a,0x75,1280, 720,0x3b79}, /* 34 */
+-      {0x0007,0x3d,0x3b,0x0a,0x75,1280, 720,0x3b7e}, /* 35 - TW: END of 16:9 modes */
+-      {0x0047,0x3e,0x34,0x06,0x29,1152, 864,0x0000}, /* 36 TW: 1152x864-75Hz - Non-BIOS, new */
+-      {0x0047,0x44,0x3a,0x06,0x29,1152, 864,0x0000}, /* 37 TW: 1152x864-85Hz - Non-BIOS, new */
+-      {0x00c7,0x3f,0x28,0x00,0x39, 848, 480,0x0000}, /* 38 TW: 848x480-38Hzi - Non-BIOS, new */
+-      {0xc047,0x40,0x3d,0x00,0x39, 848, 480,0x0000}, /* 39 TW: 848x480-60Hz  - Non-BIOS, new */
+-      {0x00c7,0x41,0x28,0x00,0x3f, 856, 480,0x0000}, /* 3a TW: 856x480-38Hzi - Non-BIOS, new */
+-      {0xc047,0x42,0x28,0x00,0x3f, 856, 480,0x0000}, /* 3b TW: 856x480-60Hz  - Non-BIOS, new */
+-      {0x0047,0x43,0x3e,0x00,0x48,1360, 768,0x0000}, /* 3c TW: 1360x768-60Hz - Non-BIOS, new */
+-      {0xffff,0,0,0,0,0,0,0}
++      {0x085f,0x0d,0x03,0x05,0x6a, 800, 600}, /* 00 */
++      {0x0467,0x0e,0x44,0x05,0x6a, 800, 600}, /* 01 */
++      {0x0067,0x0f,0x07,0x48,0x6a, 800, 600}, /* 02 - CRT1CRTC was 0x4f */
++      {0x0067,0x10,0x06,0x8b,0x6a, 800, 600}, /* 03 */
++      {0x0147,0x11,0x08,0x00,0x6a, 800, 600}, /* 04 */
++      {0x0147,0x12,0x0c,0x00,0x6a, 800, 600}, /* 05 */
++      {0x0047,0x11,0x4e,0x00,0x6a, 800, 600}, /* 06 - CRT1CRTC was 0x51 */
++      {0x0047,0x11,0x13,0x00,0x6a, 800, 600}, /* 07 */
++      {0xc85f,0x05,0x00,0x04,0x2e, 640, 480}, /* 08 */
++      {0xc067,0x06,0x02,0x04,0x2e, 640, 480}, /* 09 */
++      {0xc067,0x07,0x02,0x47,0x2e, 640, 480}, /* 0a */
++      {0xc067,0x08,0x03,0x8a,0x2e, 640, 480}, /* 0b */
++      {0xc047,0x09,0x05,0x00,0x2e, 640, 480}, /* 0c */
++      {0xc047,0x0a,0x08,0x00,0x2e, 640, 480}, /* 0d */
++      {0xc047,0x0b,0x0a,0x00,0x2e, 640, 480}, /* 0e */
++      {0xc047,0x0c,0x10,0x00,0x2e, 640, 480}, /* 0f */
++      {0x487f,0x04,0x00,0x00,0x2f, 640, 400}, /* 10 */
++      {0xc00f,0x31,0x01,0x06,0x31, 720, 480}, /* 11 */
++      {0x000f,0x32,0x03,0x06,0x32, 720, 576}, /* 12 */
++      {0x0187,0x15,0x05,0x00,0x37,1024, 768}, /* 13 */
++        {0xc877,0x16,0x09,0x06,0x37,1024, 768}, /* 14 */
++      {0xc067,0x17,0x0b,0x49,0x37,1024, 768}, /* 15 - CRT1CRTC was 0x97 */
++      {0x0267,0x18,0x0d,0x00,0x37,1024, 768}, /* 16 */
++      {0x0047,0x19,0x11,0x8c,0x37,1024, 768}, /* 17 - CRT1CRTC was 0x59 */
++      {0x0047,0x1a,0x52,0x00,0x37,1024, 768}, /* 18 */
++      {0x0007,0x1b,0x16,0x00,0x37,1024, 768}, /* 19 - CRT1CRTC was 0x5b */
++      {0x0387,0x1c,0x4d,0x00,0x3a,1280,1024}, /* 1a - CRT1CRTC was 0x5c */
++      {0x0077,0x1d,0x14,0x07,0x3a,1280,1024}, /* 1b */
++      {0x0047,0x1e,0x17,0x00,0x3a,1280,1024}, /* 1c */
++      {0x0007,0x1f,0x98,0x00,0x3a,1280,1024}, /* 1d */
++      {0x0007,0x20,0x59,0x00,0x3c,1600,1200}, /* 1e - CRT1CRTC was 0x60 */
++      {0x0007,0x21,0x5a,0x00,0x3c,1600,1200}, /* 1f */
++      {0x0007,0x22,0x1b,0x00,0x3c,1600,1200}, /* 20 */
++      {0x0007,0x23,0x1d,0x00,0x3c,1600,1200}, /* 21 - CRT1CRTC was 0x63 */
++      {0x0007,0x24,0x1e,0x00,0x3c,1600,1200}, /* 22 */
++      {0x407f,0x00,0x00,0x00,0x40, 320, 200}, /* 23 */
++      {0xc07f,0x01,0x00,0x04,0x50, 320, 240}, /* 24 */
++      {0x0077,0x02,0x04,0x05,0x51, 400, 300}, /* 25 */
++      {0xc877,0x03,0x09,0x06,0x52, 512, 384}, /* 26 */  /* was c077 */
++      {0x8207,0x25,0x1f,0x00,0x68,1920,1440}, /* 27 */
++      {0x0007,0x26,0x20,0x00,0x6c,2048,1536}, /* 28 */
++      {0x0067,0x27,0x14,0x08,0x6e,1280, 960}, /* 29 - TW: 1280x960-60 */
++      {0x0027,0x45,0x3c,0x08,0x6e,1280, 960}, /* 2a - TW: 1280x960-85 */
++      {0xc077,0x33,0x09,0x06,0x20,1024, 600}, /* 2b */
++      {0xc077,0x34,0x0b,0x06,0x23,1152, 768}, /* 2c */        /* VCLK 0x09 */
++      {0x0057,0x35,0x27,0x08,0x70, 800, 480}, /* 2d */
++      {0x0047,0x36,0x37,0x08,0x70, 800, 480}, /* 2e */
++      {0x0047,0x37,0x08,0x08,0x70, 800, 480}, /* 2f */
++      {0x0057,0x38,0x09,0x09,0x71,1024, 576}, /* 30 */
++      {0x0047,0x39,0x38,0x09,0x71,1024, 576}, /* 31 */
++      {0x0047,0x3a,0x11,0x09,0x71,1024, 576}, /* 32 */
++      {0x0057,0x3b,0x39,0x0a,0x75,1280, 720}, /* 33 */
++      {0x0047,0x3c,0x3a,0x0a,0x75,1280, 720}, /* 34 */
++      {0x0007,0x3d,0x3b,0x0a,0x75,1280, 720}, /* 35 */
++      {0x0047,0x3e,0x34,0x06,0x29,1152, 864}, /* 36 1152x864-75Hz */
++      {0x0047,0x44,0x3a,0x06,0x29,1152, 864}, /* 37 1152x864-85Hz */
++      {0x00c7,0x3f,0x28,0x00,0x39, 848, 480}, /* 38 848x480-38Hzi */
++      {0xc067,0x40,0x3d,0x0b,0x39, 848, 480}, /* 39 848x480-60Hz  */
++      {0x00c7,0x41,0x28,0x00,0x3f, 856, 480}, /* 3a 856x480-38Hzi */
++      {0xc047,0x42,0x28,0x00,0x3f, 856, 480}, /* 3b 856x480-60Hz  */
++      {0x0067,0x43,0x3e,0x0c,0x48,1360, 768}, /* 3c 1360x768-60Hz */
++      {0x0077,0x46,0x3f,0x08,0x55,1280, 768}, /* 3d 1280x768-60Hz */
++      {0x000f,0x47,0x03,0x06,0x5f, 768, 576}, /* 3e 768x576 */
++      {0x0027,0x48,0x13,0x08,0x67,1360,1024}, /* 3f 1360x1024-59Hz (BARCO1366 only) */
++      {0xffff,   0,   0,   0,   0,   0,   0}
+ };
+-/*add for 300 oem util*/
+ typedef struct _SiS_VBModeIDTableStruct
+ {
+       UCHAR  ModeID;
+@@ -649,9 +319,8 @@ static const SiS_VBModeIDTableStruct  Si
+       {0x6e,0x00,0x00,0x01,0x00,0x00,0x0b,0x0d},
+       {0x6f,0x00,0x00,0x01,0x00,0x00,0x0b,0x0d},
+       {0x7b,0x00,0x00,0x01,0x00,0x00,0x0b,0x0d},
+-      {0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00}  /* TW: added! */
++      {0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
+ };
+-/*end*/
+ typedef struct _SiS300_CRT1TableStruct
+ {
+@@ -660,15 +329,32 @@ typedef struct _SiS300_CRT1TableStruct
+ static const SiS300_CRT1TableStruct  SiS300_CRT1Table[] =
+ {
+- {{0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,    /* 0x00 */
+-  0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x00,
++#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}},
+- {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e,
+-  0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,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}},
+- {{0x3d,0x31,0x31,0x81,0x37,0x1f,0x72,0xf0,
++#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}},
+@@ -683,7 +369,7 @@ static const SiS300_CRT1TableStruct  SiS
+  {{0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e,    /* 0x05 - corrected 640x480-60 */
+   0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05,
+   0x00}},
+- #if 0  
++#if 0
+  {{0x63,0x4f,0x50,0x86,0x56,0x9b,0x06,0x3e,    /* 0x06 */
+   0xe8,0x8b,0xdf,0xe7,0xff,0x10,0x00,0x01,
+   0x00}},
+@@ -841,15 +527,10 @@ static const SiS300_CRT1TableStruct  SiS
+  {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x1e,0xf1,  /* 0x33 - 1024x600 */
+   0xae,0x85,0x57,0x57,0x1f,0x30,0x00,0x02,
+   0x01}},
+-#if 0
+- {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,  /* 0x34 - 1152x768 */
+-  0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
+-  0x01}},
+-#endif
+- {{0xa3,0x8f,0x8f,0x97,0x96,0x97,0x24,0xf5,  /* 0x34 - 1152x768 - TW: corrected */
++ {{0xa3,0x8f,0x8f,0x97,0x96,0x97,0x24,0xf5,  /* 0x34 - 1152x768 - corrected */
+   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
+   0x01}},
+- {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba,  /* 0x35 - NEW 16:9 modes, not in BIOS ------ */
++ {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba,  /* 0x35 */
+    0x27,0x8b,0xdf,0xdf,0x73,0x00,0x00,0x06,
+    0x01}}, /* 0x35 */
+  {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xba,
+@@ -864,7 +545,7 @@ static const SiS300_CRT1TableStruct  SiS
+  {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf1,
+    0xad,0x81,0x3f,0x3f,0x1f,0x30,0x00,0x02,
+    0x01}}, /* 0x39 */
+- {{0xa7,0x7f,0x7f,0x88,0x89,0x95,0x26,0xf1,           /* TW: 95 was 15 - illegal HBE! */
++ {{0xa7,0x7f,0x7f,0x88,0x89,0x95,0x26,0xf1,  /* 95 was 15 - illegal HBE! */
+    0xb1,0x85,0x3f,0x3f,0x27,0x30,0x00,0x02,
+    0x01}}, /* 0x3a */
+  {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xc4,
+@@ -875,36 +556,40 @@ static const SiS300_CRT1TableStruct  SiS
+    0x01}}, /* 0x3c */
+  {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xd4,
+    0x7d,0x81,0xcf,0xcf,0x2f,0x21,0x00,0x07,
+-   0x01}}, /* 0x3d */                      /* TW: End of 16:9 modes --------------- */
+- {{0xc3,0x8f,0x8f,0x87,0x9b,0x0b,0x82,0xef,  /* TW: New, 1152x864-75 (not in any BIOS)   */
++   0x01}}, /* 0x3d */
++ {{0xc3,0x8f,0x8f,0x87,0x9b,0x0b,0x82,0xef,  /* 1152x864-75 */
+    0x60,0x83,0x5f,0x5f,0x83,0x10,0x00,0x07,
+    0x01}},  /* 0x3e */
+- {{0x86,0x69,0x69,0x8A,0x74,0x06,0x8C,0x15,  /* TW: New, 848x480-38i, not in BIOS */
++ {{0x86,0x69,0x69,0x8A,0x74,0x06,0x8C,0x15,  /* 848x480-38i */
+    0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02,
+    0x00}}, /* 0x3f */
+-#if 0
+- {{0x81,0x69,0x69,0x85,0x70,0x00,0x0F,0x3E,  /* TW: New, 848x480-60, not in BIOS - incorrect for Philips panel */
+-   0xEB,0x8E,0xDF,0xDF,0x10,0x00,0x00,0x02,
+-   0x00}}, /* 0x40 */
+-#endif
+- {{0x83,0x69,0x69,0x87,0x6f,0x1d,0x03,0x3E,  /* TW: New, 848x480-60, not in BIOS */
++ {{0x83,0x69,0x69,0x87,0x6f,0x1d,0x03,0x3E,  /* 848x480-60  */
+    0xE5,0x8d,0xDF,0xe4,0x04,0x00,0x00,0x06,
+    0x00}}, /* 0x40 */
+- {{0x86,0x6A,0x6A,0x8A,0x74,0x06,0x8C,0x15,  /* TW: New, 856x480-38i, not in BIOS */
++ {{0x86,0x6A,0x6A,0x8A,0x74,0x06,0x8C,0x15,  /* 856x480-38i */
+    0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02,
+    0x00}}, /* 0x41 */
+- {{0x81,0x6A,0x6A,0x85,0x70,0x00,0x0F,0x3E,  /* TW: New, 856x480-60, not in BIOS */
++ {{0x81,0x6A,0x6A,0x85,0x70,0x00,0x0F,0x3E,  /* 856x480-60  */
+    0xEB,0x8E,0xDF,0xDF,0x10,0x00,0x00,0x02,
+    0x00}}, /* 0x42 */
+- {{0xdd,0xa9,0xa9,0x81,0xb4,0x97,0x26,0xfd,  /* TW: New, 1360x768-60, not in BIOS */
++ {{0xdd,0xa9,0xa9,0x81,0xb4,0x97,0x26,0xfd,  /* 1360x768-60 */
+    0x01,0x8d,0xff,0x00,0x27,0x10,0x00,0x03,
+    0x01}}, /* 0x43 */
+- {{0xd9,0x8f,0x8f,0x9d,0xba,0x0a,0x8a,0xff,  /* TW: New, 1152x864-84 (not in any BIOS)   */
++ {{0xd9,0x8f,0x8f,0x9d,0xba,0x0a,0x8a,0xff,  /* 1152x864-84 */
+    0x60,0x8b,0x5f,0x5f,0x8b,0x10,0x00,0x03,
+-   0x01}}, /* 0x44 */   
+- {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0xf1,0xff,  /* TW: New, 1280x960-85 (not in any BIOS)   */
++   0x01}}, /* 0x44 */
++ {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0xf1,0xff,  /* 1280x960-85 */
+    0xc0,0x83,0xbf,0xbf,0xf2,0x10,0x00,0x07,
+-   0x01}}  /* 0x45 */
++   0x01}}, /* 0x45 */
++ {{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 */
++ {{0xce,0xa9,0xa9,0x92,0xb1,0x07,0x28,0x52,  /* 1360x1024 (Barco iQ Pro R300) */
++   0x02,0x8e,0xff,0x00,0x29,0x0d,0x00,0x03,
++   0x00}}   /* 0x48 */
+ };
+ typedef struct _SiS300_MCLKDataStruct
+@@ -913,8 +598,8 @@ typedef struct _SiS300_MCLKDataStruct
+       USHORT CLOCK;
+ } SiS300_MCLKDataStruct;
+-static const SiS300_MCLKDataStruct  SiS300_MCLKData_630[] =   /* 630 */
+-{ /* TW: at 0x54 in BIOS */
++static const SiS300_MCLKDataStruct  SiS300_MCLKData_630[] =
++{
+       { 0x5a,0x64,0x80, 66},
+       { 0xb3,0x45,0x80, 83},
+       { 0x37,0x61,0x80,100},
+@@ -925,8 +610,8 @@ static const SiS300_MCLKDataStruct  SiS3
+       { 0x37,0x61,0x80,100}
+ };
+-static const SiS300_MCLKDataStruct  SiS300_MCLKData_300[] =  /* 300 */
+-{ /* TW: at 0x54 in BIOS */
++static const SiS300_MCLKDataStruct  SiS300_MCLKData_300[] =
++{
+       { 0x68,0x43,0x80,125},
+       { 0x68,0x43,0x80,125},
+       { 0x68,0x43,0x80,125},
+@@ -937,6 +622,7 @@ static const SiS300_MCLKDataStruct  SiS3
+       { 0x37,0x61,0x80,100}
+ };
++#ifdef LINUXBIOS
+ typedef struct _SiS300_ECLKDataStruct
+ {
+       UCHAR SR2E,SR2F,SR30;
+@@ -954,6 +640,7 @@ static const SiS300_ECLKDataStruct  SiS3
+       { 0x54,0x43,0x80,100},
+       { 0x54,0x43,0x80,100}
+ };
++#endif
+ typedef struct _SiS300_VCLKDataStruct
+ {
+@@ -964,71 +651,77 @@ typedef struct _SiS300_VCLKDataStruct
+ static const SiS300_VCLKDataStruct  SiS300_VCLKData[] =
+ {
+       { 0x1b,0xe1, 25}, /* 0x00 */
+-      { 0x4e,0xe4, 28},
++      { 0x4e,0xe4, 28}, /* 0x01 */
+       { 0x57,0xe4, 32}, /* 0x02 */
+-      { 0xc3,0xc8, 36},
++      { 0xc3,0xc8, 36}, /* 0x03 */
+       { 0x42,0xc3, 40}, /* 0x04 */
+-      { 0x5d,0xc4, 45},
++      { 0x5d,0xc4, 45}, /* 0x05 */
+       { 0x52,0x65, 50}, /* 0x06 */
+-      { 0x53,0x65, 50},
++      { 0x53,0x65, 50}, /* 0x07 */
+       { 0x6d,0x66, 56}, /* 0x08 */
+-      { 0x5a,0x64, 65},
++      { 0x5a,0x64, 65}, /* 0x09 */
+       { 0x46,0x44, 68}, /* 0x0a */
+-      { 0x3e,0x43, 75},
+-      { 0x6d,0x46, 76}, /* 0x0c: 800x600 | LVDS_2(CH), MITAC(CH);  - 730, A901(301B): 0xb1,0x46, 76 */
+-      { 0x41,0x43, 79},
++      { 0x3e,0x43, 75}, /* 0x0b */
++      { 0x6d,0x46, 76}, /* 0x0c */  /* 800x600 | LVDS_2(CH), MITAC(CH);  - 730, A901(301B): 0xb1,0x46, 76 */
++      { 0x41,0x43, 79}, /* 0x0d */
+       { 0x31,0x42, 79}, /* 0x0e */
+-      { 0x46,0x25, 85},
++      { 0x46,0x25, 85}, /* 0x0f */
+       { 0x78,0x29, 87}, /* 0x10 */
+-      { 0x62,0x44, 95},
++      { 0x62,0x44, 95}, /* 0x11 */
+       { 0x2b,0x22,105}, /* 0x12 */
+-      { 0x49,0x24,106},
++      { 0x49,0x24,106}, /* 0x13 */
+       { 0xc3,0x28,108}, /* 0x14 */
+-      { 0x3c,0x23,109},
++      { 0x3c,0x23,109}, /* 0x15 */
+       { 0xf7,0x2c,132}, /* 0x16 */
+-      { 0xd4,0x28,136},
++      { 0xd4,0x28,136}, /* 0x17 */
+       { 0x41,0x05,158}, /* 0x18 */
+-      { 0x43,0x05,162},
++      { 0x43,0x05,162}, /* 0x19 */
+       { 0xe1,0x0f,175}, /* 0x1a */
+       { 0xfc,0x12,189}, /* 0x1b */
+       { 0xde,0x26,194}, /* 0x1c */
+-      { 0x54,0x05,203},
++      { 0x54,0x05,203}, /* 0x1d */
+       { 0x3f,0x03,230}, /* 0x1e */
+-      { 0x30,0x02,234},
++      { 0x30,0x02,234}, /* 0x1f */
+       { 0x24,0x01,266}, /* 0x20 */
+-      { 0x52,0x2a, 54}, /* 301 TV */
+-      { 0x52,0x6a, 27}, /* 301 TV */
+-      { 0x62,0x24, 70}, /* 301 TV */
+-      { 0x62,0x64, 70}, /* 301 TV */
+-      { 0xa8,0x4c, 30}, /* 301 TV */
+-      { 0x20,0x26, 33}, /* 301 TV */
+-      { 0x31,0xc2, 39},
+-      { 0xbf,0xc8, 35}, /* 0x28 - 856x480 */
+-      { 0x60,0x36, 30}, /* 0x29  CH/UNTSC TEXT | LVDS_2(CH) - 730, A901(301B), Mitac(CH): 0xe0, 0xb6, 30 */
+-      { 0x40,0x4a, 28},
+-      { 0x9f,0x46, 44},
+-      { 0x97,0x2c, 26},
+-      { 0x44,0xe4, 25},
+-      { 0x7e,0x32, 47},
+-      { 0x8a,0x24, 31}, /* 0x2f  CH/PAL TEXT | LVDS_2(CH), Mitac(CH) -  730, A901(301B): 0x57, 0xe4, 31 */
+-      { 0x97,0x2c, 26},
+-      { 0xce,0x3c, 39},
+-      { 0x52,0x4a, 36}, /* 0x32  CH/PAL 800x600 5/6 */
+-      { 0x34,0x61, 95},
+-      { 0x78,0x27,108},
+-      { 0xce,0x25,189}, /* 0x35 */
+-      { 0x45,0x6b, 21}, /* 0x36 */  /* TW: Added from Mitac */
+-      { 0x52,0xe2, 49}, /* 0x37 - added for 16:9 modes (not in any BIOS) */
+-      { 0x2b,0x61, 78}, /* 0x38 - added for 16:9 modes (not in any BIOS) */
+-      { 0x70,0x44,108}, /* 0x39 - added for 16:9 modes (not in any BIOS) */
+-      { 0x54,0x42,135}, /* 0x3a - added for 16:9 modes (not in any BIOS) */
+-      { 0x41,0x22,157}, /* 0x3b - added for 16:9 modes (not in any BIOS) */
+-      { 0x52,0x07,149}, /* 0x3c - added for 1280x960-85 (not in any BIOS)*/
+-      { 0x62,0xc6, 34}, /* 0x3d - added for 848x480-60 (not in any BIOS) */
+-      { 0x30,0x23, 88}, /* 0x3e - added for 1360x768-60 (not in any BIOS)*/
+-      { 0x3f,0x64, 46}, /* 0x3f - added for 640x480-100 (not in any BIOS)*/
+-      { 0x72,0x2a, 76}, /* 0x40 - test for SiS730 */
+-      { 0x15,0x21, 79}, /* 0x41 - test for SiS730 */
++      { 0x52,0x2a, 54}, /* 0x21 */  /* 301 TV */
++      { 0x52,0x6a, 27}, /* 0x22 */  /* 301 TV */
++      { 0x62,0x24, 70}, /* 0x23 */  /* 301 TV */
++      { 0x62,0x64, 70}, /* 0x24 */  /* 301 TV */
++      { 0xa8,0x4c, 30}, /* 0x25 */  /* 301 TV */
++      { 0x20,0x26, 33}, /* 0x26 */  /* 301 TV */
++      { 0x31,0xc2, 39}, /* 0x27 */
++      { 0xbf,0xc8, 35}, /* 0x28 */  /* 856x480 */
++      { 0x60,0x36, 30}, /* 0x29 */  /* CH/UNTSC TEXT | LVDS_2(CH) - 730, A901(301B), Mitac(CH): 0xe0, 0xb6, 30 */
++      { 0x40,0x4a, 28}, /* 0x2a */
++      { 0x9f,0x46, 44}, /* 0x2b */
++      { 0x97,0x2c, 26}, /* 0x2c */
++      { 0x44,0xe4, 25}, /* 0x2d */
++      { 0x7e,0x32, 47}, /* 0x2e */
++      { 0x8a,0x24, 31}, /* 0x2f */  /* CH/PAL TEXT | LVDS_2(CH), Mitac(CH) -  730, A901(301B): 0x57, 0xe4, 31 */
++      { 0x97,0x2c, 26}, /* 0x30 */
++      { 0xce,0x3c, 39}, /* 0x31 */
++      { 0x52,0x4a, 36}, /* 0x32 */  /* CH/PAL 800x600 5/6 */
++      { 0x34,0x61, 95}, /* 0x33 */
++      { 0x78,0x27,108}, /* 0x34 */  /* Replacement for index 0x14 for 630 (?) */
++      { 0xce,0x25,189}, /* 0x35 */  /* Replacement for index 0x1b for 730 (and 540?) */
++      { 0x45,0x6b, 21}, /* 0x36 */
++      { 0x52,0xe2, 49}, /* 0x37 */  /* 16:9 modes  */
++      { 0x2b,0x61, 78}, /* 0x38 */  /* 16:9 modes  */
++      { 0x70,0x44,108}, /* 0x39 */  /* 16:9 modes  */
++      { 0x54,0x42,135}, /* 0x3a */  /* 16:9 modes  */
++      { 0x41,0x22,157}, /* 0x3b */  /* 16:9 modes  */
++      { 0x52,0x07,149}, /* 0x3c */  /* 1280x960-85 */
++      { 0x62,0xc6, 34}, /* 0x3d */  /* 848x480-60  */
++      { 0x30,0x23, 88}, /* 0x3e */  /* 1360x768-60 */
++#if 0
++      { 0x3f,0x64, 46}, /* 0x3f */  /* 640x480-100 */
++#endif
++        { 0x70,0x29, 81}, /* 0x3f */  /* 1280x768-60 */
++      { 0x72,0x2a, 76}, /* 0x40 */  /* test for SiS730 */
++      { 0x15,0x21, 79}, /* 0x41 */  /* test for SiS730 */
++      { 0xa1,0x42,108}, /* 0x42 */  /* 1280x960 LCD */
++      { 0x37,0x61,100}, /* 0x43 */  /* 1280x960 LCD */
++      { 0xe3,0x9a,106}, /* 0x44 */  /* 1360x1024 - special for Barco iQ R300 */
+       { 0xff,0x00,  0}   
+ };
+@@ -1089,66 +782,10 @@ static const SiS300_VCLKDataStruct  SiS3
+ static const UCHAR  SiS300_ScreenOffset[] =
+ {
+       0x14,0x19,0x20,0x28,0x32,0x40,0x50,
+-        0x64,0x78,0x80,0x2d,0x35,0x48,0x35,  /* 0x35 for 848 and 856 */
+-      0x55,0xff                            /* 0x55 for 1360 */        
++        0x64,0x78,0x80,0x2d,0x35,0x48,0x35,
++      0x55,0x30,0xff
+ };
+-typedef struct _SiS300_StResInfoStruct
+-{
+-      USHORT HTotal;
+-      USHORT VTotal;
+-} SiS300_StResInfoStruct;
+-
+-static const SiS300_StResInfoStruct  SiS300_StResInfo[] =
+-{
+-      { 640,400},
+-      { 640,350},
+-      { 720,400},
+-      { 720,350},
+-      { 640,480}
+-};
+-
+-typedef struct _SiS300_ModeResInfoStruct
+-{
+-      USHORT HTotal;
+-      USHORT VTotal;
+-      UCHAR  XChar;
+-      UCHAR  YChar;
+-} SiS300_ModeResInfoStruct;
+-
+-static const SiS300_ModeResInfoStruct  SiS300_ModeResInfo[] =
+-{
+-      {  320, 200, 8, 8},  /* 0x00 */
+-      {  320, 240, 8, 8},  /* 0x01 */
+-      {  320, 400, 8, 8},  /* 0x02 */
+-      {  400, 300, 8, 8},  /* 0x03 */
+-      {  512, 384, 8, 8},  /* 0x04 */
+-      {  640, 400, 8,16},  /* 0x05 */
+-      {  640, 480, 8,16},  /* 0x06 */
+-      {  800, 600, 8,16},  /* 0x07 */
+-      { 1024, 768, 8,16},  /* 0x08 */
+-      { 1280,1024, 8,16},  /* 0x09 */
+-      { 1600,1200, 8,16},  /* 0x0a */
+-      { 1920,1440, 8,16},  /* 0x0b */
+-      {  720, 480, 8,16},  /* 0x0c */
+-      {  720, 576, 8,16},  /* 0x0d */
+-      { 1280, 960, 8,16},  /* 0x0e */
+-      { 1024, 600, 8,16},  /* 0x0f */
+-      { 1152, 768, 8,16},  /* 0x10 */
+-      { 2048,1536, 8,16},  /* 0x11 - TW: Not in BIOS! */
+-      {  800, 480, 8,16},  /* 0x12 - TW: New, not in any BIOS */
+-      { 1024, 576, 8,16},  /* 0x13 - TW: New, not in any BIOS */
+-      { 1280, 720, 8,16},  /* 0x14 - TW: New, not in any BIOS */
+-      { 1152, 864, 8,16},  /* 0x15 - TW: New, not in any BIOS */
+-      {  848, 480, 8,16},  /* 0x16 - TW: New, not in any BIOS */
+-      {  856, 480, 8,16},  /* 0x17 - TW: New, not in any BIOS */
+-      { 1360, 768, 8,16}   /* 0x18 - TW: New, not in any BIOS */
+-};
+-
+-static const UCHAR SiS300_OutputSelect = 0x40;
+-
+-static const UCHAR SiS300_SoftSetting  = 0x30;
+-
+ #ifndef LINUX_XF86
+ static UCHAR SiS300_SR07 = 0x10;
+ #endif
+@@ -1183,7 +820,7 @@ 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;     /*301b*/
++static const USHORT SiS300_RGBSenseData2 = 0x0190;
+ static const USHORT SiS300_VideoSenseData2 = 0x0174;
+ static const USHORT SiS300_YCSenseData2 = 0x016b;
+@@ -1192,15 +829,6 @@ static const UCHAR SiS300_CR40[5][4];
+ static UCHAR SiS300_CR49[2];
+ #endif
+-static const UCHAR SiS300_NTSCPhase[]  = {0x21,0xed,0xba,0x08};  /* TW: Was {0x21,0xed,0x8a,0x08}; */
+-static const UCHAR SiS300_PALPhase[]   = {0x2a,0x05,0xe3,0x00};  /* TW: Was {0x2a,0x05,0xd3,0x00};  */
+-static const UCHAR SiS300_PALMPhase[]  = {0x21,0xE4,0x2E,0x9B};  /* palmn */
+-static const UCHAR SiS300_PALNPhase[]  = {0x21,0xF4,0x3E,0xBA};
+-static const UCHAR SiS300_NTSCPhase2[] = {0x21,0xF0,0x7B,0xD6};  /* 301b */
+-static const UCHAR SiS300_PALPhase2[]  = {0x2a,0x09,0x86,0xe9};  /* 301b */
+-static const UCHAR SiS300_PALMPhase2[] = {0x21,0xE6,0xEF,0xA4}; /* TW: palm 301b*/
+-static const UCHAR SiS300_PALNPhase2[] = {0x21,0xF6,0x94,0x46}; /* TW: paln 301b*/
+-
+ typedef struct _SiS300_PanelDelayTblStruct
+ {
+       UCHAR timer[2];
+@@ -1208,7 +836,7 @@ typedef struct _SiS300_PanelDelayTblStru
+ static const SiS300_PanelDelayTblStruct  SiS300_PanelDelayTbl[] =
+ {
+-      {{0x05,0xaa}}, /* TW: From 2.04.5a */
++      {{0x05,0xaa}},
+       {{0x05,0x14}},
+       {{0x05,0x36}},
+       {{0x05,0x14}},
+@@ -1355,309 +983,6 @@ static const SiS300_LCDDataStruct  SiS30
+       {    1,   1,1688,1066,1688,1066}
+ };
+-static const SiS300_LCDDataStruct  SiS300_LCD1280x960Data[] =
+-{
+-      {    9,   2, 800, 500,1800,1000},
+-      {    9,   2, 800, 500,1800,1000},
+-      {    4,   1, 900, 500,1800,1000},
+-      {    4,   1, 900, 500,1800,1000},
+-      {    9,   2, 800, 500,1800,1000},
+-      {   30,  11,1056, 625,1800,1000},
+-      {    5,   3,1350, 800,1800,1000},
+-      {    1,   1,1576,1050,1576,1050},
+-      {    1,   1,1800,1000,1800,1000}
+-};
+-
+-static const SiS300_LCDDataStruct  SiS300_ExtLCD1400x1050Data[] =  /* TW: New */
+-{
+-      {    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},
+-      {    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 SiS300_LCDDataStruct  SiS300_ExtLCD1600x1200Data[] =  /* TW: New */
+-{
+-      {    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},
+-      {    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 SiS300_LCDDataStruct  SiS300_StLCD1400x1050Data[] =  /* TW: New */
+-{
+-      {    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},
+-      {    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 SiS300_LCDDataStruct  SiS300_StLCD1600x1200Data[] =  /* TW: New */
+-{
+-      {    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},
+-      {    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 SiS300_LCDDataStruct  SiS300_NoScaleData1400x1050[] =  /* TW: New */
+-{
+-      {    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},
+-      {    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 SiS300_LCDDataStruct  SiS300_NoScaleData1600x1200[] =  /* TW: New */
+-{
+-      {    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},
+-      {    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}
+-};
+-
+-
+-typedef struct _SiS300_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;
+-} SiS300_TVDataStruct;
+-
+-static const SiS300_TVDataStruct  SiS300_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}
+-};
+-
+-static const SiS300_TVDataStruct  SiS300_ExtPALData[] =
+-{
+-      {   27,  10, 848, 448,1270, 530,  50,   0,  50,0xf4,0xff,0x1c,0x22},
+-      {  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},
+-      {   36,  25,1060, 648,1316, 530, 438,   0, 438,0xeb,0x05,0x25,0x16},
+-      {    3,   2,1080, 619,1270, 540, 438,   0, 438,0xf3,0x00,0x1d,0x20},
+-      {    1,   1,1170, 821,1270, 520, 686,   0, 686,0xF3,0x00,0x1D,0x20}
+-
+-};
+-
+-static const SiS300_TVDataStruct  SiS300_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}
+-};
+-
+-static const SiS300_TVDataStruct  SiS300_ExtNTSCData[] =
+-{
+-      {  143,  65, 858, 443,1270, 440, 171,   0, 171,0xf1,0x04,0x1f,0x18},
+-      {   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},
+-      {  143, 120,1056, 643,1270, 440,   0, 128,   0,0xf4,0x10,0x1c,0x00},
+-      {  143,  76, 836, 523,1270, 440,   0, 128,   0,0xee,0x0c,0x22,0x08},
+-      {   65,  64,1056, 791,1270, 480, 638,   0,   0,0xf1,0x04,0x1f,0x18}
+-};
+-
+-#if 0
+-static const SiS300_TVDataStruct  SiS300_St1HiTVData[]=
+-{
+-  
+-};
+-#endif
+-
+-static const SiS300_TVDataStruct  SiS300_St2HiTVData[]=
+-{
+- {    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, 0x3e8,0x233,0x311,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}
+-};
+-
+-static const SiS300_TVDataStruct  SiS300_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},
+- {    3,   1, 0x348,0x1e3,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},
+- {   16,   5, 0x41a,0x2ab,0x670,0x3c0,0x143,128, 0, 0x00,0x00,0x00,0x00},
+- {   25,  12, 0x4ec,0x353,0x670,0x3c0,0x032,  0, 0, 0x00,0x00,0x00,0x00},
+- {    5,   4, 0x627,0x464,0x670,0x3c0,0x128,  0, 0, 0x00,0x00,0x00,0x00},
+- {    4,   1, 0x41a,0x233,0x670,0x3c0,0x143,128, 0, 0x00,0x00,0x00,0x00},
+- {    5,   2, 0x578,0x293,0x670,0x3c0,0x032,  0, 0, 0x00,0x00,0x00,0x00},
+- {    8,   5, 0x6d6,0x323,0x670,0x3c0,0x128,  0, 0, 0x00,0x00,0x00,0x00}
+-};
+-
+-static const UCHAR SiS300_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,
+-      0x0c,0x50,0x00,0x97,0x00,0xda,0x4a,0x17,  /* (in 2.06.50) */
+-/*    0x0c,0x50,0x00,0x99,0x00,0xec,0x4a,0x17,     (in 2.04.5a) */
+-      0x7d,0x05,0x4b,0x00,0x00,0xe2,0x00,0x02,  /* (in 2.06.50) */
+-/*    0x88,0x00,0x4b,0x00,0x00,0xe2,0x00,0x02,     (in 2.04.5a) */
+-      0x03,0x0a,0x65,0x9d,0x08,0x92,0x8f,0x40,
+-      0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x50,
+-      0x00,0x40,0x44,0x00,0xdb,0x02,0x3b,0x00
+-};
+-
+-static const UCHAR SiS300_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,
+-        0x70,0x50,0x00,0x9b,0x00,0xd9,0x5d,0x17,  /* (in 2.06.50) */
+-/*    0x70,0x50,0x00,0x97,0x00,0xd7,0x5d,0x17,     (in 2.04.5a) */
+-      0x7d,0x05,0x45,0x00,0x00,0xe8,0x00,0x02,  /* (in 2.06.50) */
+-/*    0x88,0x00,0x45,0x00,0x00,0xe8,0x00,0x02,     (in 2.04.5a) */
+-      0x0d,0x00,0x68,0xb0,0x0b,0x92,0x8f,0x40,
+-      0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x63,
+-      0x00,0x40,0x3e,0x00,0xe1,0x02,0x28,0x00
+-};
+-
+-static const UCHAR SiS300_HiTVExtTiming[] =    /* TW: New */
+-{
+-        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,
+-      0x2a,0xde,0x2a,0x44,0x40,0x2a,0x44,0x40,
+-      0x8e,0x8e,0x82,0x07,0x0b,0x92,0x0f,0x40,
+-      0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x3d,
+-      0x63,0x4f,0x27,0x00,0xfc,0xff,0x6a,0x00
+-};
+-
+-static const UCHAR SiS300_HiTVSt1Timing[] =           /* TW: New */
+-{
+-        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,
+-      0x11,0x15,0x11,0xcf,0x10,0x11,0xcf,0x10,
+-      0x35,0x35,0x3b,0x69,0x1d,0x92,0x0f,0x40,
+-      0x60,0x80,0x14,0x90,0x8c,0x60,0x04,0x86,
+-      0xaf,0x5d,0x0e,0x00,0xfc,0xff,0x2d,0x00
+-};
+-
+-static const UCHAR SiS300_HiTVSt2Timing[] =   /* TW: New */
+-{
+-        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,
+-      0x2a,0xde,0x2a,0x44,0x40,0x2a,0x44,0x40,
+-      0x8e,0x8e,0x82,0x07,0x0b,0x92,0x0f,0x40,
+-      0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x3d,
+-      0x63,0x4f,0x27,0x00,0xfc,0xff,0x6a,0x00
+-};
+-
+-static const UCHAR SiS300_HiTVTextTiming[] =          /* TW: New */
+-{
+-        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,
+-      0x14,0x78,0x14,0x08,0x20,0x14,0x08,0x20,
+-      0xc8,0xc8,0x3b,0xd2,0x26,0x92,0x0f,0x40,
+-        0x60,0x80,0x14,0x90,0x8c,0x60,0x04,0x96,
+-      0x72,0x5c,0x11,0x00,0xfc,0xff,0x32,0x00
+-};
+-
+-static const UCHAR SiS300_HiTVGroup3Data[] =          /* TW: New */
+-{
+-        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,
+-      0x56,0x36,0x4f,0x6e,0x3f,0x80,0x00,0x80,
+-      0x4f,0x7f,0x03,0xa8,0x7d,0x20,0x1a,0xa9,
+-      0x14,0x05,0x03,0x7e,0x64,0x31,0x14,0x75,
+-      0x18,0x05,0x18,0x05,0x4c,0xa8,0x01
+-};
+-
+-static const UCHAR SiS300_HiTVGroup3Simu[] =          /* TW: New */
+-{
+-        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,
+-      0x56,0x36,0x4f,0x6e,0x3f,0x80,0x00,0x80,
+-      0x67,0x36,0x01,0x47,0x0e,0x10,0xbe,0xb4,
+-      0x01,0x05,0x03,0x7e,0x65,0x31,0x14,0x75,
+-      0x18,0x05,0x18,0x05,0x4c,0xa8,0x01
+-};
+-
+-static const UCHAR SiS300_HiTVGroup3Text[] =          /* TW: New */
+-{
+-        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,
+-      0x56,0x36,0x4f,0x6e,0x3f,0x80,0x00,0x80,
+-      0x93,0x3c,0x01,0x50,0x2f,0x10,0xf4,0xca,
+-      0x01,0x05,0x03,0x7e,0x65,0x31,0x14,0x75,
+-      0x18,0x05,0x18,0x05,0x4c,0xa8,0x01
+-};
+-
+ typedef struct _SiS300_LVDSDataStruct
+ {
+       USHORT VGAHT;
+@@ -1666,366 +991,14 @@ typedef struct _SiS300_LVDSDataStruct
+       USHORT LCDVT;
+ } SiS300_LVDSDataStruct;
+-static const SiS300_LVDSDataStruct  SiS300_LVDS320x480Data_1[] =
+-{
+-      {848, 433,400, 525},
+-      {848, 389,400, 525},
+-      {848, 433,400, 525},
+-      {848, 389,400, 525},
+-      {848, 518,400, 525},
+-      {1056,628,400, 525},
+-      {400, 525,400, 525},
+-      {800, 449,1000, 644},
+-      {800, 525,1000, 635}
+-};
+-
+-static const SiS300_LVDSDataStruct  SiS300_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},
+-      {800, 449,1000, 644},
+-      {800, 525,1000, 635}
+-};
+-
+-static const SiS300_LVDSDataStruct  SiS300_LVDS800x600Data_2[] =
+-{
+-      {1056, 628,1056, 628},
+-      {1056, 628,1056, 628},
+-      {1056, 628,1056, 628},
+-      {1056, 628,1056, 628},
+-      {1056, 628,1056, 628},
+-      {1056, 628,1056, 628},
+-      {1056, 628,1056, 628},
+-      {800, 449,1000, 644},
+-      {800, 525,1000, 635}
+-};
+-
+-static const SiS300_LVDSDataStruct  SiS300_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},
+-      {800, 449,1280, 801},
+-      {800, 525,1280, 813}
+-};
+-
+-static const SiS300_LVDSDataStruct  SiS300_LVDS1024x768Data_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},
+-      {800, 449,1280, 801},
+-      {800, 525,1280, 813}
+-};
+-
+-static const SiS300_LVDSDataStruct  SiS300_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 SiS300_LVDSDataStruct  SiS300_LVDS1280x1024Data_2[]=  
+-{     
+-      {1688,1066,1688,1066},
+-      {1688,1066,1688,1066},
+-      {1688,1066,1688,1066},
+-      {1688,1066,1688,1066},
+-      {1688,1066,1688,1066},
+-      {1688,1066,1688,1066},
+-      {1688,1066,1688,1066},
+-      {1688,1066,1688,1066}
+-};
+-
+-static const SiS300_LVDSDataStruct  SiS300_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 SiS300_LVDSDataStruct  SiS300_LVDS1400x1050Data_2[] =  
+-{
+-        {1688,1066, 1688,1066},
+-      {1688,1066, 1688,1066},
+-      {1688,1066, 1688,1066},
+-      {1688,1066, 1688,1066},
+-      {1688,1066, 1688,1066},
+-      {1688,1066, 1688,1066},
+-      {1688,1066, 1688,1066},
+-      {1688,1066, 1688,1066},
+-      {1688,1066, 1688,1066},
+-};
+-
+-static const SiS300_LVDSDataStruct  SiS300_LVDS1600x1200Data_1[]=  
+-{
+-        {1088, 450, 2048,1250},
+-      {1088, 400, 2048,1250},
+-      {1088, 450, 2048,1250},
+-      {1088, 400, 2048,1250},
+-      {1088, 530, 2048,1250},
+-      {1248, 650, 2048,1250},
+-      {1472, 818, 2048,1250},
+-      {1728,1066, 2048,1250},
+-      {1848,1066, 2048,1250},
+-      {2048,1250, 2048,1250}
+-};
+-
+-static const SiS300_LVDSDataStruct  SiS300_LVDS1600x1200Data_2[]= 
+-{
+-        {2048,1250, 2048,1250},
+-      {2048,1250, 2048,1250},
+-      {2048,1250, 2048,1250},
+-      {2048,1250, 2048,1250},
+-      {2048,1250, 2048,1250},
+-      {2048,1250, 2048,1250},
+-      {2048,1250, 2048,1250},
+-      {2048,1250, 2048,1250},
+-      {2048,1250, 2048,1250},
+-      {2048,1250, 2048,1250}
+-};
+-
+-static const SiS300_LVDSDataStruct  SiS300_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 SiS300_LVDSDataStruct  SiS300_LVDS1280x768Data_2[]=  
+-{     
+-      {1408, 806, 1408, 806},
+-      {1408, 806, 1408, 806},
+-      {1408, 806, 1408, 806},
+-      {1408, 806, 1408, 806},
+-      {1408, 806, 1408, 806},
+-      {1408, 806, 1408, 806},
+-      {1408, 806, 1408, 806},
+-      {1408, 806, 1408, 806},
+-      {1408, 806, 1408, 806}
+-};
+-
+-static const SiS300_LVDSDataStruct  SiS300_LVDS1024x600Data_1[] =
+-{
+-      {840, 604,1344, 800},
+-      {840, 560,1344, 800},
+-      {840, 604,1344, 800},
+-      {840, 560,1344, 800},
+-      {840, 689,1344, 800},
+-      {1050, 800,1344, 800},
+-      {1344, 800,1344, 800},
+-      {800, 449,1280, 789},
+-      {800, 525,1280, 785}
+-};
+-
+-static const SiS300_LVDSDataStruct  SiS300_LVDS1024x600Data_2[] =
+-{
+-      {1344, 800,1344, 800},
+-      {1344, 800,1344, 800},
+-      {1344, 800,1344, 800},
+-      {1344, 800,1344, 800},
+-      {1344, 800,1344, 800},
+-      {1344, 800,1344, 800},
+-      {1344, 800,1344, 800},
+-      {800, 449,1280, 801},
+-      {800, 525,1280, 813}
+-};
+-
+-static const SiS300_LVDSDataStruct  SiS300_LVDS1152x768Data_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 SiS300_LVDSDataStruct  SiS300_LVDS1152x768Data_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},
+-      {800, 449,1280, 801},
+-      {800, 525,1280, 813}
+-};
+-
+-/* TW: pass 1:1 data */
+-static const SiS300_LVDSDataStruct  SiS300_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   */
+-      {1344,1066, 1344,1066},  /* 1280x1024  */  /* INSERTED ! */
+-      {1688, 806, 1688, 806},  /* 1280x768 ! */
+-      /* No other panels ! */
+-};
+-
+-static const SiS300_LVDSDataStruct  SiS300_LVDS640x480Data_1[] =
+-{
+-      {800, 449, 800, 449},
+-      {800, 449, 800, 449},
+-      {800, 449, 800, 449},
+-      {800, 449, 800, 449},
+-      {800, 525, 800, 525},
+-      {1056, 628,1056, 628},
+-      {1056, 628,1056, 628},
+-      {1056, 628,1056, 628},
+-      {1056, 628,1056, 628}
+-};
+-
+-static const SiS300_LVDSDataStruct  SiS300_LVDS1280x960Data_1[] =   /* TW: New */
+-{
+-      {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 SiS300_LVDSDataStruct  SiS300_LVDS1280x960Data_2[] =   /* TW: New */
+-{
+-      {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},
+-      {800, 449,1280, 801},
+-      {800, 525,1280, 813}
+-};
+-
+-static const SiS300_LVDSDataStruct  SiS300_LCDA1400x1050Data_1[] =   /* TW: New */
+-{     /* TW: Might be temporary (invalid) data */
+-        {928, 416, 1688, 1066},
+-      {928, 366, 1688, 1066},
+-      {1008, 416, 1688, 1066},
+-      {1008, 366, 1688, 1066},
+-      {1200, 530, 1688, 1066},
+-      {1088, 616, 1688, 1066},
+-      {1312, 784, 1688, 1066},
+-      {1568, 1040, 1688, 1066},
+-      {1688, 1066, 1688, 1066}
+-};
+-
+-static const SiS300_LVDSDataStruct  SiS300_LCDA1400x1050Data_2[] =   /* TW: New */
+-{     /* TW: Temporary data. Not valid */
+-      {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},
+-      {800, 449,1280, 801},
+-      {800, 525,1280, 813}
+-};
+-
+-static const SiS300_LVDSDataStruct  SiS300_LCDA1600x1200Data_1[] =   /* TW: New */
+-{     /* TW: Temporary data. Not valid */
+-      {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},
+-      {800, 449,1280, 801},
+-      {800, 525,1280, 813}
+-};
+-
+-static const SiS300_LVDSDataStruct  SiS300_LCDA1600x1200Data_2[] =   /* TW: New */
+-{     /* TW: Temporary data. Not valid */
+-      {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, 0, 0},
+-      {0, 0, 0, 0},
+-      {0, 0, 0, 0},
+-      {0, 0, 0, 0},
+-      {0, 0, 0, 0}
+-};
+-
+-
+-/* TW: New: */
+-static const SiS300_LVDSDataStruct  SiS300_CHTVUNTSCData[] =
+-{
+-      {840, 600, 840, 600},
+-      {840, 600, 840, 600},
+-      {840, 600, 840, 600},
+-      {840, 600, 840, 600},
+-      {784, 600, 784, 600},
+-      {1064, 750,1064, 750}
+-};
+-
+-static const SiS300_LVDSDataStruct  SiS300_CHTVONTSCData[] =
+-{
+-      {840, 525, 840, 525},
+-      {840, 525, 840, 525},
+-      {840, 525, 840, 525},
+-      {840, 525, 840, 525},
+-      {784, 525, 784, 525},
+-      {1040, 700,1040, 700}
+-};
+-
+ static const SiS300_LVDSDataStruct  SiS300_CHTVUPALData[] =
+ {
+       {1008, 625,1008, 625},
+       {1008, 625,1008, 625},
+       {1008, 625,1008, 625},
+       {1008, 625,1008, 625},
+-      {840, 750, 840, 750},
+-      {936, 836, 936, 836}
++      { 840, 750, 840, 750},
++      { 936, 836, 936, 836}
+ };
+ static const SiS300_LVDSDataStruct  SiS300_CHTVOPALData[] =
+@@ -2034,8 +1007,8 @@ static const SiS300_LVDSDataStruct  SiS3
+       {1008, 625,1008, 625},
+       {1008, 625,1008, 625},
+       {1008, 625,1008, 625},
+-      {840, 625, 840, 625},
+-      {960, 750, 960, 750}
++      { 840, 625, 840, 625},
++      { 960, 750, 960, 750}
+ };
+ static const SiS300_LVDSDataStruct  SiS300_CHTVSOPALData[] =
+@@ -2044,12 +1017,10 @@ static const SiS300_LVDSDataStruct  SiS3
+       {1008, 625,1008, 625},
+       {1008, 625,1008, 625},
+       {1008, 625,1008, 625},
+-      {840, 500, 840, 500},
+-      {944, 625, 944, 625}
++      { 840, 500, 840, 500},
++      { 944, 625, 944, 625}
+ };
+-/* TW: new end */
+-
+ typedef struct _SiS300_LVDSDesStruct
+ {
+       USHORT LCDHDES;
+@@ -2058,57 +1029,90 @@ typedef struct _SiS300_LVDSDesStruct
+ static const SiS300_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}
++      {0, 627},
++      {0, 627},
++      {0,   0},
++      {0,   0}
++#endif
+ };
+ static const SiS300_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}
++      {   0, 805},
++      {   0, 794},
++      {   0,   0}
++#endif
+ };
+ static const SiS300_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}
++      {0, 627},
++      {0, 627},
++      {0,   0},
++      {0,   0}
++#endif
+ };
+ static const SiS300_LVDSDesStruct  SiS300_PanelType03_1[] =
+ {
+-      { 8, 436},
+-      { 8, 440},
+-      { 8, 436},
+-      { 8, 440},
+-      { 8, 512},
++      {   8, 436},
++      {   8, 440},
++      {   8, 436},
++      {   8, 440},
++      {   8, 512},
+       {1343, 798},
+       {1343, 794},
+       {1343, 798},
+       {1343, 794}
+ };
+-static const SiS300_LVDSDesStruct  SiS300_PanelType04_1[] =
++static const SiS300_LVDSDesStruct  SiS300_PanelType04_1[] =   /* 1280x1024 */
+ {
+       {1343, 798},
+       {1343, 794},
+@@ -2116,9 +1120,9 @@ static const SiS300_LVDSDesStruct  SiS30
+       {1343, 794},
+       {1343,   0},
+       {1343,   0},
+-      { 0, 805},
+-      { 0, 794},
+-      { 0,   0}
++      {   0, 805},
++      {   0, 794},
++      {   0,   0}
+ };
+ static const SiS300_LVDSDesStruct  SiS300_PanelType05_1[] =
+@@ -2129,9 +1133,9 @@ static const SiS300_LVDSDesStruct  SiS30
+       {1343, 794},
+       {1343,   0},
+       {1343,   0},
+-      { 0, 805},
+-      { 0, 794},
+-      { 0,   0}
++      {   0, 805},
++      {   0, 794},
++      {   0,   0}
+ };
+ static const SiS300_LVDSDesStruct  SiS300_PanelType06_1[] =
+@@ -2142,9 +1146,9 @@ static const SiS300_LVDSDesStruct  SiS30
+       {1343, 794},
+       {1343,   0},
+       {1343,   0},
+-      { 0, 805},
+-      { 0, 794},
+-      { 0,   0}
++      {   0, 805},
++      {   0, 794},
++      {   0,   0}
+ };
+ static const SiS300_LVDSDesStruct  SiS300_PanelType07_1[] =
+@@ -2155,9 +1159,9 @@ static const SiS300_LVDSDesStruct  SiS30
+       {1343, 794},
+       {1343,   0},
+       {1343,   0},
+-      { 0, 805},
+-      { 0, 794},
+-      { 0,   0}
++      {   0, 805},
++      {   0, 794},
++      {   0,   0}
+ };
+ static const SiS300_LVDSDesStruct  SiS300_PanelType08_1[] =
+@@ -2167,10 +1171,10 @@ static const SiS300_LVDSDesStruct  SiS30
+       {1059, 626},
+       {1059, 624},
+       {1059, 624},
+-      { 0, 627},
+-      { 0, 627},
+-      { 0,   0},
+-      { 0,   0}
++      {   0, 627},
++      {   0, 627},
++      {   0,   0},
++      {   0,   0}
+ };
+ static const SiS300_LVDSDesStruct  SiS300_PanelType09_1[] =
+@@ -2181,9 +1185,9 @@ static const SiS300_LVDSDesStruct  SiS30
+       {1343, 794},
+       {1343,   0},
+       {1343,   0},
+-      { 0, 805},
+-      { 0, 794},
+-      { 0,   0}
++      {   0, 805},
++      {   0, 794},
++      {   0,   0}
+ };
+ static const SiS300_LVDSDesStruct  SiS300_PanelType0a_1[] =
+@@ -2193,23 +1197,23 @@ static const SiS300_LVDSDesStruct  SiS30
+       {1059, 626},
+       {1059, 624},
+       {1059, 624},
+-      { 0, 627},
+-      { 0, 627},
+-      { 0,   0},
+-      { 0,   0}
++      {   0, 627},
++      {   0, 627},
++      {   0,   0},
++      {   0,   0}
+ };
+ static const SiS300_LVDSDesStruct  SiS300_PanelType0b_1[] =
+ {
+-      {1343, 0},
+-      {1343, 0},
+-      {1343, 0},
+-      {1343, 0},
+-      {1343, 0},   /* 640x480 - BIOS 1343, 0 */
+-      {1343, 0},
+-      { 0, 799},
+-      { 0, 0},
+-      { 0, 0}
++      {1343,   0},
++      {1343,   0},
++      {1343,   0},
++      {1343,   0},
++      {1343,   0},
++      {1343,   0},
++      {   0, 799},
++      {   0,   0},
++      {   0,   0}
+ };
+ static const SiS300_LVDSDesStruct  SiS300_PanelType0c_1[] =
+@@ -2220,9 +1224,9 @@ static const SiS300_LVDSDesStruct  SiS30
+       {1343, 794},
+       {1343,   0},
+       {1343,   0},
+-      { 0, 805},
+-      { 0, 794},
+-      { 0,   0}
++      {   0, 805},
++      {   0, 794},
++      {   0,   0}
+ };
+ static const SiS300_LVDSDesStruct  SiS300_PanelType0d_1[] =
+@@ -2233,9 +1237,9 @@ static const SiS300_LVDSDesStruct  SiS30
+       {1343, 794},
+       {1343,   0},
+       {1343,   0},
+-      { 0, 805},
+-      { 0, 794},
+-      { 0,   0}
++      {   0, 805},
++      {   0, 794},
++      {   0,   0}
+ };
+ static const SiS300_LVDSDesStruct  SiS300_PanelType0e_1[] =
+@@ -2244,11 +1248,11 @@ static const SiS300_LVDSDesStruct  SiS30
+       {1343, 794},
+       {1343, 798},
+       {1343, 794},
+-      {1343,   0},  /* 640x480 */
+-      {1343,   0},  /* 800x600 */
+-      { 0, 805},    /* 1024x768 */
+-      { 0, 794},    /* 1280x1024 */
+-      { 0,   0}     /* 1280x960 - not applicable */
++      {1343,   0},    /* 640x480 */
++      {1343,   0},    /* 800x600 */
++      {   0, 805},    /* 1024x768 */
++      {   0, 794},    /* 1280x1024 */
++      {   0,   0}     /* 1280x960 - not applicable */
+ };
+ static const SiS300_LVDSDesStruct  SiS300_PanelType0f_1[] =
+@@ -2259,9 +1263,9 @@ static const SiS300_LVDSDesStruct  SiS30
+       {1343, 794},
+       {1343,   0},
+       {1343,   0},
+-      { 0, 805},
+-      { 0, 794},
+-      { 0,   0}
++      {   0, 805},
++      {   0, 794},
++      {   0,   0}
+ };
+ static const SiS300_LVDSDesStruct  SiS300_PanelType00_2[] =
+@@ -2271,10 +1275,10 @@ static const SiS300_LVDSDesStruct  SiS30
+       {976, 527},
+       {976, 502},
+       {976, 567},
+-      { 0, 627},
+-      { 0, 627},
+-      { 0,   0},
+-      { 0,   0}
++      {  0, 627},
++      {  0, 627},
++      {  0,   0},
++      {  0,   0}
+ };
+ static const SiS300_LVDSDesStruct  SiS300_PanelType01_2[] =
+@@ -2285,9 +1289,9 @@ static const SiS300_LVDSDesStruct  SiS30
+       {1152, 597},
+       {1152, 662},
+       {1232, 722},
+-      { 0, 805},
+-      { 0, 794},
+-      { 0,   0}
++      {   0, 805},
++      {   0, 794},
++      {   0,   0}
+ };
+ static const SiS300_LVDSDesStruct  SiS300_PanelType02_2[] =
+@@ -2297,10 +1301,10 @@ static const SiS300_LVDSDesStruct  SiS30
+       {976, 527},
+       {976, 502},
+       {976, 567},
+-      { 0, 627},
+-      { 0, 627},
+-      { 0,   0},
+-      { 0,   0}
++      {  0, 627},
++      {  0, 627},
++      {  0,   0},
++      {  0,   0}
+ };
+ static const SiS300_LVDSDesStruct  SiS300_PanelType03_2[] =
+@@ -2472,156 +1476,57 @@ static const SiS300_LVDSDesStruct  SiS30
+       {   0,   0}
+ };
+-static const SiS300_LVDSDesStruct  SiS300_PanelTypeNS_1[]= 
++/* Custom data for Barco iQ R200/300/400 (BIOS 2.00.07) */
++static const SiS300_LVDSDesStruct  SiS300_PanelType04_1a[] =  /* 1280x1024 (1366x1024) */
+ {
+-      { 8,   0},
+-      { 8,   0},
+-      { 8,   0},
+-      { 8,   0},
+-      { 8,   0},
+-      { 0,   0},
+-      { 0,   0},
+-      { 0,   0},
+-      { 0, 806},
+-      { 0, 0 }
+-};
+-
+-static const SiS300_LVDSDesStruct  SiS300_PanelTypeNS_2[] = 
+-{
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0}
+-};
+-
+-static const SiS300_LVDSDesStruct SiS300_PanelType1076_1[] =   /* TW: New */
+-{
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0}
+-};
+-
+-static const SiS300_LVDSDesStruct SiS300_PanelType1076_2[] =   /* TW: New */
+-{
+-      { 1152, 622 },
+-      { 1152, 597 },
+-      { 1152, 622 },
+-      { 1152, 597 },
+-      { 1152, 622 },
+-      { 1232, 722 },
+-      {    0, 0   },
+-      {    0, 794 },
+-      {    0, 0   }
+-};
+-
+-static const SiS300_LVDSDesStruct SiS300_PanelType1210_1[] =   /* TW: New */
+-{
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0}
+-};
+-
+-static const SiS300_LVDSDesStruct SiS300_PanelType1210_2[] =   /* TW: New */
+-{
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0}
+-};
+-
+-static const SiS300_LVDSDesStruct SiS300_PanelType1296_1[] =   /* TW: New */
+-{
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0}
+-};
+-
+-static const SiS300_LVDSDesStruct SiS300_PanelType1296_2[] =   /* TW: New */
+-{
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0}
+-};
+-
+-
+-/* TW: New */
+-static const SiS300_LVDSDesStruct  SiS300_CHTVUNTSCDesData[] =
+-{
+-      { 0,   0},
+-      { 0,   0},
+-      { 0,   0},
+-      { 0,   0},
+-      { 0,   0},
+-      { 0,   0}
+-};
+-
+-static const SiS300_LVDSDesStruct  SiS300_CHTVONTSCDesData[] =
+-{
+-      { 0,   0},
+-      { 0,   0},
+-      { 0,   0},
+-      { 0,   0},
+-      { 0,   0},
+-      { 0,   0}
+-};
+-
+-static const SiS300_LVDSDesStruct  SiS300_CHTVUPALDesData[] =
+-{
+-      {256,   0},
+-      {256,   0},
+-      {256,   0},
+-      {256,   0},
+-      {  0,   0},
+-      {  0,   0}
++      {1330, 798},  /* 320x200 */
++      {1330, 794},
++      {1330, 798},
++      {1330, 794},
++      {1330,   0},  /* 640x480 / 320x240  */
++      {1343,   0},  /* 800x600 / 400x300  */
++      {   0, 805},  /* 1024x768 / 512x384 */
++      {1688,1066},  /* 1280x1024          */
++      {   0,   0}   /* 1360x1024          */
+ };
+-static const SiS300_LVDSDesStruct  SiS300_CHTVOPALDesData[] =
++static const SiS300_LVDSDesStruct  SiS300_PanelType04_2a[] =
+ {
+-      {256,   0},
+-      {256,   0},
+-      {256,   0},
+-      {256,   0},
+-      {  0,   0},
+-      {  0,   0}
++      {1152, 622},
++      {1152, 597},
++      {1152, 622},
++      {1152, 597},
++      {1152, 662},
++      {1232, 722},
++      {   0, 805},
++      {1688,1066},
++      {   0,   0}
++};
++
++/* Custom data for Barco iQ G200/300/400 (BIOS 2.00.07) */
++static const SiS300_LVDSDesStruct  SiS300_PanelType04_1b[] =  /* 1024x768 */
++{
++      {1330, 798},  /* 320x200 */
++      {1330, 794},
++      {1330, 798},
++      {1330, 794},
++      {1330,   0},  /* 640x480 / 320x240  */
++      {1343,   0},  /* 800x600 / 400x300  */
++      {   0, 805}   /* 1024x768 / 512x384 */
++};
++
++static const SiS300_LVDSDesStruct  SiS300_PanelType04_2b[] =
++{
++      {1152, 622},
++      {1152, 597},
++      {1152, 622},
++      {1152, 597},
++      {1152, 662},
++      {1232, 722},
++      {   0, 805}
+ };
+-/* TW: New end */
+-/* TW: New for SiS300+301LV */
++
+ typedef struct _SiS300_Part2PortTblStruct
+ {
+       UCHAR CR[12];
+@@ -2726,6 +1631,28 @@ static const SiS300_LVDSCRT1DataStruct  
+         0x01 }}
+ };
++static const SiS300_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 SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x768_1[] =
+ { 
+       {{0x64,0x4f,0x88,0x54,0x9f,0xc4,0x1f,
+@@ -2751,55 +1678,31 @@ static const SiS300_LVDSCRT1DataStruct  
+         0x01}}
+ };
+-static const SiS300_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 SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT1800x600_1_H[] =
++static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x768_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,
++      {{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f,
++        0x92,0x89,0x8f,0xb5,0x30,0x00,0x44,
+         0x00 }},
+-      {{0x3d,0x31,0x81,0x37,0x1f,0x72,0xf0,
+-        0x58,0x8c,0x57,0x73,0x20,0x00,0x05,
++      {{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 SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x768_1_H[] =
+-{
++#if 0
+       {{0x37,0x27,0x9B,0x2b,0x94,0xc4,0x1f,
+         0x92,0x89,0x8f,0xb5,0x30,0x00,0x44,
+         0x00 }},
+@@ -2821,6 +1724,32 @@ static const SiS300_LVDSCRT1DataStruct  
+       {{0x4f,0x3F,0x93,0x45,0x0D,0x24,0xf5,
+         0x02,0x88,0xFf,0x25,0x10,0x00,0x01,
+         0x01 }}
++#endif
++};
++
++static const SiS300_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 SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11280x1024_1_H[] =
+@@ -2870,32 +1799,29 @@ static const SiS300_LVDSCRT1DataStruct  
+         0x01 }}
+ };
+-static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x768_2[] =
++static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT1800x600_2_H[] =
+ {
+-      {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+-        0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
++      {{0x3d,0x27,0x81,0x32,0x1a,0x72,0x3e,
++        0xf4,0x88,0x8f,0x73,0x20,0x00,0x05,
+         0x00 }},
+-      {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+-        0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
++      {{0x3d,0x27,0x81,0x32,0x1a,0x72,0x3e,
++        0xdb,0x8f,0x5d,0x73,0x20,0x00,0x05,
+         0x00 }},
+-      {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+-        0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
++      {{0x3d,0x27,0x81,0x32,0x1a,0x72,0x3e,
++        0xf4,0x88,0x8f,0x73,0x20,0x00,0x05,
+         0x00 }},
+-      {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+-        0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
++      {{0x3d,0x27,0x81,0x3a,0x1a,0x72,0x3e,
++        0xdb,0x8f,0x5d,0x73,0x20,0x00,0x05,
+         0x00 }},
+-      {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+-        0x72,0x88,0xdf,0x25,0x30,0x00,0x06,
++      {{0x3d,0x27,0x81,0x32,0x1a,0x72,0xba,
++        0x1c,0x80,0xdf,0x73,0x00,0x00,0x05,
+         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,
++      {{0x3d,0x31,0x81,0x37,0x1f,0x72,0xf0,
++        0x58,0x8c,0x57,0x73,0x20,0x00,0x05,
+         0x01 }}
+ };
+-static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11280x1024_2[] =
++static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x768_2[] =
+ {
+       {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+         0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+@@ -2920,28 +1846,6 @@ static const SiS300_LVDSCRT1DataStruct  
+         0x01 }}
+ };
+-static const SiS300_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 SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x768_2_H[] =
+ {
+       {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+@@ -2967,6 +1871,31 @@ static const SiS300_LVDSCRT1DataStruct  
+         0x01 }}
+ };
++static const SiS300_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 SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11280x1024_2_H[] =
+ {
+       {{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
+@@ -2992,207 +1921,6 @@ static const SiS300_LVDSCRT1DataStruct  
+         0x01}}
+ };
+-static const SiS300_LVDSCRT1DataStruct  SiS300_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 SiS300_LVDSCRT1DataStruct  SiS300_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 SiS300_LVDSCRT1DataStruct  SiS300_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 SiS300_LVDSCRT1DataStruct  SiS300_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 SiS300_LVDSCRT1DataStruct  SiS300_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 SiS300_LVDSCRT1DataStruct  SiS300_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 SiS300_LVDSCRT1DataStruct  SiS300_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 SiS300_LVDSCRT1DataStruct  SiS300_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}}
+-};
+-
+-/* TW: New */
+ static const SiS300_LVDSCRT1DataStruct  SiS300_CHTVCRT1UNTSC[] =
+ {
+       {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
+@@ -3302,9 +2030,7 @@ static const SiS300_LVDSCRT1DataStruct  
+         0x90,0x8c,0x57,0xed,0x20,0x00,0x05,
+         0x01 }}
+ };
+-/* TW: New end */
+-/* TW: New */
+ typedef struct _SiS300_CHTVRegDataStruct
+ {
+       UCHAR Reg[16];
+@@ -3361,9 +2087,7 @@ static const SiS300_CHTVRegDataStruct Si
+       {{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 */
+ };
+-/* TW: New end */
+-/* TW: New */
+ static const UCHAR SiS300_CHTVVCLKUNTSC[]  = {0x29,0x29,0x29,0x29,0x2a,0x2e};
+ static const UCHAR SiS300_CHTVVCLKONTSC[]  = {0x2c,0x2c,0x2c,0x2c,0x2d,0x2b};
+@@ -3375,6 +2099,5 @@ static const UCHAR SiS300_CHTVVCLKUPAL[]
+ static const UCHAR SiS300_CHTVVCLKOPAL[]   = {0x2f,0x2f,0x2f,0x2f,0x30,0x32};
+ static const UCHAR SiS300_CHTVVCLKSOPAL[]  = {0x2f,0x2f,0x2f,0x2f,0x36,0x29};
+-/* TW: New end */
+--- linux-2.6.0-test6/drivers/video/sis/310vtbl.h      2003-06-14 12:18:23.000000000 -0700
++++ 25/drivers/video/sis/310vtbl.h     2003-10-05 00:34:22.000000000 -0700
+@@ -1,7 +1,37 @@
+-
+-
+-/* Register settings for SiS 310/325/330 series */
+-
++/* $XFree86$ */
++/*
++ * Register settings for SiS 315/330 series
++ *
++ * Copyright 2002, 2003 by Thomas Winischhofer, Vienna, Austria
++ *
++ * If distributed as part of the linux kernel, the contents of this file
++ * is entirely covered by the GPL.
++ *
++ * Otherwise, the following terms apply:
++ *
++ * Permission to use, copy, modify, distribute, and sell this software and its
++ * documentation for any purpose is hereby granted without fee, provided that
++ * the above copyright notice appear in all copies and that both that
++ * copyright notice and this permission notice appear in supporting
++ * documentation, and that the name of the copyright holder not be used in
++ * advertising or publicity pertaining to distribution of the software without
++ * specific, written prior permission.  The copyright holder makes no representations
++ * about the suitability of this software for any purpose.  It is provided
++ * "as is" without express or implied warranty.
++ *
++ * THE COPYRIGHT HOLDER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
++ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
++ * EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR
++ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
++ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
++ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ *
++ * Author:    Thomas Winischhofer <thomas@winischhofer.net>
++ *
++ * Based on code by Silicon Intergrated Systems
++ *
++ */
+ typedef struct _SiS310_StStruct
+ {
+@@ -39,466 +69,12 @@ static const SiS310_StStruct SiS310_SMod
+       {0xff,0x0000,0x00,0x00,0x00,0x00,0x00,0x00}
+ };
+-typedef struct _SiS310_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];
+-} SiS310_StandTableStruct;
+-
+-static const SiS310_StandTableStruct SiS310_StandTable[]=
+-{
+-/* 0x00: MD_0_200 */
+- {
+-  0x28,0x18,0x08,0x0800,
+-  {0x09,0x03,0x00,0x02},
+-  0x63,
+-  {0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f,
+-   0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00,
+-   0x9c,0x8e,0x8f,0x14,0x1f,0x96,0xb9,0xa3,
+-   0xff},
+-  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+-   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+-   0x08,0x00,0x0f,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+-   0xff}
+- },
+-/* 0x01: MD_1_200 */
+- {
+-  0x28,0x18,0x08,0x0800,
+-  {0x09,0x03,0x00,0x02},
+-  0x63,
+-  {0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f,
+-   0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00,
+-   0x9c,0x8e,0x8f,0x14,0x1f,0x96,0xb9,0xa3,
+-   0xff},
+-  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+-   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+-   0x08,0x00,0x0f,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+-   0xff}
+- },
+-/* 0x02: MD_2_200 */
+- {
+-  0x50,0x18,0x08,0x1000,
+-  {0x01,0x03,0x00,0x02},
+-  0x63,
+-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+-   0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00,
+-   0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,
+-   0xff},
+-  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+-   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+-   0x08,0x00,0x0f,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+-   0xff}
+- },
+-/* 0x03: MD_3_200 - mode 0x03 - 0 */
+- {
+-  0x50,0x18,0x08,0x1000,
+-  {0x01,0x03,0x00,0x02},
+-  0x63,
+-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+-   0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00,
+-   0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,
+-   0xff},
+-  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+-   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+-   0x08,0x00,0x0f,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+-   0xff}
+- },
+-/* 0x04: MD_4 */
+- {
+-  0x28,0x18,0x08,0x4000,
+-  {0x09,0x03,0x00,0x02},
+-  0x63,
+-  {0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,
+-   0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,
+-   0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xa2,
+-   0xff},
+-  {0x00,0x13,0x15,0x17,0x02,0x04,0x06,0x07,
+-   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+-   0x01,0x00,0x03,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x30,0x0f,0x00,
+-   0xff}
+- },
+-/* 0x05: MD_5 */
+- {
+-  0x28,0x18,0x08,0x4000,
+-  {0x09,0x03,0x00,0x02},
+-  0x63,
+-  {0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,
+-   0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,
+-   0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xa2,
+-   0xff},
+-  {0x00,0x13,0x15,0x17,0x02,0x04,0x06,0x07,
+-   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+-   0x01,0x00,0x03,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x30,0x0f,0x00,
+-   0xff}
+- },
+-/* 0x06: MD_6 */
+- {
+-  0x50,0x18,0x08,0x4000,
+-  {0x01,0x01,0x00,0x06},
+-  0x63,
+-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+-   0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,
+-   0x9c,0x8e,0x8f,0x28,0x00,0x96,0xb9,0xc2,
+-   0xff},
+-  {0x00,0x17,0x17,0x17,0x17,0x17,0x17,0x17,
+-   0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,
+-   0x01,0x00,0x01,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x00,
+-   0xff}
+- },
+-/* 0x07: MD_7 */
+- {
+-  0x50,0x18,0x0e,0x1000,
+-  {0x00,0x03,0x00,0x03},
+-  0xa6,
+-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+-   0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
+-   0x83,0x85,0x5d,0x28,0x0d,0x63,0xba,0xa3,
+-   0xff},
+-  {0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
+-   0x10,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+-   0x0e,0x00,0x0f,0x08},
+-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0a,0x00,
+-   0xff}
+- },
+-/* 0x08: MDA_DAC */
+- {
+-  0x00,0x00,0x00,0x0000,
+-  {0x00,0x00,0x00,0x15},
+-  0x15,
+-  {0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+-   0x15,0x15,0x15,0x15,0x15,0x15,0x3f,0x3f,
+-   0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x00,0x00,
+-   0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x15,0x15,0x15,
+-   0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+-   0x15,0x15,0x15,0x15},
+-  {0x15,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,
+-   0x3f}
+- },
+-/* 0x09: CGA_DAC */
+- {
+-  0x00,0x10,0x04,0x0114,
+-  {0x11,0x09,0x15,0x00},
+-  0x10,
+-  {0x04,0x14,0x01,0x11,0x09,0x15,0x2a,0x3a,
+-   0x2e,0x3e,0x2b,0x3b,0x2f,0x3f,0x2a,0x3a,
+-   0x2e,0x3e,0x2b,0x3b,0x2f,0x3f,0x00,0x10,
+-   0x04},
+-  {0x14,0x01,0x11,0x09,0x15,0x00,0x10,0x04,
+-   0x14,0x01,0x11,0x09,0x15,0x2a,0x3a,0x2e,
+-   0x3e,0x2b,0x3b,0x2f},
+-  {0x3f,0x2a,0x3a,0x2e,0x3e,0x2b,0x3b,0x2f,
+-   0x3f}
+- },
+-/* 0x0a: EGA_DAC */
+- {
+-  0x00,0x10,0x04,0x0114,
+-  {0x11,0x05,0x15,0x20},
+-  0x30,
+-  {0x24,0x34,0x21,0x31,0x25,0x35,0x08,0x18,
+-   0x0c,0x1c,0x09,0x19,0x0d,0x1d,0x28,0x38,
+-   0x2c,0x3c,0x29,0x39,0x2d,0x3d,0x02,0x12,
+-   0x06},
+-  {0x16,0x03,0x13,0x07,0x17,0x22,0x32,0x26,
+-   0x36,0x23,0x33,0x27,0x37,0x0a,0x1a,0x0e,
+-   0x1e,0x0b,0x1b,0x0f},
+-  {0x1f,0x2a,0x3a,0x2e,0x3e,0x2b,0x3b,0x2f,
+-   0x3f}
+- },
+-/* 0x0b: VGA_DAC */
+- {
+-  0x00,0x10,0x04,0x0114,
+-  {0x11,0x09,0x15,0x2a},
+-  0x3a,
+-  {0x2e,0x3e,0x2b,0x3b,0x2f,0x3f,0x00,0x05,
+-   0x08,0x0b,0x0e,0x11,0x14,0x18,0x1c,0x20,
+-   0x24,0x28,0x2d,0x32,0x38,0x3f,0x00,0x10,
+-   0x1f},
+-  {0x2f,0x3f,0x1f,0x27,0x2f,0x37,0x3f,0x2d,
+-   0x31,0x36,0x3a,0x3f,0x00,0x07,0x0e,0x15,
+-   0x1c,0x0e,0x11,0x15},
+-  {0x18,0x1c,0x14,0x16,0x18,0x1a,0x1c,0x00,
+-   0x04}
+- },
+-/* 0x0c */ 
+- {
+-  0x08,0x0c,0x10,0x0a08,
+-  {0x0c,0x0e,0x10,0x0b},
+-  0x0c,
+-  {0x0d,0x0f,0x10,0x10,0x01,0x08,0x00,0x00,
+-   0x00,0x00,0x01,0x00,0x02,0x02,0x01,0x00,
+-   0x04,0x04,0x01,0x00,0x05,0x02,0x05,0x00,
+-   0x06},
+-  {0x01,0x06,0x05,0x06,0x00,0x08,0x01,0x08,
+-   0x00,0x07,0x02,0x07,0x06,0x07,0x00,0x00,
+-   0x00,0x00,0x00,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+-   0x00}
+- },
+-/* 0x0d: MD_D */
+- {
+-  0x28,0x18,0x08,0x2000,
+-  {0x09,0x0f,0x00,0x06},
+-  0x63,
+-  {0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,
+-   0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
+-   0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xe3,
+-   0xff},
+-  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+-   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+-   0x01,0x00,0x0f,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
+-   0xff}
+- },
+-/* 0x0e: MD_E */
+- {
+-  0x50,0x18,0x08,0x4000,
+-  {0x01,0x0f,0x00,0x06},
+-  0x63,
+-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+-   0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
+-   0x9c,0x8e,0x8f,0x28,0x00,0x96,0xb9,0xe3,
+-   0xff},
+-  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+-   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+-   0x01,0x00,0x0f,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
+-   0xff}
+- },
+-/* 0x0f: ExtVGATable - modes > 0x13 */
+- {
+-  0x00,0x00,0x00,0x0000,
+-  {0x01,0x0f,0x00,0x0e},
+-  0x23,
+-  {0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
+-   0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
+-   0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
+-   0xff},
+-  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+-   0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
+-   0x01,0x00,0x00,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
+-   0xff}
+- },
+-/* 0x10: ROM_SAVEPTR */
+- {
+-  0x9f,0x3b,0x00,0x00c0,
+-  {0x00,0x00,0x00,0x00},
+-  0x00,
+-  {0x00,0x00,0x00,0x00,0x00,0x00,0xbb,0x3f,
+-   0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
+-   0x00,0x00,0x1a,0x00,0xac,0x3e,0x00,0xc0,
+-   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}
+- },
+-/* 0x11: MD_F */
+- {
+-  0x50,0x18,0x0e,0x8000,
+-  {0x01,0x0f,0x00,0x06},
+-  0xa2,
+-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+-   0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
+-   0x82,0x84,0x5d,0x28,0x0f,0x63,0xba,0xe3,
+-   0xff},
+-  {0x00,0x08,0x00,0x00,0x18,0x18,0x00,0x00,
+-   0x00,0x08,0x00,0x00,0x00,0x18,0x00,0x00,
+-   0x0b,0x00,0x05,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x05,
+-   0xff}
+- },
+-/* 0x12: MD_10 */
+- {
+-  0x50,0x18,0x0e,0x8000,
+-  {0x01,0x0f,0x00,0x06},
+-  0xa3,
+-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+-   0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
+-   0x82,0x84,0x5d,0x28,0x0f,0x63,0xba,0xe3,
+-   0xff},
+-  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+-   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+-   0x01,0x00,0x0f,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
+-   0xff}
+- },
+-/* 0x13: MD_0_350 */
+- {
+-  0x28,0x18,0x0e,0x0800,
+-  {0x09,0x03,0x00,0x02},
+-  0xa3,
+-  {0x2d,0x27,0x28,0x90,0x2b,0xb1,0xbf,0x1f,
+-   0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
+-   0x83,0x85,0x5d,0x14,0x1f,0x63,0xba,0xa3,
+-   0xff},
+-  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+-   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+-   0x08,0x00,0x0f,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+-   0xff}
+- },
+-/* 0x14: MD_1_350 */
+- {
+-  0x28,0x18,0x0e,0x0800,
+-  {0x09,0x03,0x00,0x02},
+-  0xa3,
+-  {0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f,
+-   0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
+-   0x83,0x85,0x5d,0x14,0x1f,0x63,0xba,0xa3,
+-   0xff},
+-  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+-   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+-   0x08,0x00,0x0f,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+-   0xff}
+- },
+-/* 0x15: MD_2_350 */
+- {
+-  0x50,0x18,0x0e,0x1000,
+-  {0x01,0x03,0x00,0x02},
+-  0xa3,
+-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+-   0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
+-   0x83,0x85,0x5d,0x28,0x1f,0x63,0xba,0xa3,
+-   0xff},
+-  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+-   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+-   0x08,0x00,0x0f,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+-   0xff}
+- },
+-/* 0x16: MD_3_350 - mode 0x03 - 1 */
+- {
+-  0x50,0x18,0x0e,0x1000,
+-  {0x01,0x03,0x00,0x02},
+-  0xa3,
+-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+-   0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
+-   0x83,0x85,0x5d,0x28,0x1f,0x63,0xba,0xa3,
+-   0xff},
+-  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+-   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+-   0x08,0x00,0x0f,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+-   0xff}
+- },
+-/* 0x17: MD_0_1_400 */
+- {
+-  0x28,0x18,0x10,0x0800,
+-  {0x08,0x03,0x00,0x02},
+-  0x67,
+-  {0x2d,0x27,0x28,0x90,0x2b,0xb1,0xbf,0x1f,
+-   0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,
+-   0x9c,0x8e,0x8f,0x14,0x1f,0x96,0xb9,0xa3,
+-   0xff},
+-  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+-   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+-   0x0c,0x00,0x0f,0x08},
+-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+-   0xff}
+- },
+-/* 0x18: MD_2_3_400 - mode 0x03 - 2 */
+- {
+-  0x50,0x18,0x10,0x1000,
+-  {0x00,0x03,0x00,0x02},
+-  0x67,
+-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+-   0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,
+-   0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,
+-   0xff},
+-  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+-   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+-   0x0c,0x00,0x0f,0x08},
+-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+-   0xff}
+- },
+-/* 0x19: MD_7_400 */
+- {
+-  0x50,0x18,0x10,0x1000,
+-  {0x00,0x03,0x00,0x02},
+-  0x66,
+-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+-   0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,
+-   0x9c,0x8e,0x8f,0x28,0x0f,0x96,0xb9,0xa3,
+-   0xff},
+-  {0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
+-   0x10,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+-   0x0e,0x00,0x0f,0x08},
+-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0a,0x00,
+-   0xff}
+- },
+-/* 0x1a: MD_11 */
+- {
+-  0x50,0x1d,0x10,0xa000,
+-  {0x01,0x0f,0x00,0x06},
+-  0xe3,
+-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e,
+-   0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
+-   0xe9,0x8b,0xdf,0x28,0x00,0xe7,0x04,0xc3,
+-   0xff},
+-  {0x00,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,
+-   0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,
+-   0x01,0x00,0x0f,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x01,
+-   0xff}
+- },
+-/* 0x1b: ExtEGATable - Modes <= 0x02 */
+- {
+-  0x50,0x1d,0x10,0xa000,
+-  {0x01,0x0f,0x00,0x06},
+-  0xe3,
+-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e,
+-   0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
+-   0xe9,0x8b,0xdf,0x28,0x00,0xe7,0x04,0xe3,
+-   0xff},
+-  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+-   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+-   0x01,0x00,0x0f,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
+-   0xff}
+- },
+-/* 0x1c: MD_13 */
+- {
+-  0x28,0x18,0x08,0x2000,
+-  {0x01,0x0f,0x00,0x0e},
+-  0x63,
+-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+-   0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,
+-   0x9c,0x8e,0x8f,0x28,0x40,0x96,0xb9,0xa3,
+-   0xff},
+-  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+-   0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
+-   0x41,0x00,0x0f,0x00},
+-  {0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
+-   0xff}
+- }
+-};
+-
+ typedef struct _SiS310_ExtStruct
+ {
+       UCHAR Ext_ModeID;
+       USHORT Ext_ModeFlag;
+       USHORT Ext_ModeInfo;
+-      USHORT Ext_Point;    /* TW: Address of table entry in (older) BIOS image */
+       USHORT Ext_VESAID;
+-      UCHAR Ext_VESAMEMSize;
+       UCHAR Ext_RESINFO;
+       UCHAR VB_ExtTVFlickerIndex;
+       UCHAR VB_ExtTVEdgeIndex;
+@@ -506,93 +82,93 @@ typedef struct _SiS310_ExtStruct
+       UCHAR REFindex;
+ } SiS310_ExtStruct;
+-/* TW: Checked with 650/LVDS and 650/301LVx 1.10.6s */
+ static const SiS310_ExtStruct  SiS310_EModeIDTable[]=
+ {
+-      {0x6a,0x2212,0x0407,0x3a81,0x0102,0x08,0x07,0x00,0x00,0x07,0x00},          /* 800x600x? */
+-      {0x2e,0x0a1b,0x0306,0x3a57,0x0101,0x08,0x06,0x00,0x00,0x05,0x08},          /* 640x480x8 */
+-/*    {0x2e,0x021b,0x0306,0x3a57,0x0101,0x08,0x06,0x00,0x00,0x05,0x08},    */    /* 640x480x8 - 650/LVDS BIOS (no CRt2Mode) */
+-      {0x2f,0x0a1b,0x0305,0x3a50,0x0100,0x08,0x05,0x00,0x00,0x05,0x10},          /* 640x400x8 */
+-/*    {0x2f,0x021b,0x0305,0x3a50,0x0100,0x08,0x05,0x00,0x00,0x05,0x10},    */    /* 640x400x8 - 650/LVDS BIOS (no CRt2Mode) */
+-      {0x30,0x2a1b,0x0407,0x3a81,0x0103,0x08,0x07,0x00,0x00,0x07,0x00},          /* 800x600x8 */
+-/*    {0x30,0x221b,0x0407,0x3a81,0x0103,0x08,0x07,0x00,0x00,0x07,0x00},    */    /* 800x600x8 - 650/LVDS BIOS (no CRt2Mode) */
+-/*      {0x31,0x0a1b,0x030d,0x3b85,0x0000,0x08,0x0d,0x00,0x00,0x06,0x11},    */    /* 720x480x8 */
+-        {0x31,0x0a1b,0x0a0d,0x3b85,0x0000,0x08,0x0d,0x00,0x00,0x06,0x11},          /* 720x480x8 BIOS (301/LVDS) */
+-      {0x32,0x0a1b,0x0a0e,0x3b8c,0x0000,0x08,0x0e,0x00,0x00,0x06,0x12},          /* 720x576x8 */
+-      {0x33,0x0a1d,0x0a0d,0x3b85,0x0000,0x08,0x0d,0x00,0x00,0x06,0x11},          /* 720x480x16 */
+-      {0x34,0x2a1d,0x0a0e,0x3b8c,0x0000,0x08,0x0e,0x00,0x00,0x06,0x12},          /* 720x576x16 */
+-      {0x35,0x0a1f,0x0a0d,0x3b85,0x0000,0x08,0x0d,0x00,0x00,0x06,0x11},          /* 720x480x32 */
+-      {0x36,0x2a1f,0x0a0e,0x3b8c,0x0000,0x08,0x0e,0x00,0x00,0x06,0x12},          /* 720x576x32 */
+-      {0x37,0x0212,0x0508,0x3aab,0x0104,0x08,0x08,0x00,0x00,0x08,0x13},          /* 1024x768x? */
+-      {0x38,0x0a1b,0x0508,0x3aab,0x0105,0x08,0x08,0x00,0x00,0x08,0x13},          /* 1024x768x8 */
+-      {0x3a,0x0e3b,0x0609,0x3adc,0x0107,0x08,0x09,0x00,0x00,0x00,0x1a},          /* 1280x1024x8 */
+-      {0x3c,0x0e3b,0x070a,0x3af2,0x0130,0x08,0x0a,0x00,0x00,0x00,0x1e},          /* 1600x1200x8 */
+-      {0x3d,0x0e7d,0x070a,0x3af2,0x0131,0x08,0x0a,0x00,0x00,0x00,0x1e},          /* 1600x1200x16 - 650/301LVx - no CRT2Mode? */
+-      {0x40,0x9a1c,0x0000,0x3a34,0x010d,0x08,0x00,0x00,0x00,0x04,0x25},
+-      {0x41,0x9a1d,0x0000,0x3a34,0x010e,0x08,0x00,0x00,0x00,0x04,0x25},
+-      {0x43,0x0a1c,0x0306,0x3a57,0x0110,0x08,0x06,0x00,0x00,0x05,0x08},
+-      {0x44,0x0a1d,0x0306,0x3a57,0x0111,0x08,0x06,0x00,0x00,0x05,0x08},          /* 640x480x16 */
+-      {0x46,0x2a1c,0x0407,0x3a81,0x0113,0x08,0x07,0x00,0x00,0x07,0x00},
+-      {0x47,0x2a1d,0x0407,0x3a81,0x0114,0x08,0x07,0x00,0x00,0x07,0x00},          /* 800x600x16 */
+-      {0x49,0x0a3c,0x0508,0x3aab,0x0116,0x08,0x08,0x00,0x00,0x00,0x13},
+-      {0x4a,0x0a3d,0x0508,0x3aab,0x0117,0x08,0x08,0x00,0x00,0x08,0x13},          /* 1024x768x16 */
+-      {0x4c,0x0e7c,0x0609,0x3adc,0x0119,0x08,0x09,0x00,0x00,0x00,0x1a},
+-      {0x4d,0x0e7d,0x0609,0x3adc,0x011a,0x08,0x09,0x00,0x00,0x00,0x1a},          /* 1280x1024x16 */
+-      {0x50,0x9a1b,0x0001,0x3a3b,0x0132,0x08,0x01,0x00,0x00,0x04,0x26},          /* 320x240 */
+-      {0x51,0xba1b,0x0103,0x3a42,0x0133,0x08,0x03,0x00,0x00,0x07,0x27},
+-      {0x52,0xba1b,0x0204,0x3a49,0x0134,0x08,0x04,0x00,0x00,0x00,0x28},          /* 650/301 BIOS */
+-      {0x56,0x9a1d,0x0001,0x3a3b,0x0135,0x08,0x01,0x00,0x00,0x04,0x26},
+-      {0x57,0xba1d,0x0103,0x3a42,0x0136,0x08,0x03,0x00,0x00,0x07,0x27},
+-      {0x58,0xba1d,0x0204,0x3a49,0x0137,0x08,0x04,0x00,0x00,0x00,0x28},          /* BIOS (301+LVDS) */
+-      {0x59,0x9a1b,0x0000,0x3a34,0x0138,0x08,0x00,0x00,0x00,0x04,0x25},          /* 320x200 */
+-      {0x5A,0x021b,0x0014,0x3b83,0x0138,0x08,0x01,0x00,0x00,0x04,0x3f},          /* 320x480x8 fstn add new mode*/
+-      {0x5B,0x0a1d,0x0014,0x3b83,0x0135,0x08,0x01,0x00,0x00,0x04,0x3f},          /* 320x480x16 fstn add new mode*/
+-      {0x5c,0xba1f,0x0204,0x3a49,0x0000,0x08,0x04,0x00,0x00,0x00,0x28},          /* TW: inserted 512x384x32 */
+-      {0x5d,0x0a1d,0x0305,0x3a50,0x0139,0x08,0x05,0x00,0x00,0x07,0x10},
+-      {0x5e,0x0a1f,0x0305,0x3a50,0x0000,0x08,0x05,0x00,0x00,0x07,0x10},          /* TW: Inserted 640x400x32 */
+-      {0x62,0x0a3f,0x0306,0x3a57,0x013a,0x08,0x06,0x00,0x00,0x05,0x08},          /* 640x480x32 */
+-      {0x63,0x2a3f,0x0407,0x3a81,0x013b,0x08,0x07,0x00,0x00,0x07,0x00},          /* 800x600x32 */
+-      {0x64,0x0a7f,0x0508,0x3aab,0x013c,0x08,0x08,0x00,0x00,0x08,0x13},          /* 1024x768x32 */
+-      {0x65,0x0eff,0x0609,0x3adc,0x013d,0x08,0x09,0x00,0x00,0x00,0x1a},          /* 1280x1024x32 */
+-      {0x66,0x0eff,0x070a,0x3af2,0x013e,0x08,0x0a,0x00,0x00,0x00,0x1e},          /* 1600x1200x32 */
+-      {0x68,0x067b,0x080b,0x3b17,0x013f,0x08,0x0b,0x00,0x00,0x00,0x29},          /* 1920x1440x8 */
+-      {0x69,0x06fd,0x080b,0x3b17,0x0140,0x08,0x0b,0x00,0x00,0x00,0x29},          /* 1920x1440x16 */
+-      {0x6b,0x07ff,0x080b,0x3b17,0x0141,0x10,0x0b,0x00,0x00,0x00,0x29},          /* 1920x1440x32 */
+-      {0x6c,0x067b,0x090c,0x3b37,0x0000,0x08,0x0c,0x00,0x00,0x00,0x2f},          /* 2048x1536x8 */
+-      {0x6d,0x06fd,0x090c,0x3b37,0x0000,0x10,0x0c,0x00,0x00,0x00,0x2f},          /* 2048x1536x16 */
+-      {0x6e,0x07ff,0x090c,0x3b37,0x0000,0x10,0x0c,0x00,0x00,0x00,0x2f},          /* 2048x1536x32 */
+-      {0x70,0x2a1b,0x0410,0x3b52,0x0000,0x08,0x10,0x00,0x00,0x07,0x34},          /* 800x480x8 */
+-      {0x71,0x0a1b,0x0511,0x3b63,0x0000,0x08,0x11,0x00,0x00,0x00,0x37},          /* 1024x576x8 */
+-      {0x74,0x0a1d,0x0511,0x3b63,0x0000,0x08,0x11,0x00,0x00,0x00,0x37},          /* 1024x576x16 */
+-      {0x75,0x0a3d,0x0612,0x3b74,0x0000,0x08,0x12,0x00,0x00,0x00,0x3a},          /* 1280x720x16 */
+-      {0x76,0x2a1f,0x0410,0x3b52,0x0000,0x08,0x10,0x00,0x00,0x07,0x34},          /* 800x480x32 */
+-      {0x77,0x0a1f,0x0511,0x3b63,0x0000,0x08,0x11,0x00,0x00,0x00,0x37},          /* 1024x576x32 */
+-      {0x78,0x0a3f,0x0612,0x3b74,0x0000,0x08,0x12,0x00,0x00,0x00,0x3a},          /* 1280x720x32 */
+-      {0x79,0x0a3b,0x0612,0x3b74,0x0000,0x08,0x12,0x00,0x00,0x00,0x3a},          /* 1280x720x8 */
+-      {0x7a,0x2a1d,0x0410,0x3b52,0x0000,0x08,0x10,0x00,0x00,0x07,0x34},          /* 800x480x16 */
+-      {0x7c,0x0e3b,0x060f,0x3ad0,0x0000,0x08,0x0f,0x00,0x00,0x00,0x3d},          /* 1280x960x8 - TW */
+-      {0x7d,0x0e7d,0x060f,0x3ad0,0x0000,0x08,0x0f,0x00,0x00,0x00,0x3d},          /* 1280x960x16 - TW */
+-      {0x7e,0x0eff,0x060f,0x3ad0,0x0000,0x08,0x0f,0x00,0x00,0x00,0x3d},          /* 1280x960x32 - TW */
+-        /* TW: 650/LVDS BIOS new modes */
+-      {0x23,0x0e3b,0x0614,0x36f7,0x0000,0x08,0x14,0x00,0x00,0x00,0x40},          /* 1280x768x8 */
+-      {0x24,0x0e7d,0x0614,0x36f7,0x0000,0x08,0x14,0x00,0x00,0x00,0x40},          /* 1280x768x16 */
+-      {0x25,0x0eff,0x0614,0x36f7,0x0000,0x08,0x14,0x00,0x00,0x00,0x40},          /* 1280x768x32 */
+-      {0x26,0x0e3b,0x0c15,0x36fe,0x0000,0x08,0x15,0x00,0x00,0x00,0x41},          /* 1400x1050x8 */
+-      {0x27,0x0e7d,0x0c15,0x36fe,0x0000,0x08,0x15,0x00,0x00,0x00,0x41},          /* 1400x1050x16 */
+-      {0x28,0x0eff,0x0c15,0x36fe,0x0000,0x08,0x15,0x00,0x00,0x00,0x41},          /* 1400x1050x32*/
+-      {0x29,0x0e1b,0x0d16,0x0000,0x0000,0x08,0x16,0x00,0x00,0x00,0x43},    /* TW: NEW 1152x864 - not in BIOS */
+-      {0x2a,0x0e3d,0x0d16,0x0000,0x0000,0x08,0x16,0x00,0x00,0x00,0x43},
+-      {0x2b,0x0e7f,0x0d16,0x0000,0x0000,0x08,0x16,0x00,0x00,0x00,0x43},
+-      {0x39,0x2a1b,0x0b17,0x0000,0x0000,0x08,0x17,0x00,0x00,0x00,0x45},    /* TW: NEW 848x480 - not in BIOS */
+-      {0x3b,0x2a3d,0x0b17,0x0000,0x0000,0x08,0x17,0x00,0x00,0x00,0x45},
+-      {0x3e,0x2a7f,0x0b17,0x0000,0x0000,0x08,0x17,0x00,0x00,0x00,0x45},
+-      {0x3f,0x2a1b,0x0b13,0x0000,0x0000,0x08,0x13,0x00,0x00,0x00,0x47},    /* TW: NEW 856x480 - not in BIOS */
+-      {0x42,0x2a3d,0x0b13,0x0000,0x0000,0x08,0x13,0x00,0x00,0x00,0x47},
+-      {0x45,0x2a7f,0x0b13,0x0000,0x0000,0x08,0x13,0x00,0x00,0x00,0x47},
+-      {0x48,0x2a1b,0x0e18,0x0000,0x0000,0x08,0x18,0x00,0x00,0x00,0x49},    /* TW: NEW 1360x768 - not in BIOS */
+-      {0x4b,0x2a3d,0x0e18,0x0000,0x0000,0x08,0x18,0x00,0x00,0x00,0x49},
+-      {0x4e,0x2a7f,0x0e18,0x0000,0x0000,0x08,0x18,0x00,0x00,0x00,0x49},
+-      {0xff,0x0000,0x0000,0x0000,0x0000,0x00,0x00,0x00,0x00,0x00,0x00}
++      {0x6a,0x2212,0x0407,0x0102,SIS_RI_800x600,  0x00,0x00,0x07,0x00}, /* 800x600x? */
++      {0x2e,0x0a1b,0x0306,0x0101,SIS_RI_640x480,  0x00,0x00,0x05,0x08}, /* 640x480x8 */
++        {0x2f,0x0a1b,0x0305,0x0100,SIS_RI_640x400,  0x00,0x00,0x05,0x10}, /* 640x400x8 */
++      {0x30,0x2a1b,0x0407,0x0103,SIS_RI_800x600,  0x00,0x00,0x07,0x00}, /* 800x600x8 */
++        {0x31,0x0a1b,0x0a0d,0x0000,SIS_RI_720x480,  0x00,0x00,0x06,0x11}, /* 720x480x8 */
++      {0x32,0x0a1b,0x0a0e,0x0000,SIS_RI_720x576,  0x00,0x00,0x06,0x12}, /* 720x576x8 */
++      {0x33,0x0a1d,0x0a0d,0x0000,SIS_RI_720x480,  0x00,0x00,0x06,0x11}, /* 720x480x16 */
++      {0x34,0x2a1d,0x0a0e,0x0000,SIS_RI_720x576,  0x00,0x00,0x06,0x12}, /* 720x576x16 */
++      {0x35,0x0a1f,0x0a0d,0x0000,SIS_RI_720x480,  0x00,0x00,0x06,0x11}, /* 720x480x32 */
++      {0x36,0x2a1f,0x0a0e,0x0000,SIS_RI_720x576,  0x00,0x00,0x06,0x12}, /* 720x576x32 */
++      {0x37,0x0212,0x0508,0x0104,SIS_RI_1024x768, 0x00,0x00,0x08,0x13}, /* 1024x768x? */
++      {0x38,0x0a1b,0x0508,0x0105,SIS_RI_1024x768, 0x00,0x00,0x08,0x13}, /* 1024x768x8 */
++      {0x3a,0x0e3b,0x0609,0x0107,SIS_RI_1280x1024,0x00,0x00,0x00,0x1a}, /* 1280x1024x8 */
++      {0x3c,0x0e3b,0x070a,0x0130,SIS_RI_1600x1200,0x00,0x00,0x00,0x1e}, /* 1600x1200x8 */
++      {0x3d,0x0e7d,0x070a,0x0131,SIS_RI_1600x1200,0x00,0x00,0x00,0x1e}, /* 1600x1200x16 */
++      {0x40,0x9a1c,0x0000,0x010d,SIS_RI_320x200,  0x00,0x00,0x04,0x25}, /* 320x200x15 */
++      {0x41,0x9a1d,0x0000,0x010e,SIS_RI_320x200,  0x00,0x00,0x04,0x25}, /* 320x200x16 */
++      {0x43,0x0a1c,0x0306,0x0110,SIS_RI_640x480,  0x00,0x00,0x05,0x08},
++      {0x44,0x0a1d,0x0306,0x0111,SIS_RI_640x480,  0x00,0x00,0x05,0x08}, /* 640x480x16 */
++      {0x46,0x2a1c,0x0407,0x0113,SIS_RI_800x600,  0x00,0x00,0x07,0x00},
++      {0x47,0x2a1d,0x0407,0x0114,SIS_RI_800x600,  0x00,0x00,0x07,0x00}, /* 800x600x16 */
++      {0x49,0x0a3c,0x0508,0x0116,SIS_RI_1024x768, 0x00,0x00,0x00,0x13},
++      {0x4a,0x0a3d,0x0508,0x0117,SIS_RI_1024x768, 0x00,0x00,0x08,0x13}, /* 1024x768x16 */
++      {0x4c,0x0e7c,0x0609,0x0119,SIS_RI_1280x1024,0x00,0x00,0x00,0x1a},
++      {0x4d,0x0e7d,0x0609,0x011a,SIS_RI_1280x1024,0x00,0x00,0x00,0x1a}, /* 1280x1024x16 */
++      {0x50,0x9a1b,0x0001,0x0132,SIS_RI_320x240,  0x00,0x00,0x04,0x26}, /* 320x240x8  */
++      {0x51,0xba1b,0x0103,0x0133,SIS_RI_400x300,  0x00,0x00,0x07,0x27}, /* 400x300x8  */
++      {0x52,0xba1b,0x0204,0x0134,SIS_RI_512x384,  0x00,0x00,0x00,0x28}, /* 512x384x8  */
++      {0x56,0x9a1d,0x0001,0x0135,SIS_RI_320x240,  0x00,0x00,0x04,0x26}, /* 320x240x16 */
++      {0x57,0xba1d,0x0103,0x0136,SIS_RI_400x300,  0x00,0x00,0x07,0x27}, /* 400x300x16 */
++      {0x58,0xba1d,0x0204,0x0137,SIS_RI_512x384,  0x00,0x00,0x00,0x28}, /* 512x384x16 */
++      {0x59,0x9a1b,0x0000,0x0138,SIS_RI_320x200,  0x00,0x00,0x04,0x25}, /* 320x200x8  */
++      {0x5a,0x021b,0x0014,0x0138,SIS_RI_320x240,  0x00,0x00,0x04,0x3f}, /* 320x240x8  fstn */
++      {0x5b,0x0a1d,0x0014,0x0135,SIS_RI_320x240,  0x00,0x00,0x04,0x3f}, /* 320x240x16 fstn */
++      {0x5c,0xba1f,0x0204,0x0000,SIS_RI_512x384,  0x00,0x00,0x00,0x28}, /* 512x384x32 */
++      {0x5d,0x0a1d,0x0305,0x0139,SIS_RI_640x400,  0x00,0x00,0x07,0x10},
++      {0x5e,0x0a1f,0x0305,0x0000,SIS_RI_640x400,  0x00,0x00,0x07,0x10}, /* 640x400x32 */
++      {0x62,0x0a3f,0x0306,0x013a,SIS_RI_640x480,  0x00,0x00,0x05,0x08}, /* 640x480x32 */
++      {0x63,0x2a3f,0x0407,0x013b,SIS_RI_800x600,  0x00,0x00,0x07,0x00}, /* 800x600x32 */
++      {0x64,0x0a7f,0x0508,0x013c,SIS_RI_1024x768, 0x00,0x00,0x08,0x13}, /* 1024x768x32 */
++      {0x65,0x0eff,0x0609,0x013d,SIS_RI_1280x1024,0x00,0x00,0x00,0x1a}, /* 1280x1024x32 */
++      {0x66,0x0eff,0x070a,0x013e,SIS_RI_1600x1200,0x00,0x00,0x00,0x1e}, /* 1600x1200x32 */
++      {0x68,0x067b,0x080b,0x013f,SIS_RI_1920x1440,0x00,0x00,0x00,0x29}, /* 1920x1440x8 */
++      {0x69,0x06fd,0x080b,0x0140,SIS_RI_1920x1440,0x00,0x00,0x00,0x29}, /* 1920x1440x16 */
++      {0x6b,0x07ff,0x080b,0x0141,SIS_RI_1920x1440,0x00,0x00,0x00,0x29}, /* 1920x1440x32 */
++      {0x6c,0x067b,0x090c,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x2f}, /* 2048x1536x8 */
++      {0x6d,0x06fd,0x090c,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x2f}, /* 2048x1536x16 */
++      {0x6e,0x07ff,0x090c,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x2f}, /* 2048x1536x32 */
++      {0x70,0x2a1b,0x0410,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x34}, /* 800x480x8 */
++      {0x71,0x0a1b,0x0511,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x37}, /* 1024x576x8 */
++      {0x74,0x0a1d,0x0511,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x37}, /* 1024x576x16 */
++      {0x75,0x0a3d,0x0612,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x3a}, /* 1280x720x16 */
++      {0x76,0x2a1f,0x0410,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x34}, /* 800x480x32 */
++      {0x77,0x0a1f,0x0511,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x37}, /* 1024x576x32 */
++      {0x78,0x0a3f,0x0612,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x3a}, /* 1280x720x32 */
++      {0x79,0x0a3b,0x0612,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x3a}, /* 1280x720x8 */
++      {0x7a,0x2a1d,0x0410,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x34}, /* 800x480x16 */
++      {0x7c,0x0e3b,0x060f,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x3d}, /* 1280x960x8 */
++      {0x7d,0x0e7d,0x060f,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x3d}, /* 1280x960x16 */
++      {0x7e,0x0eff,0x060f,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x3d}, /* 1280x960x32 */
++      {0x23,0x0e3b,0x0614,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x40}, /* 1280x768x8 */
++      {0x24,0x0e7d,0x0614,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x40}, /* 1280x768x16 */
++      {0x25,0x0eff,0x0614,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x40}, /* 1280x768x32 */
++      {0x26,0x0e3b,0x0c15,0x0000,SIS_RI_1400x1050,0x00,0x00,0x00,0x41}, /* 1400x1050x8 */
++      {0x27,0x0e7d,0x0c15,0x0000,SIS_RI_1400x1050,0x00,0x00,0x00,0x41}, /* 1400x1050x16 */
++      {0x28,0x0eff,0x0c15,0x0000,SIS_RI_1400x1050,0x00,0x00,0x00,0x41}, /* 1400x1050x32*/
++      {0x29,0x0e1b,0x0d16,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x43}, /* 1152x864 */
++      {0x2a,0x0e3d,0x0d16,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x43},
++      {0x2b,0x0e7f,0x0d16,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x43},
++      {0x39,0x2a1b,0x0b17,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x45}, /* 848x480 */
++      {0x3b,0x2a3d,0x0b17,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x45},
++      {0x3e,0x2a7f,0x0b17,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x45},
++      {0x3f,0x2a1b,0x0b13,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x47}, /* 856x480 */
++      {0x42,0x2a3d,0x0b13,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x47},
++      {0x45,0x2a7f,0x0b13,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x47},
++      {0x48,0x2a1b,0x0e18,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x49}, /* 1360x768 */
++      {0x4b,0x2a3d,0x0e18,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x49},
++      {0x4e,0x2a7f,0x0e18,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x49},
++      {0x4f,0x9a1f,0x0000,0x0000,SIS_RI_320x200,  0x00,0x00,0x04,0x25}, /* 320x200x32 */
++      {0x53,0x9a1f,0x0001,0x0000,SIS_RI_320x240,  0x00,0x00,0x04,0x26}, /* 320x240x32 */
++      {0x54,0xba1f,0x0103,0x0000,SIS_RI_400x300,  0x00,0x00,0x07,0x27}, /* 400x300x32 */
++      {0x5f,0x2a1b,0x0f0e,0x0000,SIS_RI_768x576,  0x00,0x00,0x00,0x4a}, /* 768x576x8 */
++      {0x60,0x2a1d,0x0f0e,0x0000,SIS_RI_768x576,  0x00,0x00,0x00,0x4a}, /* 768x576x16 */
++      {0x61,0x2a1f,0x0f0e,0x0000,SIS_RI_768x576,  0x00,0x00,0x00,0x4a}, /* 768x576x32 */
++      {0xff,0x0000,0x0000,0x0000,0x00,            0x00,0x00,0x00,0x00}
+ };
+ typedef struct _SiS310_Ext2Struct
+@@ -604,89 +180,87 @@ typedef struct _SiS310_Ext2Struct
+       UCHAR  ModeID;
+       USHORT XRes;
+       USHORT YRes;
+-      USHORT ROM_OFFSET;
+ } SiS310_Ext2Struct;
+ static const SiS310_Ext2Struct SiS310_RefIndex[]=
+ {
+-/*    {0x005f,0x0d,0x03,0x05,0x6a, 800, 600,0x3a81},    0x0 - TW: Patch for Chrontel 7019  */
+-      {0x085f,0x0d,0x03,0x05,0x6a, 800, 600,0x3a81}, /* 0x0 */
+-      {0x0467,0x0e,0x04,0x05,0x6a, 800, 600,0x3a86}, /* 0x1 */
+-      {0x0067,0x0f,0x08,0x48,0x6a, 800, 600,0x3a8b}, /* 0x2 */
+-      {0x0067,0x10,0x07,0x8b,0x6a, 800, 600,0x3a90}, /* 0x3 */
+-      {0x0147,0x11,0x0a,0x00,0x6a, 800, 600,0x3a95}, /* 0x4 */
+-      {0x0147,0x12,0x0d,0x00,0x6a, 800, 600,0x3a9a}, /* 0x5 - 4147 TW: Test sync change */
+-      {0x0047,0x13,0x13,0x00,0x6a, 800, 600,0x3a9f}, /* 0x6 - 4047 */
+-      {0x0047,0x14,0x1c,0x00,0x6a, 800, 600,0x3aa4}, /* 0x7 - 4047 */
+-/*    {0xc05f,0x05,0x00,0x04,0x2e, 640, 480,0x3a57},    0x8 - TW: Patch for Chrontel 7019  */
+-      {0xc85f,0x05,0x00,0x04,0x2e, 640, 480,0x3a57}, /* 0x8 */
+-      {0xc067,0x06,0x02,0x04,0x2e, 640, 480,0x3a5c}, /* 0x9 */
+-      {0xc067,0x07,0x02,0x47,0x2e, 640, 480,0x3a61}, /* 0xa */
+-      {0xc067,0x08,0x03,0x8a,0x2e, 640, 480,0x3a66}, /* 0xb */
+-      {0xc047,0x09,0x05,0x00,0x2e, 640, 480,0x3a6b}, /* 0xc - 4047 */
+-      {0xc047,0x0a,0x09,0x00,0x2e, 640, 480,0x3a70}, /* 0xd - 4047 */
+-      {0xc047,0x0b,0x0e,0x00,0x2e, 640, 480,0x3a75}, /* 0xe - 4047 */
+-      {0xc047,0x0c,0x15,0x00,0x2e, 640, 480,0x3a7a}, /* 0xf */
+-      {0x407f,0x04,0x00,0x00,0x2f, 640, 400,0x3a50}, /* 0x10 */
+-      {0xc00f,0x3c,0x01,0x06,0x31, 720, 480,0x3b85}, /* 0x11 */
+-      {0x000f,0x3d,0x03,0x06,0x32, 720, 576,0x3b8c}, /* 0x12 */
+-      {0x0187,0x15,0x06,0x00,0x37,1024, 768,0x3aab}, /* 0x13 */
+-      {0xc877,0x16,0x0b,0x06,0x37,1024, 768,0x3ab0}, /* 0x14 */
+-      {0xc067,0x17,0x0f,0x49,0x37,1024, 768,0x3ab5}, /* 0x15 */
+-      {0x0267,0x18,0x11,0x00,0x37,1024, 768,0x3aba}, /* 0x16 */
+-      {0x0047,0x19,0x16,0x8c,0x37,1024, 768,0x3abf}, /* 0x17 */
+-      {0x0047,0x1a,0x1b,0x00,0x37,1024, 768,0x3ac4}, /* 0x18 - 4047 */
+-      {0x0007,0x1b,0x1f,0x00,0x37,1024, 768,0x3ac9}, /* 0x19 - 4047 */
+-      {0x0387,0x1c,0x11,0x00,0x3a,1280,1024,0x3adc}, /* 0x1a */
+-      {0x0077,0x1d,0x19,0x07,0x3a,1280,1024,0x3ae1}, /* 0x1b */
+-      {0x0047,0x1e,0x1e,0x00,0x3a,1280,1024,0x3ae6}, /* 0x1c */
+-      {0x0007,0x1f,0x20,0x00,0x3a,1280,1024,0x3aeb}, /* 0x1d */
+-      {0x0027,0x20,0x21,0x09,0x3c,1600,1200,0x3af2}, /* 0x1e */
+-      {0x0007,0x21,0x22,0x00,0x3c,1600,1200,0x3af7}, /* 0x1f */
+-      {0x0007,0x22,0x23,0x00,0x3c,1600,1200,0x3afc}, /* 0x20 */
+-      {0x0007,0x23,0x25,0x00,0x3c,1600,1200,0x3b01}, /* 0x21 */
+-      {0x0007,0x24,0x26,0x00,0x3c,1600,1200,0x3b06}, /* 0x22 */
+-      {0x0007,0x25,0x2c,0x00,0x3c,1600,1200,0x3b0b}, /* 0x23 */
+-      {0x0007,0x26,0x34,0x00,0x3c,1600,1200,0x3b10}, /* 0x24 */
+-      {0x407f,0x00,0x00,0x00,0x40, 320, 200,0x3a34}, /* 0x25 */
+-      {0xc07f,0x01,0x00,0x04,0x50, 320, 240,0x3a3b}, /* 0x26 */
+-      {0x007f,0x02,0x04,0x05,0x51, 400, 300,0x3a42}, /* 0x27 */
+-      {0xc077,0x03,0x0b,0x06,0x52, 512, 384,0x3a49}, /* 0x28 */
+-      {0x8007,0x27,0x27,0x00,0x68,1920,1440,0x3b17}, /* 0x29 */
+-      {0x4007,0x28,0x29,0x00,0x68,1920,1440,0x3b1c}, /* 0x2a */
+-      {0x4007,0x29,0x2e,0x00,0x68,1920,1440,0x3b21}, /* 0x2b */
+-      {0x4007,0x2a,0x30,0x00,0x68,1920,1440,0x3b26}, /* 0x2c */
+-      {0x4007,0x2b,0x35,0x00,0x68,1920,1440,0x3b2b}, /* 0x2d */
+-      {0x4005,0x2c,0x39,0x00,0x68,1920,1440,0x3b30}, /* 0x2e */
+-      {0x4007,0x2d,0x2b,0x00,0x6c,2048,1536,0x3b37}, /* 0x2f */
+-      {0x4007,0x2e,0x31,0x00,0x6c,2048,1536,0x3b3c}, /* 0x30 */
+-      {0x4007,0x2f,0x33,0x00,0x6c,2048,1536,0x3b41}, /* 0x31 */
+-      {0x4007,0x30,0x37,0x00,0x6c,2048,1536,0x3b46}, /* 0x32 */
+-      {0x4005,0x31,0x38,0x00,0x6c,2048,1536,0x3b4b}, /* 0x33 */
+-      {0x0057,0x32,0x40,0x08,0x70, 800, 480,0x3b52}, /* 0x34 */
+-      {0x0047,0x33,0x07,0x08,0x70, 800, 480,0x3b57}, /* 0x35 */
+-      {0x0047,0x34,0x0a,0x08,0x70, 800, 480,0x3b5c}, /* 0x36 */
+-      {0x0057,0x35,0x0b,0x09,0x71,1024, 576,0x3b63}, /* 0x37 */
+-      {0x0047,0x36,0x11,0x09,0x71,1024, 576,0x3b68}, /* 0x38 */
+-      {0x0047,0x37,0x16,0x09,0x71,1024, 576,0x3b6d}, /* 0x39 */
+-      {0x0057,0x38,0x19,0x0a,0x75,1280, 720,0x3b74}, /* 0x3a */
+-      {0x0047,0x39,0x1e,0x0a,0x75,1280, 720,0x3b79}, /* 0x3b */
+-      {0x0007,0x3a,0x20,0x0a,0x75,1280, 720,0x3b7e}, /* 0x3c */
+-      {0x0067,0x3b,0x19,0x08,0x7c,1280, 960,0x3ad0}, /* 0x3d */
+-      {0x0027,0x4c,0x59,0x08,0x7c,1280, 960,0x3ad0}, /* 0x3e */
+-      {0xc07f,0x01,0x00,0x06,0x5a, 320, 480,0x3b83}, /* 0x3f */    /* FSTN mode */
+-        {0x0077,0x42,0x12,0x08,0x23,1280, 768,0x0000}, /* 0x40 */  
+-      {0x0067,0x43,0x4d,0x08,0x26,1400,1050,0x0000}, /* 0x41 */  
+-      {0x0007,0x4b,0x5a,0x08,0x26,1400,1050,0x0000}, /* 0x42 */    /* TW: new, not in any BIOS */
+-      {0x0047,0x44,0x19,0x00,0x29,1152, 864,0x0000}, /* 0x43 TW: Non-BIOS, new */
+-      {0x0047,0x4a,0x1e,0x00,0x29,1152, 864,0x0000}, /* 0x44 TW: Non-BIOS, new */
+-      {0x00c7,0x45,0x57,0x00,0x39, 848, 480,0x0000}, /* 0x45 TW: 848x480-38Hzi - Non-BIOS, new */
+-      {0xc047,0x46,0x55,0x00,0x39, 848, 480,0x0000}, /* 0x46 TW: 848x480-60Hz  - Non-BIOS, new */
+-      {0x00c7,0x47,0x57,0x00,0x3f, 856, 480,0x0000}, /* 0x47 TW: 856x480-38Hzi - Non-BIOS, new */
+-      {0xc047,0x48,0x57,0x00,0x3f, 856, 480,0x0000}, /* 0x48 TW: 856x480-60Hz  - Non-BIOS, new */
+-      {0x0047,0x49,0x58,0x00,0x48,1360, 768,0x0000}, /* 0x49 TW: 1360x768-60Hz - Non-BIOS, new */
+-      {0xffff,0x00,0x00,0x00,0x00,   0,   0,0x0000}
+-}; 
++      {0x085f,0x0d,0x03,0x05,0x6a, 800, 600}, /* 0x0 */
++      {0x0467,0x0e,0x04,0x05,0x6a, 800, 600}, /* 0x1 */
++      {0x0067,0x0f,0x08,0x48,0x6a, 800, 600}, /* 0x2 */
++      {0x0067,0x10,0x07,0x8b,0x6a, 800, 600}, /* 0x3 */
++      {0x0147,0x11,0x0a,0x00,0x6a, 800, 600}, /* 0x4 */
++      {0x0147,0x12,0x0d,0x00,0x6a, 800, 600}, /* 0x5 - TW: Test sync change */
++      {0x0047,0x13,0x13,0x00,0x6a, 800, 600}, /* 0x6 */
++      {0x0047,0x14,0x1c,0x00,0x6a, 800, 600}, /* 0x7 */
++      {0xc85f,0x05,0x00,0x04,0x2e, 640, 480}, /* 0x8 */
++      {0xc067,0x06,0x02,0x04,0x2e, 640, 480}, /* 0x9 */
++      {0xc067,0x07,0x02,0x47,0x2e, 640, 480}, /* 0xa */
++      {0xc067,0x08,0x03,0x8a,0x2e, 640, 480}, /* 0xb */
++      {0xc047,0x09,0x05,0x00,0x2e, 640, 480}, /* 0xc */
++      {0xc047,0x0a,0x09,0x00,0x2e, 640, 480}, /* 0xd */
++      {0xc047,0x0b,0x0e,0x00,0x2e, 640, 480}, /* 0xe */
++      {0xc047,0x0c,0x15,0x00,0x2e, 640, 480}, /* 0xf */
++      {0x407f,0x04,0x00,0x00,0x2f, 640, 400}, /* 0x10 */
++      {0xc00f,0x3c,0x01,0x06,0x31, 720, 480}, /* 0x11 */
++      {0x000f,0x3d,0x03,0x06,0x32, 720, 576}, /* 0x12 */
++      {0x0187,0x15,0x06,0x00,0x37,1024, 768}, /* 0x13 */
++      {0xc877,0x16,0x0b,0x06,0x37,1024, 768}, /* 0x14 */
++      {0xc067,0x17,0x0f,0x49,0x37,1024, 768}, /* 0x15 */
++      {0x0267,0x18,0x11,0x00,0x37,1024, 768}, /* 0x16 */
++      {0x0047,0x19,0x16,0x8c,0x37,1024, 768}, /* 0x17 */
++      {0x0047,0x1a,0x1b,0x00,0x37,1024, 768}, /* 0x18 */
++      {0x0007,0x1b,0x1f,0x00,0x37,1024, 768}, /* 0x19 */
++      {0x0387,0x1c,0x11,0x00,0x3a,1280,1024}, /* 0x1a */
++      {0x0077,0x1d,0x19,0x07,0x3a,1280,1024}, /* 0x1b */
++      {0x0047,0x1e,0x1e,0x00,0x3a,1280,1024}, /* 0x1c */
++      {0x0007,0x1f,0x20,0x00,0x3a,1280,1024}, /* 0x1d */
++      {0x0867,0x20,0x21,0x09,0x3c,1600,1200}, /* 0x1e */
++      {0x0007,0x21,0x22,0x00,0x3c,1600,1200}, /* 0x1f */
++      {0x0007,0x22,0x23,0x00,0x3c,1600,1200}, /* 0x20 */
++      {0x0007,0x23,0x25,0x00,0x3c,1600,1200}, /* 0x21 */
++      {0x0007,0x24,0x26,0x00,0x3c,1600,1200}, /* 0x22 */
++      {0x0007,0x25,0x2c,0x00,0x3c,1600,1200}, /* 0x23 */
++      {0x0007,0x26,0x34,0x00,0x3c,1600,1200}, /* 0x24 */
++      {0x407f,0x00,0x00,0x00,0x40, 320, 200}, /* 0x25 */
++      {0xc07f,0x01,0x00,0x04,0x50, 320, 240}, /* 0x26 */
++      {0x007f,0x02,0x04,0x05,0x51, 400, 300}, /* 0x27 */
++      {0xc077,0x03,0x0b,0x06,0x52, 512, 384}, /* 0x28 */
++      {0x8007,0x27,0x27,0x00,0x68,1920,1440}, /* 0x29 */
++      {0x4007,0x28,0x29,0x00,0x68,1920,1440}, /* 0x2a */
++      {0x4007,0x29,0x2e,0x00,0x68,1920,1440}, /* 0x2b */
++      {0x4007,0x2a,0x30,0x00,0x68,1920,1440}, /* 0x2c */
++      {0x4007,0x2b,0x35,0x00,0x68,1920,1440}, /* 0x2d */
++      {0x4005,0x2c,0x39,0x00,0x68,1920,1440}, /* 0x2e */
++      {0x4007,0x2d,0x2b,0x00,0x6c,2048,1536}, /* 0x2f */
++      {0x4007,0x2e,0x31,0x00,0x6c,2048,1536}, /* 0x30 */
++      {0x4007,0x2f,0x33,0x00,0x6c,2048,1536}, /* 0x31 */
++      {0x4007,0x30,0x37,0x00,0x6c,2048,1536}, /* 0x32 */
++      {0x4005,0x31,0x38,0x00,0x6c,2048,1536}, /* 0x33 */
++      {0x0057,0x32,0x40,0x08,0x70, 800, 480}, /* 0x34 */
++      {0x0047,0x33,0x07,0x08,0x70, 800, 480}, /* 0x35 */
++      {0x0047,0x34,0x0a,0x08,0x70, 800, 480}, /* 0x36 */
++      {0x0057,0x35,0x0b,0x09,0x71,1024, 576}, /* 0x37 */
++      {0x0047,0x36,0x11,0x09,0x71,1024, 576}, /* 0x38 */
++      {0x0047,0x37,0x16,0x09,0x71,1024, 576}, /* 0x39 */
++      {0x0057,0x38,0x19,0x0a,0x75,1280, 720}, /* 0x3a */
++      {0x0047,0x39,0x1e,0x0a,0x75,1280, 720}, /* 0x3b */
++      {0x0007,0x3a,0x20,0x0a,0x75,1280, 720}, /* 0x3c */
++      {0x0067,0x3b,0x19,0x08,0x7c,1280, 960}, /* 0x3d */
++      {0x0027,0x4c,0x59,0x08,0x7c,1280, 960}, /* 0x3e */
++      {0xc07f,0x4e,0x00,0x06,0x5a, 320, 240}, /* 0x3f */    /* FSTN 320x240 */
++        {0x0077,0x42,0x5b,0x08,0x23,1280, 768}, /* 0x40 */    /* TW: 0x5b was 0x12 */
++      {0x0067,0x43,0x4d,0x08,0x26,1400,1050}, /* 0x41 */
++      {0x0007,0x4b,0x5a,0x08,0x26,1400,1050}, /* 0x42 TW: not in any BIOS */
++      {0x0047,0x44,0x19,0x00,0x29,1152, 864}, /* 0x43 TW: Non-BIOS, new */
++      {0x0047,0x4a,0x1e,0x00,0x29,1152, 864}, /* 0x44 TW: Non-BIOS, new */
++      {0x00c7,0x45,0x57,0x00,0x39, 848, 480}, /* 0x45 TW: 848x480-38Hzi - Non-BIOS, new */
++      {0xc067,0x46,0x55,0x0b,0x39, 848, 480}, /* 0x46 TW: 848x480-60Hz  - Non-BIOS, new */
++      {0x00c7,0x47,0x57,0x00,0x3f, 856, 480}, /* 0x47 TW: 856x480-38Hzi - Non-BIOS, new */
++      {0xc047,0x48,0x57,0x00,0x3f, 856, 480}, /* 0x48 TW: 856x480-60Hz  - Non-BIOS, new */
++      {0x0067,0x49,0x58,0x0c,0x48,1360, 768}, /* 0x49 TW: 1360x768-60Hz - Non-BIOS, new */
++      {0x000f,0x4d,0x03,0x06,0x5f, 768, 576}, /* 0x4a TW: 768x576 */
++      {0xffff,0x00,0x00,0x00,0x00,   0,   0}
++};
+ typedef struct _SiS310_CRT1TableStruct
+ {
+@@ -710,7 +284,7 @@ static const SiS310_CRT1TableStruct SiS3
+  {{0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+    0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x05,
+    0x00}}, /* 0x4 */
+-#if 0   
++#if 0
+  {{0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e,
+    0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05,
+    0x00}}, /* 0x5 */
+@@ -940,19 +514,25 @@ static const SiS310_CRT1TableStruct SiS3
+    0x00}},  /* 0x4b */ 
+  {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0xf1,0xff, /* TW: New, 1280x960-85, not in any BIOS */
+    0xc0,0x83,0xbf,0xbf,0xf2,0x10,0x00,0x07,
+-   0x01}}   /* 0x4c */
++   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,
++   0x00}}   /* 0x4e */
+ };
+-
+ typedef struct _SiS310_MCLKDataStruct
+ {
+       UCHAR SR28,SR29,SR2A;
+       USHORT CLOCK;
+ } SiS310_MCLKDataStruct;
++#ifdef LINUXBIOS
+ static const SiS310_MCLKDataStruct SiS310_MCLKData_0_315[] =
+ {
+-      { 0x3b,0x22,0x01,143},   /* TW: Was { 0x5c,0x23,0x01,166}, */
++      { 0x3b,0x22,0x01,143},
+       { 0x5c,0x23,0x01,166},
+       { 0x5c,0x23,0x01,166},
+       { 0x5c,0x23,0x01,166},
+@@ -962,7 +542,7 @@ static const SiS310_MCLKDataStruct SiS31
+       { 0x5c,0x23,0x01,166}
+ };
+-static const SiS310_MCLKDataStruct SiS310_MCLKData_0_650[] =  /* @ 0x54 */
++static const SiS310_MCLKDataStruct SiS310_MCLKData_0_650[] =
+ {
+       { 0x5a,0x64,0x82, 66},
+       { 0xb3,0x45,0x82, 83},
+@@ -973,8 +553,22 @@ static const SiS310_MCLKDataStruct SiS31
+       { 0x37,0x22,0x82,133},
+       { 0x37,0x22,0x82,133}
+ };
++#endif
++
++static const SiS310_MCLKDataStruct SiS310_MCLKData_0_330[] =
++{
++      { 0x5c,0x23,0x01,166},
++      { 0x5c,0x23,0x01,166},
++      { 0x7c,0x08,0x01,200},
++      { 0x79,0x06,0x01,250},
++      { 0x7c,0x08,0x01,200},
++      { 0x7c,0x08,0x01,200},
++      { 0x7c,0x08,0x01,200},
++      { 0x79,0x06,0x01,250}
++};
+-static const SiS310_MCLKDataStruct SiS310_MCLKData_0_330[] =   /* @ 0x54 */
++#ifdef LINUXBIOS
++static const SiS310_MCLKDataStruct SiS310_MCLKData_0_660[] =  /* TODO */
+ {
+       { 0x5c,0x23,0x01,166},
+       { 0x5c,0x23,0x01,166},
+@@ -985,8 +579,9 @@ static const SiS310_MCLKDataStruct SiS31
+       { 0x7c,0x08,0x01,200},
+       { 0x79,0x06,0x01,250}
+ };
++#endif
+-static const SiS310_MCLKDataStruct SiS310_MCLKData_1[] =      /* @ 0x155 */
++static const SiS310_MCLKDataStruct SiS310_MCLKData_1[] =
+ {
+         { 0x29,0x21,0x82,150},
+       { 0x5c,0x23,0x82,166},
+@@ -998,6 +593,7 @@ static const SiS310_MCLKDataStruct SiS31
+       { 0x37,0x22,0x82,133}
+ };
++#ifdef LINUXBIOS
+ typedef struct _SiS310_ECLKDataStruct
+ {
+       UCHAR SR2E,SR2F,SR30;
+@@ -1011,6 +607,7 @@ static const SiS310_ECLKDataStruct SiS31
+       { 0x5c,0x23,0x01,166},
+       { 0x5c,0x23,0x01,166}
+ };
++#endif
+ typedef struct _SiS310_VCLKDataStruct
+ {
+@@ -1020,22 +617,22 @@ typedef struct _SiS310_VCLKDataStruct
+ static const SiS310_VCLKDataStruct SiS310_VCLKData[]=
+ {
+-      { 0x1b,0xe1, 25}, /* 0x0 */   /* 650/LVDS BIOS: @ 0x5647 */
+-      { 0x4e,0xe4, 28}, /* 0x1 */
+-      { 0x57,0xe4, 31}, /* 0x2 */
+-      { 0xc3,0xc8, 36}, /* 0x3 */
+-      { 0x42,0xe2, 40}, /* 0x4 */
+-      { 0xfe,0xcd, 43}, /* 0x5 */
+-      { 0x5d,0xc4, 44}, /* 0x6 */
+-      { 0x52,0xe2, 49}, /* 0x7 */
+-      { 0x53,0xe2, 50}, /* 0x8 */
+-      { 0x74,0x67, 52}, /* 0x9 */
+-      { 0x6d,0x66, 56}, /* 0xa */
+-      { 0x5a,0x64, 65}, /* 0xb */   /* TW: was 6c c3 - WRONG */
+-      { 0x46,0x44, 67}, /* 0xc */
+-      { 0xb1,0x46, 68}, /* 0xd */
+-      { 0xd3,0x4a, 72}, /* 0xe */
+-      { 0x29,0x61, 75}, /* 0xf */
++      { 0x1b,0xe1, 25}, /* 0x00 */
++      { 0x4e,0xe4, 28}, /* 0x01 */
++      { 0x57,0xe4, 31}, /* 0x02 */
++      { 0xc3,0xc8, 36}, /* 0x03 */
++      { 0x42,0xe2, 40}, /* 0x04 */
++      { 0xfe,0xcd, 43}, /* 0x05 */
++      { 0x5d,0xc4, 44}, /* 0x06 */
++      { 0x52,0xe2, 49}, /* 0x07 */
++      { 0x53,0xe2, 50}, /* 0x08 */
++      { 0x74,0x67, 52}, /* 0x09 */
++      { 0x6d,0x66, 56}, /* 0x0a */
++      { 0x5a,0x64, 65}, /* 0x0b */  /* TW: was 6c c3 - WRONG */
++      { 0x46,0x44, 67}, /* 0x0c */
++      { 0xb1,0x46, 68}, /* 0x0d */
++      { 0xd3,0x4a, 72}, /* 0x0e */
++      { 0x29,0x61, 75}, /* 0x0f */
+       { 0x6e,0x46, 76}, /* 0x10 */
+       { 0x2b,0x61, 78}, /* 0x11 */
+       { 0x31,0x42, 79}, /* 0x12 */
+@@ -1045,7 +642,7 @@ static const SiS310_VCLKDataStruct SiS31
+       { 0x62,0x44, 94}, /* 0x16 */
+       { 0x2b,0x41,104}, /* 0x17 */
+       { 0x3a,0x23,105}, /* 0x18 */
+-      { 0x70,0x44,108}, /* 0x19 */
++      { 0x70,0x44,108}, /* 0x19 */  /* 1400x1050 LCD */
+       { 0x3c,0x23,109}, /* 0x1a */
+       { 0x5e,0x43,113}, /* 0x1b */
+       { 0xbc,0x44,116}, /* 0x1c */
+@@ -1078,12 +675,12 @@ static const SiS310_VCLKDataStruct SiS31
+       { 0xea,0x08,340}, /* 0x37 */
+       { 0xe8,0x07,376}, /* 0x38 */
+       { 0xde,0x06,389}, /* 0x39 */
+-      { 0x52,0x2a, 54}, /* 0x3a */
+-      { 0x52,0x6a, 27}, /* 0x3b */
+-      { 0x62,0x24, 70}, /* 0x3c */
+-      { 0x62,0x64, 70}, /* 0x3d */
+-      { 0xa8,0x4c, 30}, /* 0x3e */
+-      { 0x20,0x26, 33}, /* 0x3f */
++      { 0x52,0x2a, 54}, /* 0x3a */  /* 301 TV */
++      { 0x52,0x6a, 27}, /* 0x3b */  /* 301 TV */
++      { 0x62,0x24, 70}, /* 0x3c */  /* 301 TV */
++      { 0x62,0x64, 70}, /* 0x3d */  /* 301 TV */
++      { 0xa8,0x4c, 30}, /* 0x3e */  /* 301 TV */
++      { 0x20,0x26, 33}, /* 0x3f */  /* 301 TV */
+       { 0x31,0xc2, 39}, /* 0x40 */
+       { 0x60,0x36, 30}, /* 0x41 */  /* Chrontel */
+       { 0x40,0x4a, 28}, /* 0x42 */  /* Chrontel */
+@@ -1096,7 +693,7 @@ static const SiS310_VCLKDataStruct SiS31
+       { 0xce,0x3c, 39}, /* 0x49 */
+       { 0x52,0x4a, 36}, /* 0x4a */  /* Chrontel */
+       { 0x34,0x61, 95}, /* 0x4b */
+-      { 0x78,0x27,108}, /* 0x4c - was 102 */  /* TW: Last entry in 650/301 BIOS */
++      { 0x78,0x27,108}, /* 0x4c - was 102 */
+       { 0x66,0x43,123}, /* 0x4d */  /* Modes 0x26-0x28 (1400x1050) */
+       { 0x41,0x4e, 21}, /* 0x4e */
+       { 0xa1,0x4a, 29}, /* 0x4f */  /* Chrontel */
+@@ -1110,7 +707,8 @@ static const SiS310_VCLKDataStruct SiS31
+       { 0xbf,0xc8, 35}, /* 0x57 - added for 856x480-38i,60 (not in any BIOS) */
+       { 0x30,0x23, 88}, /* 0x58 - added for 1360x768-62 (is 60Hz!) (not in any BIOS) */
+       { 0x52,0x07,149}, /* 0x59 - added for 1280x960-85 (Not in any BIOS) */
+-      { 0x56,0x07,156}  /* 0x5a - added for 1400x1050-75 */
++      { 0x56,0x07,156}, /* 0x5a - added for 1400x1050-75 */
++      { 0x70,0x29, 81}  /* 0x5b */  /* 1280x768 LCD */
+ };
+ typedef struct _SiS310_VBVCLKDataStruct
+@@ -1121,22 +719,22 @@ typedef struct _SiS310_VBVCLKDataStruct
+ static const SiS310_VBVCLKDataStruct SiS310_VBVCLKData[]=
+ {
+-      { 0x1b,0xe1, 25}, /* 0x0 */   /* 650/LVDS BIOS: @ 0x579c */
+-      { 0x4e,0xe4, 28}, /* 0x1 */
+-      { 0x57,0xe4, 31}, /* 0x2 */
+-      { 0xc3,0xc8, 36}, /* 0x3 */
+-      { 0x42,0x47, 40}, /* 0x4 */
+-      { 0xfe,0xcd, 43}, /* 0x5 */
+-      { 0x5d,0xc4, 44}, /* 0x6 */
+-      { 0x52,0x47, 49}, /* 0x7 */
+-      { 0x53,0x47, 50}, /* 0x8 */
+-      { 0x74,0x67, 52}, /* 0x9 */
+-      { 0x6d,0x66, 56}, /* 0xa */
+-      { 0x35,0x62, 65}, /* 0xb */  /* Was 0x5a,0x64 - 650/LVDS+301 bios: 35,62  */
+-      { 0x46,0x44, 67}, /* 0xc */
+-      { 0xb1,0x46, 68}, /* 0xd */
+-      { 0xd3,0x4a, 72}, /* 0xe */
+-      { 0x29,0x61, 75}, /* 0xf */
++      { 0x1b,0xe1, 25}, /* 0x00 */
++      { 0x4e,0xe4, 28}, /* 0x01 */
++      { 0x57,0xe4, 31}, /* 0x02 */
++      { 0xc3,0xc8, 36}, /* 0x03 */
++      { 0x42,0x47, 40}, /* 0x04 */
++      { 0xfe,0xcd, 43}, /* 0x05 */
++      { 0x5d,0xc4, 44}, /* 0x06 */
++      { 0x52,0x47, 49}, /* 0x07 */
++      { 0x53,0x47, 50}, /* 0x08 */
++      { 0x74,0x67, 52}, /* 0x09 */
++      { 0x6d,0x66, 56}, /* 0x0a */
++      { 0x35,0x62, 65}, /* 0x0b */  /* Was 0x5a,0x64 - 650/LVDS+301 bios: 35,62  */
++      { 0x46,0x44, 67}, /* 0x0c */
++      { 0xb1,0x46, 68}, /* 0x0d */
++      { 0xd3,0x4a, 72}, /* 0x0e */
++      { 0x29,0x61, 75}, /* 0x0f */
+       { 0x6d,0x46, 75}, /* 0x10 */
+       { 0x41,0x43, 78}, /* 0x11 */
+       { 0x31,0x42, 79}, /* 0x12 */
+@@ -1146,7 +744,7 @@ static const SiS310_VBVCLKDataStruct SiS
+       { 0x62,0x44, 94}, /* 0x16 */
+       { 0x2b,0x22,104}, /* 0x17 */
+       { 0x49,0x24,105}, /* 0x18 */
+-      { 0xf8,0x2f,108}, /* 0x19 */
++      { 0xf8,0x2f,108}, /* 0x19 */  /* 1400x1050 LCD */
+       { 0x3c,0x23,109}, /* 0x1a */
+       { 0x5e,0x43,113}, /* 0x1b */
+       { 0xbc,0x44,116}, /* 0x1c */
+@@ -1179,19 +777,19 @@ static const SiS310_VBVCLKDataStruct SiS
+       { 0xea,0x08,340}, /* 0x37 */
+       { 0xe8,0x07,376}, /* 0x38 */
+       { 0xde,0x06,389}, /* 0x39 */
+-      { 0x52,0x2a, 54}, /* 0x3a */
+-      { 0x52,0x6a, 27}, /* 0x3b */
+-      { 0x62,0x24, 70}, /* 0x3c */
+-      { 0x62,0x64, 70}, /* 0x3d */
+-      { 0xa8,0x4c, 30}, /* 0x3e */
+-      { 0x20,0x26, 33}, /* 0x3f */
++      { 0x52,0x2a, 54}, /* 0x3a */  /* 301 TV */
++      { 0x52,0x6a, 27}, /* 0x3b */  /* 301 TV */
++      { 0x62,0x24, 70}, /* 0x3c */  /* 301 TV */
++      { 0x62,0x64, 70}, /* 0x3d */  /* 301 TV */
++      { 0xa8,0x4c, 30}, /* 0x3e */  /* 301 TV */
++      { 0x20,0x26, 33}, /* 0x3f */  /* 301 TV */
+       { 0x31,0xc2, 39}, /* 0x40 */
+-      { 0x2e,0x48, 25}, /* 0x41 */
+-      { 0x24,0x46, 25}, /* 0x42 */
+-      { 0x26,0x64, 28}, /* 0x43 */
+-      { 0x37,0x64, 40}, /* 0x44 */
+-      { 0xa1,0x42,108}, /* 0x45 */
+-      { 0x37,0x61,100}, /* 0x46 */
++      { 0x2e,0x48, 25}, /* 0x41 */  /* Replacement for LCD on 315 for index 0 */
++      { 0x24,0x46, 25}, /* 0x42 */  /* Replacement for LCD on 315 for modes 0x01, 0x03, 0x0f, 0x10, 0x12 */
++      { 0x26,0x64, 28}, /* 0x43 */  /* Replacement for LCD on 315 for index 1 */
++      { 0x37,0x64, 40}, /* 0x44 */  /* Replacement for LCD on 315 for index 4 */
++      { 0xa1,0x42,108}, /* 0x45 */  /* 1280x960 LCD */
++      { 0x37,0x61,100}, /* 0x46 */  /* 1280x960 LCD */
+       { 0x78,0x27,108}, /* 0x47 */
+       { 0x97,0x2c, 26}, /* 0x48 */  /* UNUSED - Entries from here new, not in any BIOS */
+       { 0xce,0x3c, 39}, /* 0x49 */  /* UNUSED */
+@@ -1211,72 +809,17 @@ static const SiS310_VBVCLKDataStruct SiS
+       { 0xbf,0xc8, 35}, /* 0x57 */  /* 856x480-38i,60  */
+       { 0x30,0x23, 88}, /* 0x58 */  /* 1360x768-62 (is 60Hz!) TEMP, UNUSED */
+       { 0x52,0x07,149}, /* 0x59 */  /* 1280x960-85  - UNUSED */
+-      { 0x56,0x07,156}  /* 0x5a */  /* 1400x1050-75 - UNUSED */
++      { 0x56,0x07,156}, /* 0x5a */  /* 1400x1050-75 - UNUSED */
++      { 0x70,0x29, 81}  /* 0x5b */  /* 1280x768 LCD */
+ };
+ static const UCHAR SiS310_ScreenOffset[] = 
+ {
+         0x14,0x19,0x20,0x28,0x32,0x40,0x50,0x64,
+-      0x78,0x80,0x2d,0x35,0x57,0x48,0x55,
++      0x78,0x80,0x2d,0x35,0x57,0x48,0x55,0x30,
+       0xff
+-};      /* TW: Added 1400x1050, 1152x864, 848/856x480, 1360x768 */
+-
+-typedef struct _SiS310_StResInfoStruct
+-{
+-      USHORT HTotal;
+-      USHORT VTotal;
+-} SiS310_StResInfoStruct;
+-
+-static const SiS310_StResInfoStruct SiS310_StResInfo[]=
+-{
+-      { 640,400},
+-      { 640,350},
+-      { 720,400},
+-      { 720,350},
+-      { 640,480}
+-};
+-
+-typedef struct _SiS310_ModeResInfoStruct
+-{
+-      USHORT HTotal;
+-      USHORT VTotal;
+-      UCHAR  XChar;
+-      UCHAR  YChar;
+-} SiS310_ModeResInfoStruct;
+-
+-static const SiS310_ModeResInfoStruct SiS310_ModeResInfo[] =
+-{
+-      {  320, 200, 8, 8},   /* 0x00 */
+-      {  320, 240, 8, 8},   /* 0x01 */
+-      {  320, 400, 8, 8},   /* 0x02 */
+-      {  400, 300, 8, 8},   /* 0x03 */
+-      {  512, 384, 8, 8},   /* 0x04 */
+-      {  640, 400, 8,16},   /* 0x05 */
+-      {  640, 480, 8,16},   /* 0x06 */
+-      {  800, 600, 8,16},   /* 0x07 */
+-      { 1024, 768, 8,16},   /* 0x08 */
+-      { 1280,1024, 8,16},   /* 0x09 */
+-      { 1600,1200, 8,16},   /* 0x0a */
+-      { 1920,1440, 8,16},   /* 0x0b */
+-      { 2048,1536, 8,16},   /* 0x0c */
+-      {  720, 480, 8,16},   /* 0x0d */
+-      {  720, 576, 8,16},   /* 0x0e */
+-      { 1280, 960, 8,16},   /* 0x0f */
+-      {  800, 480, 8,16},   /* 0x10 */
+-      { 1024, 576, 8,16},   /* 0x11 */
+-      { 1280, 720, 8,16},   /* 0x12 */
+-      {  856, 480, 8,16},   /* 0x13 - TW: New, not in any BIOS */
+-      { 1280, 768, 8,16},   /* 0x14 20; TW: New */
+-      { 1400,1050, 8,16},   /* 0x15 21; TW: New */
+-      { 1152, 864, 8,16},   /* 0x16 - TW: New, not in any BIOS */
+-      {  848, 480, 8,16},   /* 0x17 - TW: New, not in any BIOS */
+-      { 1360, 768, 8,16}    /* 0x18 - TW: New, not in any BIOS */
+ };
+-static const UCHAR SiS310_OutputSelect = 0x40;
+-
+-static const UCHAR SiS310_SoftSetting  = 0x30;   /* TW: RAM setting */
+-
+ static const UCHAR SiS310_SR15[8][4]={
+       {0x00,0x04,0x60,0x60},
+       {0x0f,0x0f,0x0f,0x0f},
+@@ -1322,16 +865,6 @@ static const USHORT SiS310_VideoSenseDat
+ static const USHORT SiS310_YCSenseData2    = 0x016b;
+ #endif
+-static const UCHAR SiS310_NTSCPhase[]    = {0x21,0xed,0xba,0x08};  /* TW: Was {0x21,0xed,0x8a,0x08}; */
+-static const UCHAR SiS310_PALPhase[]     = {0x2a,0x05,0xe3,0x00};  /* TW: Was {0x2a,0x05,0xd3,0x00}; */
+-static const UCHAR SiS310_PALMPhase[]    = {0x21,0xE4,0x2E,0x9B};  /* TW: palm*/
+-static const UCHAR SiS310_PALNPhase[]    = {0x21,0xF4,0x3E,0xBA};  /* TW: paln*/
+-static const UCHAR SiS310_NTSCPhase2[]   = {0x21,0xF0,0x7B,0xD6};
+-static const UCHAR SiS310_PALPhase2[]    = {0x2a,0x09,0x86,0xe9};
+-static const UCHAR SiS310_PALMPhase2[]   = {0x21,0xE6,0xEF,0xA4};  /* TW: palm 301b*/
+-static const UCHAR SiS310_PALNPhase2[]   = {0x21,0xF6,0x94,0x46};  /* TW: paln 301b*/
+-static const UCHAR SiS310_SpecialPhase[] = {0x1e,0x8c,0x5c,0x7a};
+-
+ typedef struct _SiS310_LCDDataStruct
+ {
+       USHORT RVBHCMAX;
+@@ -1353,25 +886,6 @@ static const SiS310_LCDDataStruct  SiS31
+       {    1,   1,1344, 806,1344, 806}
+ };
+-#if 0   /* Seems out-dated, all BIOSes since 03/27/2002 have the other version */
+-static const SiS310_LCDDataStruct  SiS310_ExtLCD1024x768Data[] = 
+-{
+-      {   12,   5, 896, 512,1344, 806},
+-      {   12,   5, 896, 510,1344, 806},
+-      {   32,  15,1008, 505,1344, 806},
+-      {   32,  15,1008, 514,1344, 806},
+-      {   12,   5, 896, 500,1344, 806},
+-      {   42,  25,1024, 625,1344, 806},
+-      {    1,   1,1344, 806,1344, 806},
+-      {   12,   5, 896, 500,1344, 806},
+-      {   42,  25,1024, 625,1344, 806},
+-      {    1,   1,1344, 806,1344, 806},
+-      {   12,   5, 896, 500,1344, 806},
+-      {   42,  25,1024, 625,1344, 806},
+-      {    1,   1,1344, 806,1344, 806}
+-};
+-#endif
+-
+ static const SiS310_LCDDataStruct  SiS310_ExtLCD1024x768Data[] =   
+ {
+       {   42,  25,1536, 419,1344, 806},
+@@ -1413,7 +927,7 @@ static const SiS310_LCDDataStruct  SiS31
+       {    1,   1,1688,1066,1688,1066}
+ };
+-static const SiS310_LCDDataStruct  SiS310_ExtLCD1280x1024Data[] = 
++static const SiS310_LCDDataStruct  SiS310_ExtLCD1280x1024Data[] =
+ {
+       {  211,  60,1024, 501,1688,1066},
+       {  211,  60,1024, 508,1688,1066},
+@@ -1450,7 +964,7 @@ static const SiS310_LCDDataStruct  SiS31
+       {    1,   1,1344, 806,1344, 806}
+ };
+-static const SiS310_LCDDataStruct  SiS310_NoScaleData1280x1024[] =  
++static const SiS310_LCDDataStruct  SiS310_NoScaleData1280x1024[] =
+ {
+         {    1,   1,1688,1066,1688,1066},
+       {    1,   1,1688,1066,1688,1066},
+@@ -1463,272 +977,15 @@ static const SiS310_LCDDataStruct  SiS31
+       {    1,   1,1688,1066,1688,1066}
+ };
+-static const SiS310_LCDDataStruct  SiS310_LCD1280x960Data[] =
+-{
+-      {    9,   2, 800, 500,1800,1000},
+-      {    9,   2, 800, 500,1800,1000},
+-      {    4,   1, 900, 500,1800,1000},
+-      {    4,   1, 900, 500,1800,1000},
+-      {    9,   2, 800, 500,1800,1000},
+-      {   30,  11,1056, 625,1800,1000},
+-      {    5,   3,1350, 800,1800,1000},
+-      {    1,   1,1576,1050,1576,1050},
+-      {    1,   1,1800,1000,1800,1000}
+-};
+-
+-static const SiS310_LCDDataStruct  SiS310_StLCD1400x1050Data[] = 
+-{  /* TW: New from 1.11.6s */
+-      { 211,  100, 2100,  408, 1688, 1066 },
+-      { 211,   64, 1536,  358, 1688, 1066 },
+-      { 211,  100, 2100,  408, 1688, 1066 },
+-      { 211,   64, 1536,  358, 1688, 1066 },
+-      { 211,   48,  840,  488, 1688, 1066 },
+-      { 211,   72, 1008,  609, 1688, 1066 },
+-      { 211,  128, 1400,  776, 1688, 1066 },
+-      { 211,  205, 1680, 1041, 1688, 1066 },
+-      {   1,    1, 1688, 1066, 1688, 1066 }
+-};
+-
+-static const SiS310_LCDDataStruct  SiS310_ExtLCD1400x1050Data[] = 
+-{  /* TW: New from 1.11.6s */
+-      { 211,  100, 2100,  408, 1688, 1066 },
+-      { 211,   64, 1536,  358, 1688, 1066 },
+-      { 211,  100, 2100,  408, 1688, 1066 },
+-      { 211,   64, 1536,  358, 1688, 1066 },
+-      { 211,   48,  840,  488, 1688, 1066 },
+-      { 211,   72, 1008,  609, 1688, 1066 },
+-      { 211,  128, 1400,  776, 1688, 1066 },
+-      { 211,  205, 1680, 1041, 1688, 1066 },
+-      {   1,    1, 1688, 1066, 1688, 1066 }
+-};
+-
+-static const SiS310_LCDDataStruct  SiS310_NoScaleData1400x1050[] = 
+-{  /* TW: To be checked (BIOS uses 1280x1024 data, one line too short) */
+-      { 1, 1, 1688, 1066, 1688, 1066 },
+-      { 1, 1, 1688, 1066, 1688, 1066 },
+-      { 1, 1, 1688, 1066, 1688, 1066 },
+-      { 1, 1, 1688, 1066, 1688, 1066 },
+-      { 1, 1, 1688, 1066, 1688, 1066 },
+-      { 1, 1, 1688, 1066, 1688, 1066 },
+-      { 1, 1, 1688, 1066, 1688, 1066 },
+-      { 1, 1, 1688, 1066, 1688, 1066 },
+-      { 1, 1, 1688, 1066, 1688, 1066 }
+-};
+-
+-static const SiS310_LCDDataStruct  SiS310_StLCD1600x1200Data[] = 
+-{  /* TODO */
+-      {    0,   0,   0,   0,   0,   0}
+-};
+-
+-static const SiS310_LCDDataStruct  SiS310_ExtLCD1600x1200Data[] = 
+-{  /* TODO */
+-      {    0,   0,   0,   0,   0,   0}
+-};
+-
+-static const SiS310_LCDDataStruct  SiS310_NoScaleData1600x1200[] = 
+-{  /* TODO */
+-      {    0,   0,   0,   0,   0,   0}
+-};
+-
+-typedef struct _SiS310_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;
+-} SiS310_TVDataStruct;
+-
+-static const SiS310_TVDataStruct  SiS310_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}
+-};
+-
+-static const SiS310_TVDataStruct  SiS310_ExtPALData[] =   
+-{
+- {   27,  10, 848, 448,1270, 530,  50,   0,  50,0xf4,0xff,0x1c,0x22},
+- {  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 */
+- {   36,  25,1060, 648,1316, 530, 438,   0, 438,0xeb,0x05,0x25,0x16},  /* 800x600 */
+- {    3,   2,1080, 619,1270, 540, 438,   0, 438,0xf3,0x00,0x1d,0x20},  /* 720x480/576 */
+- {    1,   1,1170, 821,1270, 520, 686,   0, 686,0xF3,0x00,0x1D,0x20}   /* 1024x768 */
+-};
+-
+-static const SiS310_TVDataStruct  SiS310_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}
+-};
+-
+-static const SiS310_TVDataStruct  SiS310_ExtNTSCData[]=
+-{
+- {  143,  65, 858, 443,1270, 440, 171,   0, 171,0xf1,0x04,0x1f,0x18},
+- {   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 */
+- {  143, 120,1056, 643,1270, 440,   0, 128,   0,0xf4,0x10,0x1c,0x00},  /* 800x600  */
+- {    2,   1, 858, 503,1270, 480,   0, 128,   0,0xee,0x0c,0x22,0x08},  /* 720x480/576 */
+- {   65,  64,1056, 791,1270, 480, 638,   0,   0,0xEE,0x0C,0x22,0x08}   /* 1024x768 */
+-};
+-
+-#if 0
+-static const SiS310_TVDataStruct  SiS310_St1HiTVData[]=
+-{
+-  
+-};
+-#endif
+-
+-static const SiS310_TVDataStruct  SiS310_St2HiTVData[]=
+-{
+- {    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, 0x3e8,0x233,0x311,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}
+-};
+-
+-static const SiS310_TVDataStruct  SiS310_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},
+- {    3,   1, 0x348,0x1e3,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},
+- {   16,   5, 0x41a,0x2ab,0x670,0x3c0,0x143,128, 0, 0x00,0x00,0x00,0x00},
+- {   25,  12, 0x4ec,0x353,0x670,0x3c0,0x032,  0, 0, 0x00,0x00,0x00,0x00},
+- {    5,   4, 0x627,0x464,0x670,0x3c0,0x128,  0, 0, 0x00,0x00,0x00,0x00},
+- {    4,   1, 0x41a,0x233,0x670,0x3c0,0x143,128, 0, 0x00,0x00,0x00,0x00},
+- {    5,   2, 0x578,0x293,0x670,0x3c0,0x032,  0, 0, 0x00,0x00,0x00,0x00},
+- {    8,   5, 0x6d6,0x323,0x670,0x3c0,0x128,  0, 0, 0x00,0x00,0x00,0x00}
+-};
+-
+-static const UCHAR SiS310_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,
+-      0x0c,0x50,0x00,0x97,0x00,0xda,0x4a,0x17,
+-      0x7d,0x05,0x4b,0x00,0x00,0xe2,0x00,0x02,
+-      0x03,0x0a,0x65,0x9d,0x08,0x92,0x8f,0x40,
+-      0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x50,
+-      0x00,0x40,0x44,0x00,0xdb,0x02,0x3b,0x00
+-};
+-
+-static const UCHAR SiS310_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,
+-      0x70,0x50,0x00,0x9b,0x00,0xd9,0x5d,0x17,
+-      0x7d,0x05,0x45,0x00,0x00,0xe8,0x00,0x02,
+-      0x0d,0x00,0x68,0xb0,0x0b,0x92,0x8f,0x40,
+-      0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x63,
+-      0x00,0x40,0x3e,0x00,0xe1,0x02,0x28,0x00
+-};
+-
+-static const UCHAR SiS310_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,
+-      0x2a,0xde,0x2a,0x44,0x40,0x2a,0x44,0x40,
+-      0x8e,0x8e,0x82,0x07,0x0b,0x92,0x0f,0x40,
+-      0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x3d,
+-      0x63,0x4f,0x27,0x00,0xfc,0xff,0x6a,0x00
+-};
+-
+-static const UCHAR SiS310_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,
+-      0x11,0x15,0x11,0xcf,0x10,0x11,0xcf,0x10,
+-      0x35,0x35,0x3b,0x69,0x1d,0x92,0x0f,0x40,
+-      0x60,0x80,0x14,0x90,0x8c,0x60,0x04,0x86,
+-      0xaf,0x5d,0x0e,0x00,0xfc,0xff,0x2d,0x00
+-};
+-
+-static const UCHAR SiS310_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,
+-      0x2a,0xde,0x2a,0x44,0x40,0x2a,0x44,0x40,
+-      0x8e,0x8e,0x82,0x07,0x0b,0x92,0x0f,0x40,
+-      0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x3d,
+-      0x63,0x4f,0x27,0x00,0xfc,0xff,0x6a,0x00
+-};
+-
+-static const UCHAR SiS310_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,
+-      0x14,0x78,0x14,0x08,0x20,0x14,0x08,0x20,
+-      0xc8,0xc8,0x3b,0xd2,0x26,0x92,0x0f,0x40,
+-        0x60,0x80,0x14,0x90,0x8c,0x60,0x04,0x96,
+-      0x72,0x5c,0x11,0x00,0xfc,0xff,0x32,0x00
+-};
+-
+-static const UCHAR SiS310_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,
+-      0x56,0x36,0x4f,0x6e,0x3f,0x80,0x00,0x80,
+-      0x4f,0x7f,0x03,0xa8,0x7d,0x20,0x1a,0xa9,
+-      0x14,0x05,0x03,0x7e,0x64,0x31,0x14,0x75,
+-      0x18,0x05,0x18,0x05,0x4c,0xa8,0x01
+-};
+-
+-static const UCHAR SiS310_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,
+-      0x56,0x36,0x4f,0x6e,0x3f,0x80,0x00,0x80,
+-      0x67,0x36,0x01,0x47,0x0e,0x10,0xbe,0xb4,
+-      0x01,0x05,0x03,0x7e,0x65,0x31,0x14,0x75,
+-      0x18,0x05,0x18,0x05,0x4c,0xa8,0x01
+-};
+-
+-static const UCHAR SiS310_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,
+-      0x56,0x36,0x4f,0x6e,0x3f,0x80,0x00,0x80,
+-      0x93,0x3c,0x01,0x50,0x2f,0x10,0xf4,0xca,
+-      0x01,0x05,0x03,0x7e,0x65,0x31,0x14,0x75,
+-      0x18,0x05,0x18,0x05,0x4c,0xa8,0x01
+-};
+ typedef struct _SiS310_PanelDelayTblStruct
+ {
+       UCHAR timer[2];
+ } SiS310_PanelDelayTblStruct;
+-static const SiS310_PanelDelayTblStruct SiS310_PanelDelayTbl[]=  
++static const SiS310_PanelDelayTblStruct SiS310_PanelDelayTbl[]=
+ {
+-        {{0x10,0x40}},                /* TW: from 650/301LVx 1.10.6s BIOS */
++        {{0x10,0x40}},
+       {{0x10,0x40}},
+       {{0x10,0x40}},
+       {{0x10,0x40}},
+@@ -1744,24 +1001,6 @@ static const SiS310_PanelDelayTblStruct 
+       {{0x10,0x40}},
+       {{0x10,0x40}},
+       {{0x10,0x40}}
+-#if 0
+-      {{0x28,0xc8}},          /* TW: from 650/301LV BIOS */
+-      {{0x28,0xc8}},
+-      {{0x28,0xc8}},
+-      {{0x28,0xc8}},
+-      {{0x28,0xc8}},
+-      {{0x28,0xc8}},
+-      {{0x28,0xc8}},
+-      {{0x28,0xc8}},
+-      {{0x28,0xc8}},
+-      {{0x28,0xc8}},
+-      {{0x28,0xc8}},
+-      {{0x28,0xc8}},
+-      {{0x28,0xc8}},
+-      {{0x28,0xc8}},
+-      {{0x28,0xc8}},
+-      {{0x28,0xc8}}
+-#endif
+ };
+ static const SiS310_PanelDelayTblStruct SiS310_PanelDelayTblLVDS[]=
+@@ -1792,363 +1031,7 @@ typedef struct _SiS310_LVDSDataStruct
+       USHORT LCDVT;
+ } SiS310_LVDSDataStruct;
+-static const SiS310_LVDSDataStruct  SiS310_LVDS320x480Data_1[]=
+-{
+-      { 848, 433, 400, 525},
+-      { 848, 389, 400, 525},
+-      { 848, 433, 400, 525},
+-      { 848, 389, 400, 525},
+-      { 848, 518, 400, 525},
+-      {1056, 628, 400, 525},
+-      { 400, 525, 400, 525},
+-      { 800, 449,1000, 644},
+-      { 800, 525,1000, 635}
+-};
+-
+-static const SiS310_LVDSDataStruct  SiS310_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},
+-      { 800, 449,1000, 644},
+-      { 800, 525,1000, 635}
+-};
+-
+-static const SiS310_LVDSDataStruct  SiS310_LVDS800x600Data_2[]=  
+-{
+-      {1056, 628,1056, 628},
+-      {1056, 628,1056, 628},
+-      {1056, 628,1056, 628},
+-      {1056, 628,1056, 628},
+-      {1056, 628,1056, 628},
+-      {1056, 628,1056, 628},
+-      {1056, 628,1056, 628},
+-      { 800, 449,1000, 644},
+-      { 800, 525,1000, 635}
+-};
+-
+-static const SiS310_LVDSDataStruct  SiS310_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 */
+-      { 800, 449,1280, 801},
+-      { 800, 525,1280, 813}
+-};
+-
+-static const SiS310_LVDSDataStruct  SiS310_LVDS1024x768Data_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},
+-      { 800, 449,1280, 801},
+-      { 800, 525,1280, 813}
+-};
+-
+-static const SiS310_LVDSDataStruct  SiS310_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 SiS310_LVDSDataStruct  SiS310_LVDS1280x1024Data_2[]=  
+-{     
+-      {1688,1066,1688,1066},
+-      {1688,1066,1688,1066},
+-      {1688,1066,1688,1066},
+-      {1688,1066,1688,1066},
+-      {1688,1066,1688,1066},
+-      {1688,1066,1688,1066},
+-      {1688,1066,1688,1066},
+-      {1688,1066,1688,1066}
+-};
+-
+-static const SiS310_LVDSDataStruct  SiS310_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 SiS310_LVDSDataStruct  SiS310_LVDS1400x1050Data_2[]= 
+-{
+-        {1688,1066, 1688,1066},
+-      {1688,1066, 1688,1066},
+-      {1688,1066, 1688,1066},
+-      {1688,1066, 1688,1066},
+-      {1688,1066, 1688,1066},
+-      {1688,1066, 1688,1066},
+-      {1688,1066, 1688,1066},
+-      {1688,1066, 1688,1066},
+-      {1688,1066, 1688,1066},
+-};
+-
+-static const SiS310_LVDSDataStruct  SiS310_LVDS1600x1200Data_1[]=  
+-{
+-        {1088, 450, 2048,1250},
+-      {1088, 400, 2048,1250},
+-      {1088, 450, 2048,1250},
+-      {1088, 400, 2048,1250},
+-      {1088, 530, 2048,1250},
+-      {1248, 650, 2048,1250},
+-      {1472, 818, 2048,1250},
+-      {1728,1066, 2048,1250},
+-      {1848,1066, 2048,1250},
+-      {2048,1250, 2048,1250}
+-};
+-
+-static const SiS310_LVDSDataStruct  SiS310_LVDS1600x1200Data_2[]= 
+-{
+-        {2048,1250, 2048,1250},
+-      {2048,1250, 2048,1250},
+-      {2048,1250, 2048,1250},
+-      {2048,1250, 2048,1250},
+-      {2048,1250, 2048,1250},
+-      {2048,1250, 2048,1250},
+-      {2048,1250, 2048,1250},
+-      {2048,1250, 2048,1250},
+-      {2048,1250, 2048,1250},
+-      {2048,1250, 2048,1250}
+-};
+-
+-static const SiS310_LVDSDataStruct  SiS310_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 SiS310_LVDSDataStruct  SiS310_LVDS1280x768Data_2[]=  
+-{     
+-      {1408, 806, 1408, 806},
+-      {1408, 806, 1408, 806},
+-      {1408, 806, 1408, 806},
+-      {1408, 806, 1408, 806},
+-      {1408, 806, 1408, 806},
+-      {1408, 806, 1408, 806},
+-      {1408, 806, 1408, 806},
+-      {1408, 806, 1408, 806},
+-      {1408, 806, 1408, 806}
+-};
+-
+-static const SiS310_LVDSDataStruct  SiS310_LVDS1024x600Data_1[]=
+-{
+-      { 840, 604, 1344, 800},
+-      { 840, 560, 1344, 800},
+-      { 840, 604, 1344, 800},
+-      { 840, 560, 1344, 800},
+-      { 840, 689, 1344, 800},
+-      {1050, 800, 1344, 800},
+-      {1344, 800, 1344, 800},
+-      { 800, 449, 1280, 801},
+-      { 800, 525, 1280, 813}
+-};
+-
+-static const SiS310_LVDSDataStruct  SiS310_LVDS1024x600Data_2[]=
+-{
+-      {1344, 800, 1344, 800},
+-      {1344, 800, 1344, 800},
+-      {1344, 800, 1344, 800},
+-      {1344, 800, 1344, 800},
+-      {1344, 800, 1344, 800},
+-      {1344, 800, 1344, 800},
+-      {1344, 800, 1344, 800},
+-      { 800, 449, 1280, 801},
+-      { 800, 525, 1280, 813}
+-};
+-
+-static const SiS310_LVDSDataStruct  SiS310_LVDS1152x768Data_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 SiS310_LVDSDataStruct  SiS310_LVDS1152x768Data_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},
+-      { 800, 449, 1280, 801},
+-      { 800, 525, 1280, 813}
+-};
+-
+-/* TW: Pass 1:1 data */
+-static const SiS310_LVDSDataStruct  SiS310_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   */
+-      {1344,1066, 1344,1066},  /* 1280x1024  */  /* INSERTED ! */
+-      {1688, 806, 1688, 806},  /* 1280x768 ! */
+-      /* No other panels ! */
+-};
+-
+-static const SiS310_LVDSDataStruct  SiS310_LVDS640x480Data_1[]=  
+-{
+-      { 800, 449, 800, 449},
+-      { 800, 449, 800, 449},
+-      { 800, 449, 800, 449},
+-      { 800, 449, 800, 449},
+-      { 800, 525, 800, 525},
+-      {1056, 628,1056, 628},
+-      {1056, 628,1056, 628},
+-      {1056, 628,1056, 628},
+-      {1056, 628,1056, 628}
+-};
+-
+-static const SiS310_LVDSDataStruct  SiS310_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 SiS310_LVDSDataStruct  SiS310_LVDS1280x960Data_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},
+-      { 800, 449,1280, 801},
+-      { 800, 525,1280, 813}
+-};
+-
+-/* LCDA */
+-
+-static const SiS310_LVDSDataStruct  SiS310_LCDA1400x1050Data_1[]=   
+-{     /* TW: Might be temporary (invalid) data */
+-        { 928, 416, 1688,1066},
+-      { 928, 366, 1688,1066},
+-      {1008, 416, 1688,1066},
+-      {1008, 366, 1688,1066},
+-      {1200, 530, 1688,1066},
+-      {1088, 616, 1688,1066},
+-      {1312, 784, 1688,1066},
+-      {1568,1040, 1688,1066},
+-      {1688,1066, 1688,1066}
+-};
+-
+-static const SiS310_LVDSDataStruct  SiS310_LCDA1400x1050Data_2[]=   
+-{     /* TW: Temporary data. Not valid */
+-      {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},
+-      { 800, 449,1280, 801},
+-      { 800, 525,1280, 813}
+-};
+-
+-static const SiS310_LVDSDataStruct  SiS310_LCDA1600x1200Data_1[]=  
+-{     /* TW: Temporary data. Not valid */
+-      {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},
+-      { 800, 449,1280, 801},
+-      { 800, 525,1280, 813}
+-};
+-
+-static const SiS310_LVDSDataStruct  SiS310_LCDA1600x1200Data_2[]=  
+-{     /* TW: Temporary data. Not valid */
+-      {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, 0, 0},
+-      {0, 0, 0, 0},
+-      {0, 0, 0, 0},
+-      {0, 0, 0, 0},
+-      {0, 0, 0, 0}
+-};
+-
+-/* Chrontel TV */
+-
+-static const SiS310_LVDSDataStruct  SiS310_CHTVUNTSCData[]=   
+-{
+-      { 840, 600, 840, 600},
+-      { 840, 600, 840, 600},
+-      { 840, 600, 840, 600},
+-      { 840, 600, 840, 600},
+-      { 784, 600, 784, 600},
+-      {1064, 750,1064, 750},
+-        {1160, 945,1160, 945}           /* TW: For Ch7019 1024 */
+-};
+-
+-static const SiS310_LVDSDataStruct  SiS310_CHTVONTSCData[]=   
+-{
+-      { 840, 525, 840, 525},
+-      { 840, 525, 840, 525},
+-      { 840, 525, 840, 525},
+-      { 840, 525, 840, 525},
+-      { 784, 525, 784, 525},
+-      {1040, 700,1040, 700},
+-        {1160, 840,1160, 840}                 /* TW: For Ch7019 1024 */
+-};
+-
+-static const SiS310_LVDSDataStruct  SiS310_CHTVUPALData[]=   
++static const SiS310_LVDSDataStruct  SiS310_CHTVUPALData[]=
+ {
+       {1008, 625,1008, 625},
+       {1008, 625,1008, 625},
+@@ -2156,7 +1039,7 @@ static const SiS310_LVDSDataStruct  SiS3
+       {1008, 625,1008, 625},
+       { 840, 625, 840, 625},
+       { 960, 750, 960, 750},
+-      {1400,1000,1400,1000}           /*  TW: For Ch7019 1024 */
++      {1400,1000,1400,1000}
+ };
+ static const SiS310_LVDSDataStruct  SiS310_CHTVOPALData[]= 
+@@ -2167,7 +1050,7 @@ static const SiS310_LVDSDataStruct  SiS3
+       {1008, 625,1008, 625},
+       { 840, 625, 840, 625},
+       { 944, 625, 944, 625},
+-        {1400, 875,1400, 875}         /*  TW: For Ch7019 1024 */
++        {1400, 875,1400, 875}
+ };
+ static const SiS310_LVDSDataStruct  SiS310_CHTVUPALMData[]=  
+@@ -2178,7 +1061,7 @@ static const SiS310_LVDSDataStruct  SiS3
+       { 840, 600, 840, 600},
+       { 784, 600, 784, 600},
+       {1064, 750,1064, 750},
+-        {1160, 945,1160, 945}           /* TW: For Ch7019 1024 */
++        {1160, 945,1160, 945}
+ };
+ static const SiS310_LVDSDataStruct  SiS310_CHTVOPALMData[]=  
+@@ -2189,7 +1072,7 @@ static const SiS310_LVDSDataStruct  SiS3
+       { 840, 525, 840, 525},
+       { 784, 525, 784, 525},
+       {1040, 700,1040, 700},
+-        {1160, 840,1160, 840}                 /* TW: For Ch7019 1024 */
++        {1160, 840,1160, 840}
+ };
+ static const SiS310_LVDSDataStruct  SiS310_CHTVUPALNData[]=  
+@@ -2200,7 +1083,7 @@ static const SiS310_LVDSDataStruct  SiS3
+       {1008, 625,1008, 625},
+       { 840, 625, 840, 625},
+       { 960, 750, 960, 750},
+-      {1400,1000,1400,1000}           /*  TW: For Ch7019 1024 */
++      {1400,1000,1400,1000}
+ };
+ static const SiS310_LVDSDataStruct  SiS310_CHTVOPALNData[]= 
+@@ -2211,7 +1094,7 @@ static const SiS310_LVDSDataStruct  SiS3
+       {1008, 625,1008, 625},
+       { 840, 625, 840, 625},
+       { 944, 625, 944, 625},
+-        {1400, 875,1400, 875}         /*  TW: For Ch7019 1024 */
++        {1400, 875,1400, 875}
+ };
+ static const SiS310_LVDSDataStruct  SiS310_CHTVSOPALData[]=   /* TW: (super overscan - no effect on 7019) */
+@@ -2231,7 +1114,7 @@ typedef struct _SiS310_LVDSDesStruct
+       USHORT LCDVDES;
+ } SiS310_LVDSDesStruct;
+-static const SiS310_LVDSDesStruct  SiS310_PanelType00_1[]=  
++static const SiS310_LVDSDesStruct  SiS310_PanelType00_1[]=  /* 800x600 */
+ {
+       { 0, 0},
+       { 0, 0},
+@@ -2244,7 +1127,7 @@ static const SiS310_LVDSDesStruct  SiS31
+       { 0, 0}
+ };
+-static const SiS310_LVDSDesStruct  SiS310_PanelType01_1[]=   
++static const SiS310_LVDSDesStruct  SiS310_PanelType01_1[]=  /* 1024x768 */
+ {
+       { 0, 0},
+       { 0, 0},
+@@ -2257,7 +1140,7 @@ static const SiS310_LVDSDesStruct  SiS31
+       { 0, 0}
+ };
+-static const SiS310_LVDSDesStruct  SiS310_PanelType02_1[]=  
++static const SiS310_LVDSDesStruct  SiS310_PanelType02_1[]=  /* 1280x1024 */
+ {
+       { 0, 0},
+       { 0, 0},
+@@ -2382,33 +1265,31 @@ static const SiS310_LVDSDesStruct  SiS31
+       { 0, 0}
+ };
+-static const SiS310_LVDSDesStruct  SiS310_PanelType0b_1[]= 
+-{
+-      {1343, 798},
+-      {1343, 794},
+-      {1343, 798},
+-      {1343, 794},
+-      {1343,   0},
+-      {1343,   0},
+-      { 0, 805},
+-      { 0, 794},
+-      { 0,   0}
+-};
+-
+-static const SiS310_LVDSDesStruct  SiS310_PanelType0c_1[]=  
++static const SiS310_LVDSDesStruct  SiS310_PanelType0b_1[]=  /* 640x480_2 */
+ {
+-      {1343, 798},
+-      {1343, 794},
+-      {1343, 798},
+-      {1343, 794},
+-      {1343,   0},
+-      {1343,   0},
+-      { 0, 805},
+-      { 0, 794},
+-      { 0,   0}
++      { 0, 524},
++      { 0, 524},
++      { 0, 524},
++      { 0, 524},
++      { 0, 524},
++      { 0, 524},
++      { 8, 524},
++      { 0, 524}
++};
++
++static const SiS310_LVDSDesStruct  SiS310_PanelType0c_1[]=  /* 640x480_3 */
++{
++      { 0, 524},
++      { 0, 524},
++      { 0, 524},
++      { 0, 524},
++      { 0, 524},
++      { 0, 524},
++      { 8, 524},
++      { 0, 524}
+ };
+-static const SiS310_LVDSDesStruct  SiS310_PanelType0d_1[]= 
++static const SiS310_LVDSDesStruct  SiS310_PanelType0d_1[]=
+ {
+       {1343, 798},
+       {1343, 794},
+@@ -2604,7 +1485,7 @@ static const SiS310_LVDSDesStruct  SiS31
+       {   0,   0}
+ };
+-static const SiS310_LVDSDesStruct  SiS310_PanelType0b_2[]=  
++static const SiS310_LVDSDesStruct  SiS310_PanelType0b_2[]=  /* 640x480_2 */
+ {
+       {1152, 622},
+       {1152, 597},
+@@ -2617,7 +1498,7 @@ static const SiS310_LVDSDesStruct  SiS31
+       { 0,   0}
+ };
+-static const SiS310_LVDSDesStruct  SiS310_PanelType0c_2[]= 
++static const SiS310_LVDSDesStruct  SiS310_PanelType0c_2[]=  /* 640x480_3 */
+ {
+       {1152, 622},
+       {1152, 597},
+@@ -2669,184 +1550,6 @@ static const SiS310_LVDSDesStruct  SiS31
+       { 0,   0}
+ };
+-static const SiS310_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 SiS310_LVDSDesStruct  SiS310_PanelTypeNS_2[] = 
+-{
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0}
+-};
+-
+-static const SiS310_LVDSDesStruct SiS310_PanelType1076_1[]=  
+-{  /* 1024x768 - Checked (1.10.6s) */
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0}
+-};
+-
+-static const SiS310_LVDSDesStruct SiS310_PanelType1076_2[]=  
+-{  /* 1024x768 - Checked (1.10.6s) */
+-      { 1184, 622 },
+-      { 1184, 597 },
+-      { 1184, 622 },
+-      { 1184, 597 },
+-      { 1152, 622 },
+-      { 1232, 722 },
+-      {    0, 0   },
+-      {    0, 794 },
+-      {    0, 0   }
+-};
+-
+-static const SiS310_LVDSDesStruct SiS310_PanelType1210_1[]=  
+-{  /* 1280x1024 - Checked (1.10.6s) */
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0}
+-};
+-
+-static const SiS310_LVDSDesStruct SiS310_PanelType1210_2[]=  
+-{  /* 1280x1024 - Checked (1.10.6s) */
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0}
+-};
+-
+-static const SiS310_LVDSDesStruct SiS310_PanelType1296_1[]=  
+-{  /* 1400x1050 - Checked (1.10.6s) */
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0}
+-};
+-
+-static const SiS310_LVDSDesStruct SiS310_PanelType1296_2[]=  
+-{  /* 1400x1050 - Checked (1.10.6s) - looks heavily invalid */
+-      { 808 , 740},
+-      { 0   , 715},
+-      { 632 , 740},
+-      { 632 , 715},
+-      { 1307, 780},
+-      { 1387,1157},
+-      { 1499, 924},
+-      { 1627,1052},
+-      { 0 , 0}
+-};
+-
+-static const SiS310_LVDSDesStruct SiS310_PanelType1600_1[]= 
+-{  /* 1600x1200 - Checked (1.10.6s) */
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0}
+-};
+-
+-static const SiS310_LVDSDesStruct SiS310_PanelType1600_2[]= 
+-{  /* 1600x1200 - Checked (1.10.6s) - looks heavily invalid, not copied */
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0},
+-      { 0 , 0}
+-};
+-
+-static const SiS310_LVDSDesStruct  SiS310_CHTVUNTSCDesData[]=
+-{
+-      { 0,   0},
+-      { 0,   0},
+-      { 0,   0},
+-      { 0,   0},
+-      { 0,   0},
+-      { 0,   0},
+-      { 0,   0}
+-};
+-
+-static const SiS310_LVDSDesStruct  SiS310_CHTVONTSCDesData[]=
+-{
+-      { 0,   0},
+-      { 0,   0},
+-      { 0,   0},
+-      { 0,   0},
+-      { 0,   0},
+-      { 0,   0},
+-      { 0,   0}
+-};
+-
+-static const SiS310_LVDSDesStruct  SiS310_CHTVUPALDesData[]=
+-{
+-      {256,   0},
+-      {256,   0},
+-      {256,   0},
+-      {256,   0},
+-      { 0,   0},
+-      { 0,   0},
+-      { 0,   0}
+-};
+-
+-static const SiS310_LVDSDesStruct  SiS310_CHTVOPALDesData[]=
+-{
+-      {256,   0},
+-      {256,   0},
+-      {256,   0},
+-      {256,   0},
+-      { 0,   0},
+-      { 0,   0},
+-      { 0,   0}
+-};
+-
+ typedef struct _SiS310_Part2PortTblStruct
+ {
+       UCHAR CR[12];
+@@ -2866,16 +1569,15 @@ static const SiS310_Part2PortTblStruct S
+ };
+ static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1280x1024_1[] =
+-{     /* TW: Temporary data, invalid */
+- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}}
++{     /* TW: BIOS data invalid, last row taken from _3 */
++ {{0x25,0x12,0x51,0x6E,0x48,0x99,0x35,0x89,0x47,0xC1,0x49,0x33}},
++ {{0x2C,0x12,0x38,0x55,0x2F,0x99,0x35,0x89,0x47,0xC1,0x49,0x33}},
++ {{0x25,0x12,0x51,0x6E,0x48,0x99,0x35,0x89,0x47,0xC1,0x49,0x33}},
++ {{0x2C,0x12,0x38,0x55,0x2F,0xC1,0x35,0xB1,0x47,0xE9,0x71,0x33}},
++ {{0x2D,0x12,0x79,0x96,0x70,0x99,0x35,0x89,0x47,0xC1,0x49,0x33}},
++ {{0x29,0x12,0xB5,0xD2,0xAC,0xE9,0x35,0xD9,0x47,0x11,0x99,0x33}},
++ {{0x36,0x13,0x02,0x25,0xFF,0x03,0x45,0x09,0x07,0xF9,0x00,0x24}},
++ {{0x47,0x1C,0x14,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}}
+ };
+ static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1400x1050_1[] =
+@@ -2892,16 +1594,17 @@ static const SiS310_Part2PortTblStruct S
+ };
+ static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1600x1200_1[] =
+-{     /* TW: Temporary data, invalid */
+- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}}
++{
++ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
++ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
++ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
++ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
++ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
++ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
++ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
++ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
++ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
++ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}}
+ };
+ static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1024x768_2[] =
+@@ -2912,7 +1615,8 @@ static const SiS310_Part2PortTblStruct S
+  {{0x2c,0x12,0x38,0x55,0x2f,0xc1,0x35,0xb1,0x47,0xe9,0x71,0x33}},
+  {{0x2d,0x12,0x79,0x96,0x70,0x99,0x35,0x89,0x47,0xc1,0x49,0x33}},
+  {{0x29,0x12,0xb5,0xd2,0xac,0xe9,0x35,0xd9,0x47,0x11,0x99,0x33}},
+- {{0x36,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
++ {{0x36,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},  /* old  */
++/* 0x36,0x13,0x02,0x25,0xff,0x03,0x45,0x09,0x07,0xf9,0x00,0x24        new? */
+  {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+  {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
+ };
+@@ -2944,21 +1648,23 @@ static const SiS310_Part2PortTblStruct S
+ };
+ static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1600x1200_2[] =
+-{     /* TW: Temporary data, invalid */
+- {{0x2b,0x12,0xd9,0xe5,0xd5,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
+- {{0x22,0x12,0xc0,0xcc,0xbc,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
+- {{0x2b,0x12,0xd9,0xe5,0xd5,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
+- {{0x22,0x12,0xc0,0xcc,0xbc,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
+- {{0x33,0x13,0x01,0x0d,0xfd,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
+- {{0x3f,0x1b,0x3d,0x49,0x39,0x54,0x23,0xc0,0x27,0x66,0x30,0x42}},
+- {{0x33,0x1b,0x91,0x9d,0x8d,0x8c,0x23,0xf8,0x27,0x9e,0x68,0x42}},
+- {{0x43,0x24,0x11,0x1d,0x0d,0xcc,0x23,0x38,0x37,0xde,0xa8,0x42}},
+- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}}
++{
++ {{0x32,0x1B,0x2C,0x52,0x20,0x80,0x20,0x52,0x30,0xA3,0x3A,0x02}},
++ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
++ {{0x32,0x1B,0x2C,0x52,0x20,0x80,0x20,0x52,0x30,0xA3,0x3A,0x02}},
++ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
++ {{0x3A,0x1B,0x54,0x7A,0x48,0x80,0x24,0x52,0x30,0xA3,0x3A,0x02}},
++ {{0x36,0x1B,0x90,0xB6,0x84,0xA8,0x24,0x7A,0x30,0xCB,0x62,0x02}},
++ {{0x3A,0x1C,0xE4,0x0A,0xD8,0xE0,0x24,0xB2,0x30,0x03,0x9A,0x02}},
++ {{0x4A,0x24,0x64,0x8A,0x58,0x20,0x34,0xF2,0x30,0x43,0xDA,0x52}},
++ {{0x47,0x24,0x71,0x97,0x65,0x3E,0x34,0x10,0x40,0x61,0xF8,0x02}},
++ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}}
+ };
+ static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1024x768_3[] =
+ {     /* TW: Data from 650/301LVx 1.10.6s */
++#if 0
+  {{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,0x24,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+@@ -2968,56 +1674,56 @@ static const SiS310_Part2PortTblStruct S
+  {{0x36,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+  {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+  {{0x25,0x13,0xc9,0x25,0xff,0xf9,0x45,0x09,0x07,0xf9,0x09,0x24}}
+-#if 0 /* TW: Data from 650/301LV */
+- {{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,0x13,0x25,0xff,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}},
+- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
+-#endif
++#endif        /* Data from my 301LV */
++ {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}},   /* @@@@@ TEST */
++ {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}},
++ {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}},
++ {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}},
++ {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}},
++ {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}},
++ {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}},
++ {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}},
++ {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}}
+ };
+ /*   1     2    4    5    6   1c   1d   1f   20   21   23   25   */
+ static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1280x1024_3[] =
+-{     /* TW: Temporary data, invalid */
+-  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+-  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+-  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+-  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+-  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+-  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+-  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+-  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+-  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}}
++{
++ {{0x31,0x1B,0xC4,0xDA,0xB0,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}},
++ {{0x34,0x1B,0x9F,0xC0,0x80,0xB8,0x23,0x0A,0x07,0x14,0x8A,0x12}},
++ {{0x3E,0x1B,0xCF,0xF0,0xB0,0xB8,0x23,0x0A,0x07,0x14,0x8A,0x12}},
++ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
++ {{0x48,0x1C,0x15,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}},
++ {{0x48,0x1C,0x15,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}},
++ {{0x48,0x1C,0x15,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}},
++ {{0x47,0x1C,0x14,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}}
+ };
+ static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1400x1050_3[] =
+ {     
+-  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+-  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+-  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+-  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+-  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+-  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+-  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+-  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+-  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}}
++ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
++ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
++ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
++ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
++ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
++ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
++ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
++ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
++ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}}
+ };
+ static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1600x1200_3[] =
+-{     /* TW: Temporary data, invalid */
+-  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+-  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+-  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+-  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+-  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+-  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+-  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+-  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+-  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}}
++{
++ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
++ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
++ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
++ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
++ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
++ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
++ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
++ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
++ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
++ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}}
+ };
+ typedef struct _SiS310_LCDACRT1DataStruct
+@@ -3054,7 +1760,7 @@ static const SiS310_LCDACRT1DataStruct  
+ };
+ static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11024x768_1[]=
+-{  /* TW: Checked (1.10.6s) */
++{
+  {{0x73,0x4f,0x4f,0x97,0x55,0x86,0xc4,0x1f,
+    0x92,0x89,0x8f,0x8f,0xb5,0x30,0x00,0x05,
+    0x00}},
+@@ -3079,7 +1785,7 @@ static const SiS310_LCDACRT1DataStruct  
+ };
+ static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11280x1024_1[]=
+-{  /* Checked (1.10.6s) */
++{
+  {{0x7e,0x4f,0x4f,0x82,0x58,0x06,0xb8,0x1f,
+    0x90,0x84,0x8f,0x8f,0xb9,0x30,0x00,0x06,
+    0x00}},
+@@ -3107,7 +1813,7 @@ static const SiS310_LCDACRT1DataStruct  
+ };
+ static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11400x1050_1[]=
+-{    /* Checked (1.10.6s) */
++{
+  {{0x6f,0x4f,0x4f,0x93,0x54,0x82,0x9e,0x1f,
+    0x93,0x86,0x8f,0x8f,0x9f,0x30,0x00,0x05,
+    0x00}},
+@@ -3200,7 +1906,7 @@ static const SiS310_LCDACRT1DataStruct  
+ };
+ static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11024x768_1_H[]=
+-{  /* TW: Checked (1.10.6s) */
++{
+  {{0x4b,0x27,0x27,0x8f,0x2b,0x03,0xc4,0x1f,
+    0x92,0x89,0x8f,0x8f,0xb5,0x30,0x00,0x44,
+    0x00}},
+@@ -3225,7 +1931,7 @@ static const SiS310_LCDACRT1DataStruct  
+ };
+ static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11280x1024_1_H[]=
+-{   /* Checked (1.10.6s) */
++{
+  {{0x56,0x27,0x27,0x9a,0x30,0x1e,0xb8,0x1f,
+    0x90,0x84,0x8f,0x8f,0xb9,0x30,0x00,0x05,
+    0x00}},
+@@ -3250,7 +1956,7 @@ static const SiS310_LCDACRT1DataStruct  
+ };
+ static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11400x1050_1_H[]=
+-{   /* Checked (1.10.6s) */
++{
+   {{0x47,0x27,0x27,0x8b,0x2c,0x1a,0x9e,0x1f,
+     0x93,0x86,0x8f,0x8f,0x9f,0x30,0x00,0x05,
+     0x00}},
+@@ -3343,7 +2049,7 @@ static const SiS310_LCDACRT1DataStruct  
+ };
+ static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11024x768_2[]=
+-{   /* Checked (1.10.6s) */
++{
+  {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+    0x4a,0x80,0x8f,0x8f,0x25,0x30,0x00,0x06,
+    0x00}},
+@@ -3368,7 +2074,7 @@ static const SiS310_LCDACRT1DataStruct  
+ };
+ static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11280x1024_2[]=
+-{   /* Checked (1.10.6s) */
++{
+  {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+    0x4a,0x80,0x8f,0x8f,0x25,0x30,0x00,0x06,
+    0x00}},
+@@ -3393,7 +2099,7 @@ static const SiS310_LCDACRT1DataStruct  
+ };
+ static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11400x1050_2[]=
+-{    /* Checked (1.10.6s) */
++{
+  {{0xce,0x4f,0x4f,0x92,0x8c,0x1a,0x28,0x9a,
+    0xdb,0x8f,0x8f,0x8f,0x29,0x21,0x00,0x03,
+    0x00}},
+@@ -3486,7 +2192,7 @@ static const SiS310_LCDACRT1DataStruct  
+ };
+ static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11024x768_2_H[]=
+-{   /* Checked (1.10.6s) */
++{
+  {{0x4f,0x27,0x27,0x93,0x39,0x01,0x24,0xbb,
+    0x4a,0x80,0x8f,0x8f,0x25,0x30,0x00,0x01,
+    0x00 }},
+@@ -3511,7 +2217,7 @@ static const SiS310_LCDACRT1DataStruct  
+ };
+ static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11280x1024_2_H[]=
+-{   /* Checked (1.10.6s) */
++{
+  {{0x4f,0x27,0x27,0x93,0x39,0x81,0x24,0xbb,
+    0x4a,0x80,0x8f,0x8f,0x25,0x30,0x00,0x01,
+    0x00 }},
+@@ -3536,7 +2242,7 @@ static const SiS310_LCDACRT1DataStruct  
+ };
+ static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11400x1050_2_H[]=
+-{  /* Checked (1.10.6s) */
++{
+  {{0xa6,0x27,0x27,0x8a,0x64,0x92,0x28,0x9a,
+    0xdb,0x8f,0x8f,0x8f,0x29,0x21,0x00,0x06,
+    0x00}},
+@@ -3605,32 +2311,7 @@ typedef struct _SiS310_LVDSCRT1DataStruc
+       UCHAR CR[15];
+ } SiS310_LVDSCRT1DataStruct;
+-static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1320x480_1[] =
+-{
+- {{0x65,0x4f,0x89,0x56,0x83,0xaa,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,0x54,0x9f,0xc4,0x1f,
+-   0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
+-   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 }},
+- {{0x2d,0x27,0x90,0x2c,0x80,0x0b,0x3e,
+-   0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00,
+-   0x00 }}
+-};
+-
+-static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_1[] =   
++static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_1[] =
+ {
+  {{0x6b,0x4f,0x8f,0x55,0x85,0xaa,0x1f,
+    0x90,0x85,0x8f,0xab,0x30,0x00,0x05,
+@@ -3924,63 +2605,7 @@ static const SiS310_LVDSCRT1DataStruct  
+    0x01}}
+ };
+-static const SiS310_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 SiS310_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}}
+-};
+-
+-static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11400x1050_1[] =  
++static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11400x1050_1[] =
+ {
+   {{0x6f,0x4f,0x93,0x54,0x82,0x9e,0x1f,
+     0x8f,0x81,0x8f,0x9f,0x30,0x00,0x05,
+@@ -4220,332 +2845,8 @@ static const SiS310_LVDSCRT1DataStruct  
+ #endif   
+ };
+-static const SiS310_LVDSCRT1DataStruct  SiS310_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 SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x768_1_H[] = 
+-{
+- {{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}},
+- {{0x6f,0x4f,0x93,0x54,0x82,0x0e,0x5a,
+-   0x02,0x86,0xff,0x0f,0x09,0x00,0x05,
+-   0x01}}
+-};
+-
+-static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x768_2[] = 
++static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11600x1200_1[] =
+ {
+- {{0xab,0x60,0x9f,0x80,0x04,0x24,0xbb,
+-   0x54,0x86,0xdb,0xda,0x00,0x00,0x02,
+-   0x00}},
+- {{0xab,0x60,0x9f,0x80,0x04,0x24,0xbb,
+-   0x3b,0x8d,0xc2,0xc1,0x00,0x00,0x02,
+-   0x00}},
+- {{0xab,0x60,0x9f,0x80,0x04,0x24,0xbb,
+-   0x54,0x86,0xdb,0xda,0x00,0x00,0x02,
+-   0x00}},
+- {{0xab,0x60,0x9f,0x80,0x04,0x24,0xbb,
+-   0x3b,0x8d,0xc2,0xc1,0x00,0x00,0x02,
+-   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,
+-   0x01}}
+-};
+-
+-static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x768_2_H[] =
+-{
+- {{0x83,0x38,0x97,0x58,0x9c,0x24,0xbb,
+-   0x54,0x86,0xdb,0xda,0x00,0x00,0x01,
+-   0x00}},
+- {{0x83,0x38,0x97,0x58,0x9c,0x24,0xbb,
+-   0x3b,0x8d,0xc2,0xc1,0x00,0x00,0x01,
+-   0x00}},
+- {{0x83,0x38,0x97,0x58,0x9c,0x24,0xbb,
+-   0x54,0x86,0xdb,0xda,0x00,0x00,0x01,
+-   0x00}},
+- {{0x83,0x38,0x97,0x58,0x9c,0x24,0xbb,
+-   0x3b,0x8d,0xc2,0xc1,0x00,0x00,0x01,
+-   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}}
+-};
+-
+-static const SiS310_LVDSCRT1DataStruct  SiS310_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 SiS310_LVDSCRT1DataStruct  SiS310_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 SiS310_LVDSCRT1DataStruct  SiS310_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 SiS310_LVDSCRT1DataStruct  SiS310_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 SiS310_LVDSCRT1DataStruct  SiS310_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 SiS310_LVDSCRT1DataStruct  SiS310_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 SiS310_LVDSCRT1DataStruct  SiS310_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 SiS310_LVDSCRT1DataStruct  SiS310_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 SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11600x1200_1[] =  
+-{    
+  {{0x83,0x4f,0x87,0x51,0x09,0xc0,0x1f,
+    0x90,0x84,0x8f,0xc1,0x30,0x00,0x06,
+    0x00}},
+@@ -4701,7 +3002,7 @@ static const SiS310_LVDSCRT1DataStruct  
+       {{0x80,0x63,0x84,0x6d,0x0f,0xec,0xf0,
+         0x7a,0x8f,0x57,0xed,0x20,0x00,0x06,
+         0x01 }},
+-      {{0x8c,0x7f,0x90,0x86,0x09,0xaf,0xf5,  /* TW: 1024x768 */
++      {{0x8c,0x7f,0x90,0x86,0x09,0xaf,0xf5,
+         0x36,0x88,0xff,0xb0,0x10,0x00,0x02,
+         0x01}}
+ };
+@@ -4726,7 +3027,7 @@ static const SiS310_LVDSCRT1DataStruct  
+       {{0x7d,0x63,0x81,0x68,0x0e,0xba,0xf0,
+         0x78,0x8a,0x57,0xbb,0x20,0x00,0x06,
+         0x01 }},
+-      {{0x8c,0x7f,0x90,0x82,0x06,0x46,0xf5,   /* TW: 1024x768 */
++      {{0x8c,0x7f,0x90,0x82,0x06,0x46,0xf5,
+         0x15,0x88,0xff,0x47,0x70,0x00,0x02,
+         0x01 }}
+ };
+@@ -4751,7 +3052,7 @@ static const SiS310_LVDSCRT1DataStruct  
+       {{0x73,0x63,0x97,0x69,0x8b,0xec,0xf0,
+         0x90,0x8c,0x57,0xed,0x20,0x00,0x05,
+         0x01 }},
+-      {{0xaa,0x7f,0x8e,0x8e,0x96,0xe6,0xf5,   /* TW: 1024x768 */
++      {{0xaa,0x7f,0x8e,0x8e,0x96,0xe6,0xf5,
+         0x50,0x88,0xff,0xe7,0x10,0x00,0x02,
+         0x01}}
+ };
+@@ -4776,7 +3077,7 @@ static const SiS310_LVDSCRT1DataStruct  
+       {{0x71,0x63,0x95,0x69,0x8c,0x6f,0xf0,
+         0x5a,0x8b,0x57,0x70,0x20,0x00,0x05,
+         0x01 }},
+-      {{0xaa,0x7f,0x8e,0x8f,0x96,0x69,0xf5,   /* TW:  1024x768 */
++      {{0xaa,0x7f,0x8e,0x8f,0x96,0x69,0xf5,
+         0x28,0x88,0xff,0x6a,0x10,0x00,0x02,
+         0x01 }}
+ };
+@@ -4801,12 +3102,11 @@ static const SiS310_LVDSCRT1DataStruct  
+       {{0x71,0x63,0x95,0x69,0x8c,0x6f,0xf0,
+         0x5a,0x8b,0x57,0x70,0x20,0x00,0x05,
+         0x01 }},
+-      {{0xaa,0x7f,0x8e,0x8f,0x96,0x69,0xf5,   /* TW:  1024x768 */
++      {{0xaa,0x7f,0x8e,0x8f,0x96,0x69,0xf5,
+         0x28,0x88,0xff,0x6a,0x10,0x00,0x02,
+         0x01 }}
+ };
+-/* TW: Data for Chrontel 7019  */
+ typedef struct _SiS310_CHTVRegDataStruct
+ {
+       UCHAR Reg[16];
+--- linux-2.6.0-test6/drivers/video/sis/init301.c      2003-07-13 21:44:34.000000000 -0700
++++ 25/drivers/video/sis/init301.c     2003-10-05 00:34:22.000000000 -0700
+@@ -1,27 +1,16 @@
+ /* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/sis/init301.c,v 1.3 2002/22/04 01:16:16 dawes Exp $ */
+ /*
+- * Mode switching code (CRT2 section) for SiS 300/540/630/730/315/550/650/740/330
+- * (Universal module for Linux kernel framebuffer, XFree86 4.x)
++ * Mode switching code (CRT2 section) for SiS 300/540/630/730/315/550/650/740/330/660
++ * (Universal module for Linux kernel framebuffer and XFree86 4.x)
+  *
+  * Assembler-To-C translation
+  * Copyright 2002, 2003 by Thomas Winischhofer <thomas@winischhofer.net>
+- * Minor parts Copyright SiS, Inc.
++ * Formerly based on non-functional code-fragements by SiS, Inc.
+  *
+- * Based on BIOS
+- *     1.10.07, 1.10a for 650/CH7019
+- *     1.11.21a for 740/CH7019
+- *     1.11.05 for 650/LVDS (w/o Chrontel)
+- *     1.07.1b, 1.10.6s, 1.11.6w, 1.11.7w, 1.11.8r for 650/301(B/LV), 650/302LV
+- *     2.04.50 (I) and 2.04.5c (II) for 630/301(B)
+- *     2.02.3b, 2.03.02, 2.04.2c, 2.04.5c, 2.07a and 2.08.b3 for 630/LVDS/LVDS+CH7005
+- *     2.04.5c, 2.04.6c for 730+LVDS+CH7005
+- *     1.09b for 315/301(B)
+- *     1.16.51 for 300+301LV (ECS A907)
+- *     1.01.03 for 330 (Xabre 400)
++ * If distributed as part of the linux kernel, the contents of this file
++ * is entirely covered by the GPL.
+  *
+- * Known bugs:
+- *   1024x768 panel, expanding (CR37=1): Mode 640x480 does not work on SOME panels
+- *       therefore, we always do the scaling ourselves for now.
++ * Otherwise, the following terms apply:
+  *
+  * Permission to use, copy, modify, distribute, and sell this software and its
+  * documentation for any purpose is hereby granted without fee, provided that
+@@ -73,8 +62,8 @@
+ #define SiS_I2CDELAYSHORT  150
+ BOOLEAN
+-SiS_SetCRT2Group301(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
+-                    PSIS_HW_DEVICE_INFO HwDeviceExtension)
++SiS_SetCRT2Group(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
++                 PSIS_HW_DEVICE_INFO HwDeviceExtension)
+ {
+    USHORT ModeIdIndex;
+    USHORT RefreshRateTableIndex;
+@@ -85,9 +74,9 @@ SiS_SetCRT2Group301(SiS_Private *SiS_Pr,
+       SiS_SearchModeID(SiS_Pr,ROMAddr,&ModeNo,&ModeIdIndex);
+    } else {
+       ModeIdIndex = 0;
+-   }      
++   }
+-   /* TW: Used for shifting CR33 */
++   /* Used for shifting CR33 */
+    SiS_Pr->SiS_SelectCRT2Rate = 4;
+    SiS_UnLockCRT2(SiS_Pr, HwDeviceExtension, BaseAddr);
+@@ -110,8 +99,6 @@ SiS_SetCRT2Group301(SiS_Private *SiS_Pr,
+       return(TRUE);
+    }
+-   if(SiS_Pr->UseCustomMode) return(FALSE);
+-   
+    SiS_GetCRT2Data(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+                    HwDeviceExtension);
+@@ -153,9 +140,9 @@ SiS_SetCRT2Group301(SiS_Private *SiS_Pr,
+                  SiS_SetGroup5(SiS_Pr,HwDeviceExtension, BaseAddr,ROMAddr,
+                        ModeNo,ModeIdIndex);
+-         /* TW: For 301BDH (Panel link initialization): */
++         /* For 301BDH (Panel link initialization): */
+          if((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) {
+-            if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {   
++            if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
+                if(!((SiS_Pr->SiS_SetFlag & SetDOSMode) && ((ModeNo == 0x03) || (ModeNo = 0x10)))) {
+                   if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+                      SiS_ModCRT1CRTC(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
+@@ -176,10 +163,10 @@ SiS_SetCRT2Group301(SiS_Private *SiS_Pr,
+                             RefreshRateTableIndex,HwDeviceExtension);
+          }
+       }
+-        if(SiS_Pr->SiS_IF_DEF_FSTN == 0) {
+-         SiS_SetCRT2ECLK(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
+-                         RefreshRateTableIndex,HwDeviceExtension);
+-      }
++
++        SiS_SetCRT2ECLK(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
++                      RefreshRateTableIndex,HwDeviceExtension);
++
+       if(SiS_LowModeStuff(SiS_Pr,ModeNo,HwDeviceExtension)) {
+          if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+             if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+@@ -199,74 +186,64 @@ SiS_SetCRT2Group301(SiS_Private *SiS_Pr,
+    }
+ #ifdef SIS300
+-   if ( (HwDeviceExtension->jChipType == SIS_540) ||
+-        (HwDeviceExtension->jChipType == SIS_630) ||
+-        (HwDeviceExtension->jChipType == SIS_730) ||
+-        (HwDeviceExtension->jChipType == SIS_300) )
+-    {
+-      if(SiS_LowModeStuff(SiS_Pr,ModeNo,HwDeviceExtension)) {
+-         if(SiS_Pr->SiS_UseOEM) {
+-            if((SiS_Pr->SiS_UseROM) && ROMAddr && (SiS_Pr->SiS_UseOEM == -1)) {
+-               if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) {
+-                  SiS_OEM300Setting(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo);
+-               }
+-            } else {
+-                       SiS_OEM300Setting(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo);
+-            }
+-         }
+-      }
+-    }
+-#endif
+-
+-#ifdef SIS315H
+-   if ( (HwDeviceExtension->jChipType == SIS_315H)  ||
+-        (HwDeviceExtension->jChipType == SIS_315)   ||
+-      (HwDeviceExtension->jChipType == SIS_315PRO)||
+-        (HwDeviceExtension->jChipType == SIS_550)   ||
+-        (HwDeviceExtension->jChipType == SIS_740)   ||
+-        (HwDeviceExtension->jChipType == SIS_650)   ||
+-      (HwDeviceExtension->jChipType == SIS_330) )
+-   {
+-        if(SiS_LowModeStuff(SiS_Pr,ModeNo,HwDeviceExtension)) {
+-         SiS_FinalizeLCD(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex, HwDeviceExtension);
+-#if 0      /* Instead of FinalizeLCD(), older BIOSes (A92x) used OEMLCD() */
+-         SiS_OEMLCD(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
+-#endif
+-           if(SiS_Pr->SiS_UseOEM) {
+-              SiS_OEM310Setting(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
+-           }
+-           SiS_CRT2AutoThreshold(SiS_Pr,BaseAddr);
+-        }
+-   }
+-#endif
+-
+    if(HwDeviceExtension->jChipType < SIS_315H) {
++      if(SiS_LowModeStuff(SiS_Pr,ModeNo,HwDeviceExtension)) {
++       if(SiS_Pr->SiS_UseOEM) {
++          if((SiS_Pr->SiS_UseROM) && ROMAddr && (SiS_Pr->SiS_UseOEM == -1)) {
++             if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) {
++                SiS_OEM300Setting(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
++                                  RefreshRateTableIndex);
++             }
++          } else {
++                     SiS_OEM300Setting(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
++                               RefreshRateTableIndex);
++          }
++       }
++       if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
++            if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) ||
++             (SiS_Pr->SiS_CustomT == CUT_BARCO1024)) {
++             SetOEMLCDData2(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,
++                            ModeIdIndex,RefreshRateTableIndex);
++          }
++            if(HwDeviceExtension->jChipType == SIS_730) {
++               SiS_DisplayOn(SiS_Pr);
++          }
++         }
++      }
+       if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+           if(HwDeviceExtension->jChipType != SIS_730) {
+              SiS_DisplayOn(SiS_Pr);
+         }
+       }
+    }
++#endif
+-   if(SiS_LowModeStuff(SiS_Pr,ModeNo,HwDeviceExtension)) {
+-      if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+-         if(HwDeviceExtension->jChipType == SIS_730) {
+-            SiS_DisplayOn(SiS_Pr);
+-       }
++#ifdef SIS315H
++   if(HwDeviceExtension->jChipType >= SIS_315H) {
++      if(SiS_LowModeStuff(SiS_Pr,ModeNo,HwDeviceExtension)) {
++       SiS_FinalizeLCD(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex, HwDeviceExtension);
++         if(SiS_Pr->SiS_UseOEM) {
++            SiS_OEM310Setting(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
++         }
++         SiS_CRT2AutoThreshold(SiS_Pr,BaseAddr);
+       }
++   }
++#endif
++
++   if(SiS_LowModeStuff(SiS_Pr,ModeNo,HwDeviceExtension)) {
+       SiS_EnableBridge(SiS_Pr,HwDeviceExtension,BaseAddr);
+    }
+    SiS_DisplayOn(SiS_Pr);
+    if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) {
+-      if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+-           /* TW: Disable LCD panel when using TV */
+-           SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x11,0x0C);
+-      } else {
+-           /* TW: Disable TV when using LCD */
+-           SiS_SetCH70xxANDOR(SiS_Pr,0x010E,0xF8);
+-      }
++      if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
++       /* Disable LCD panel when using TV */
++       SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x11,0x0C);
++      } else {
++       /* Disable TV when using LCD */
++       SiS_SetCH70xxANDOR(SiS_Pr,0x010E,0xF8);
++      }
+    }
+    if(SiS_LowModeStuff(SiS_Pr,ModeNo,HwDeviceExtension)) {
+@@ -283,7 +260,7 @@ SiS_LowModeStuff(SiS_Private *SiS_Pr, US
+     USHORT temp,temp1,temp2;
+     if((ModeNo != 0x03) && (ModeNo != 0x10) && (ModeNo != 0x12))
+-         return(1);
++       return(1);
+     temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x11);
+     SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x11,0x80);
+     temp1 = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x00);
+@@ -304,7 +281,7 @@ SiS_LowModeStuff(SiS_Private *SiS_Pr, US
+     }
+ }
+-/* TW: Set Part1 registers */
++/* Set Part1 registers */
+ void
+ SiS_SetGroup1(SiS_Private *SiS_Pr,USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
+               USHORT ModeIdIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension,
+@@ -313,31 +290,35 @@ SiS_SetGroup1(SiS_Private *SiS_Pr,USHORT
+   USHORT  temp=0, tempax=0, tempbx=0, tempcx=0;
+   USHORT  pushbx=0, CRT1Index=0;
+ #ifdef SIS315H
+-  USHORT  pushcx=0, tempbl=0;
++  USHORT  tempbl=0;
+ #endif
+   USHORT  modeflag, resinfo=0;
+-  if(ModeNo<=0x13) {
+-      modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
++  if(ModeNo <= 0x13) {
++     modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+   } else {
++     if(SiS_Pr->UseCustomMode) {
++      modeflag = SiS_Pr->CModeFlag;
++     } else {
+       CRT1Index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
+       resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+       modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
++     }
+   }
+   if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+-
+-         SiS_SetCRT2Sync(SiS_Pr,BaseAddr,ROMAddr,ModeNo,
+-                           RefreshRateTableIndex,HwDeviceExtension);
+ #ifdef SIS315H
+-         SiS_SetGroup1_LCDA(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
+-                            HwDeviceExtension,RefreshRateTableIndex);
++     SiS_SetCRT2Sync(SiS_Pr,BaseAddr,ROMAddr,ModeNo,
++                     RefreshRateTableIndex,HwDeviceExtension);
++
++     SiS_SetGroup1_LCDA(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
++                        HwDeviceExtension,RefreshRateTableIndex);
+ #endif
+   } else {
+      if( (HwDeviceExtension->jChipType >= SIS_315H) &&
+          (SiS_Pr->SiS_IF_DEF_LVDS == 1) &&
+-       (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
++       (SiS_Pr->SiS_VBInfo & SetInSlaveMode) ) {
+         SiS_SetCRT2Sync(SiS_Pr,BaseAddr,ROMAddr,ModeNo,
+                         RefreshRateTableIndex,HwDeviceExtension);
+@@ -367,13 +348,13 @@ SiS_SetGroup1(SiS_Private *SiS_Pr,USHORT
+ #ifdef SIS300   /* ------------- 300 series --------------*/
+               temp = (SiS_Pr->SiS_VGAHT - 1) & 0x0FF;                         /* BTVGA2HT 0x08,0x09 */
+-              SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,temp);                   /* TW: CRT2 Horizontal Total */
++              SiS_SetReg1(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);          /* TW: CRT2 Horizontal Total Overflow [7: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_SetReg1(SiS_Pr->SiS_Part1Port,0x0A,temp);                   /* TW: CRT2 Horizontal Display Enable End */
++              SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0A,temp);                   /* CRT2 Horizontal Display Enable End */
+               pushbx = SiS_Pr->SiS_VGAHDE + 12;                               /* bx  BTVGA@HRS 0x0B,0x0C */
+               tempcx = (SiS_Pr->SiS_VGAHT - SiS_Pr->SiS_VGAHDE) >> 2;
+@@ -382,108 +363,129 @@ SiS_SetGroup1(SiS_Private *SiS_Pr,USHORT
+               tempcx += tempbx;
+               if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+-                              if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC){
+-                              /* CRT1Index &= 0x3F; - Not any longer */
+-                              tempbx = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[4];
+-                              tempbx |= ((SiS_Pr->SiS_CRT1Table[CRT1Index].CR[14] & 0xC0) << 2);
+-                              tempbx = (tempbx - 1) << 3;
+-                              tempcx = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[5];
+-                              tempcx &= 0x1F;
+-                              temp = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[15];
+-                              temp = (temp & 0x04) << (6-2);
+-                              tempcx = (tempcx | temp);
+-                              tempcx--;
+-                              tempcx <<= 3;
+-                              }
+-
+-                      if((SiS_Pr->SiS_VBInfo & SetCRT2ToTV) && (resinfo == 0x08)){
+-                              if(!(SiS_Pr->SiS_VBInfo & SetPALTV)){
+-                                              tempbx = 1040;
+-                                              tempcx = 1042;
+-                                      }
+-                      }
++
++                 if(SiS_Pr->UseCustomMode) {
++                    tempbx = SiS_Pr->CHSyncStart + 12;
++                    tempcx = SiS_Pr->CHSyncEnd + 12;
++                 }
++
++                         if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) {
++                    unsigned char cr4, cr14, cr5, cr15;
++                    if(SiS_Pr->UseCustomMode) {
++                       cr4  = SiS_Pr->CCRT1CRTC[4];
++                       cr14 = SiS_Pr->CCRT1CRTC[14];
++                       cr5  = SiS_Pr->CCRT1CRTC[5];
++                       cr15 = SiS_Pr->CCRT1CRTC[15];
++                    } else {
++                       cr4  = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[4];
++                       cr14 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[14];
++                       cr5  = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[5];
++                       cr15 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[15];
++                    }
++                    tempbx = ((cr4 | ((cr14 & 0xC0) << 2)) - 1) << 3;
++                    tempcx = (((cr5 & 0x1F) | ((cr15 & 0x04) << (6-2))) - 1) << 3;
++                         }
++
++                 if((SiS_Pr->SiS_VBInfo & SetCRT2ToTV) && (resinfo == SIS_RI_1024x768)){
++                    if(!(SiS_Pr->SiS_VBInfo & SetPALTV)){
++                               tempbx = 1040;
++                               tempcx = 1042;
++                            }
++                 }
+               }
+               temp = tempbx & 0x00FF;
+-              SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0B,temp);                   /* TW: CRT2 Horizontal Retrace Start */
++              SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0B,temp);                   /* CRT2 Horizontal Retrace Start */
+ #endif /* SIS300 */
+       } else {
+-#ifdef SIS315H  /* ----------------- 310/325/330 series ------------- */
++#ifdef SIS315H  /* ------------------- 315/330 series --------------- */
+               tempcx = SiS_Pr->SiS_VGAHT;                                    /* BTVGA2HT 0x08,0x09 */
+-              pushcx = tempcx;
+               if(modeflag & HalfDCLK) {
+-#ifndef NEWCH701x             
+-                  if((SiS_Pr->SiS_IF_DEF_LVDS == 1) && (SiS_Pr->SiS_IF_DEF_CH70xx == 0)) {
+-#endif                    
++                  if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+                         tempax = SiS_Pr->SiS_VGAHDE >> 1;
+                         tempcx = SiS_Pr->SiS_HT - SiS_Pr->SiS_HDE + tempax;
+                         if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+                             tempcx = SiS_Pr->SiS_HT - tempax;
+                         }
+-#ifndef NEWCH701x                                       
+                   } else {
+                         tempcx >>= 1;
+                   }
+-#endif                    
+               }
+               tempcx--;
+               temp = tempcx & 0xff;
+-              SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,temp);                  /* TW: CRT2 Horizontal Total */
++              SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,temp);                  /* CRT2 Horizontal Total */
+               temp = ((tempcx & 0xff00) >> 8) << 4;
+-              SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x09,0x0F,temp);         /* TW: CRT2 Horizontal Total Overflow [7:4] */
++              SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x09,0x0F,temp);         /* CRT2 Horizontal Total Overflow [7:4] */
+-              tempcx = pushcx;                                               /* BTVGA2HDEE 0x0A,0x0C */
++              tempcx = SiS_Pr->SiS_VGAHT;                                    /* BTVGA2HDEE 0x0A,0x0C */
+               tempbx = SiS_Pr->SiS_VGAHDE;
+               tempcx -= tempbx;
+               tempcx >>= 2;
+               if(modeflag & HalfDCLK) {
+-                  tempbx >>= 1;
+-                  tempcx >>= 1;
++                 tempbx >>= 1;
++                 tempcx >>= 1;
+               }
+               tempbx += 16;
+               temp = tempbx & 0xff;
+-              SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0A,temp);                  /* TW: CRT2 Horizontal Display Enable End */
++              SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0A,temp);                  /* CRT2 Horizontal Display Enable End */
+               pushbx = tempbx;
+               tempcx >>= 1;
+               tempbx += tempcx;
+               tempcx += tempbx;
+-              if(SiS_Pr->SiS_IF_DEF_LVDS==0) {
++              if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
++
++                 if(SiS_Pr->UseCustomMode) {
++                    tempbx = SiS_Pr->CHSyncStart + 16;
++                    tempcx = SiS_Pr->CHSyncEnd + 16;
++                    tempax = SiS_Pr->SiS_VGAHT;
++                    if(modeflag & HalfDCLK) tempax >>= 1;
++                    tempax--;
++                    if(tempcx > tempax)  tempcx = tempax;
++                 }
++
+                  if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) {
+-                      tempbx = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[4];
+-                      tempbx |= ((SiS_Pr->SiS_CRT1Table[CRT1Index].CR[14] & 0xC0) << 2);
+-                      tempbx = (tempbx - 3) << 3;                     /*(VGAHRS-3)*8 */
+-                      tempcx = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[5];
+-                              tempcx &= 0x1F;
+-                      temp = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[15];
+-                      temp = (temp & 0x04) << (5-2);                  /* VGAHRE D[5] */
+-                      tempcx = (tempcx | temp);                       /* (VGAHRE-3)*8 */
+-                      tempcx -= 3;
+-                      tempcx <<= 3;
+-                      tempcx &= 0x00FF;
+-                      tempcx |= (tempbx & 0xFF00);
+-                      tempbx += 16;
+-                      tempcx += 16;
+-                      tempax = SiS_Pr->SiS_VGAHT;
+-                      if(modeflag & HalfDCLK)  tempax >>= 1;
+-                      tempax--;
+-                      if(tempcx > tempax)  tempcx = tempax;
++                    unsigned char cr4, cr14, cr5, cr15;
++                    if(SiS_Pr->UseCustomMode) {
++                       cr4  = SiS_Pr->CCRT1CRTC[4];
++                       cr14 = SiS_Pr->CCRT1CRTC[14];
++                       cr5  = SiS_Pr->CCRT1CRTC[5];
++                       cr15 = SiS_Pr->CCRT1CRTC[15];
++                    } else {
++                       cr4  = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[4];
++                       cr14 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[14];
++                       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 */
++                    tempcx &= 0x00FF;
++                    tempcx |= (tempbx & 0xFF00);
++                      tempbx += 16;
++                      tempcx += 16;
++                    tempax = SiS_Pr->SiS_VGAHT;
++                    if(modeflag & HalfDCLK) tempax >>= 1;
++                    tempax--;
++                    if(tempcx > tempax)  tempcx = tempax;
+                  }
+-                 if((SiS_Pr->SiS_VBInfo & SetCRT2ToTV) && (resinfo == 0x08)){
+-                    if(!(SiS_Pr->SiS_VBInfo & SetPALTV)){
+-                               tempbx = 1040;
+-                               tempcx = 1042;
+-                            }
++                 if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
++                    if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
++                       if(resinfo == SIS_RI_1024x768) {
++                                  tempbx = 1040;
++                                  tempcx = 1042;
++                               }
++                    }
+                  }
+-                 /* TW: Makes no sense, but is in 650/302LV 1.10.6s */
+-                 if((SiS_Pr->SiS_VBInfo & SetCRT2ToTV) && (resinfo == 0x08)){
++#if 0
++                 /* Makes no sense, but is in 650/30xLV 1.10.6s */
++                 if((SiS_Pr->SiS_VBInfo & SetCRT2ToTV) && (resinfo == SIS_RI_1024x768)){
+                     if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV)) {
+                        if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+                                   tempbx = 1040;
+@@ -491,25 +493,26 @@ SiS_SetGroup1(SiS_Private *SiS_Pr,USHORT
+                                }
+                     }
+                  }
++#endif
+                 }
+               temp = tempbx & 0xff;
+-              SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0B,temp);                 /* TW: CRT2 Horizontal Retrace Start */
++              SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0B,temp);                 /* CRT2 Horizontal Retrace Start */
+ #endif  /* SIS315H */
+-      }  /* 310/325/330 series */
++      }  /* 315/330 series */
+-      /* TW: The following is done for all bridge/chip types/series */
++      /* The following is done for all bridge/chip types/series */
+       tempax = tempbx & 0xFF00;
+       tempbx = pushbx;
+       tempbx = (tempbx & 0x00FF) | ((tempbx & 0xFF00) << 4);
+       tempax |= (tempbx & 0xFF00);
+       temp = (tempax & 0xFF00) >> 8;
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0C,temp);                        /* TW: Overflow */
++      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0C,temp);                        /* Overflow */
+       temp = tempcx & 0x00FF;
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0D,temp);                        /* TW: CRT2 Horizontal Retrace End */
++      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0D,temp);                        /* CRT2 Horizontal Retrace End */
+       /* 2. Vertical setup */
+@@ -517,30 +520,30 @@ SiS_SetGroup1(SiS_Private *SiS_Pr,USHORT
+       temp = tempcx & 0x00FF;
+         if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+-           if(HwDeviceExtension->jChipType < SIS_315H) {
+-                if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+-                     if(SiS_Pr->SiS_VBInfo & (SetCRT2ToSVIDEO | SetCRT2ToAVIDEO)) {
+-                         temp--;
+-                     }
+-                  }
+-           } else {
+-                    temp--;
+-             }
++         if(HwDeviceExtension->jChipType < SIS_315H) {
++            if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
++               if(SiS_Pr->SiS_VBInfo & (SetCRT2ToSVIDEO | SetCRT2ToAVIDEO)) {
++                  temp--;
++               }
++              }
++         } else {
++            temp--;
++           }
+         } else if(HwDeviceExtension->jChipType >= SIS_315H) {
+-          /* TW: 650/30xLV 1.10.6s */
+-          temp--;
++         /* 650/30xLV 1.10.6s */
++         temp--;
+       }
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0E,temp);                        /* TW: CRT2 Vertical Total */
++      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0E,temp);                        /* CRT2 Vertical Total */
+       tempbx = SiS_Pr->SiS_VGAVDE - 1;
+       temp = tempbx & 0x00FF;
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0F,temp);                        /* TW: CRT2 Vertical Display Enable End */
++      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0F,temp);                        /* CRT2 Vertical Display Enable End */
+       temp = ((tempbx & 0xFF00) << 3) >> 8;
+       temp |= ((tempcx & 0xFF00) >> 8);
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x12,temp);                        /* TW: Overflow (and HWCursor Test Mode) */
++      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x12,temp);                        /* Overflow (and HWCursor Test Mode) */
+-      /* TW: 650/LVDS (1.10.07), 650/30xLV (1.10.6s) */
++      /* 650/LVDS (1.10.07), 650/30xLV (1.10.6s) */
+       if(HwDeviceExtension->jChipType >= SIS_315H) {
+            tempbx++;
+          tempax = tempbx;
+@@ -553,29 +556,44 @@ SiS_SetGroup1(SiS_Private *SiS_Pr,USHORT
+          tempcx += tempbx;
+          tempcx++;
+       } else {
+-         /* TW: 300 series, LVDS/301B: */
++         /* 300 series, LVDS/301B: */
+          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_IF_DEF_LVDS == 0) {
+-         if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC){
+-                      tempbx = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[8];
+-                      temp = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[7];
+-                      if(temp & 0x04) tempbx |= 0x0100;
+-                      if(temp & 0x80) tempbx |= 0x0200;
+-                      temp = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[13];
+-                      if(temp & 0x08) tempbx |= 0x0400;
+-                      temp = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[9];
+-                      tempcx = (tempcx & 0xFF00) | (temp & 0x00FF);
++
++         if(SiS_Pr->UseCustomMode) {
++            tempbx = SiS_Pr->CVSyncStart;
++            tempcx = (tempcx & 0xFF00) | (SiS_Pr->CVSyncEnd & 0x00FF);
++         }
++
++         if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) {
++            unsigned char cr8, cr7, cr13, cr9;
++            if(SiS_Pr->UseCustomMode) {
++               cr8  = SiS_Pr->CCRT1CRTC[8];
++               cr7  = SiS_Pr->CCRT1CRTC[7];
++               cr13 = SiS_Pr->CCRT1CRTC[13];
++               cr9  = SiS_Pr->CCRT1CRTC[9];
++            } else {
++               cr8  = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[8];
++               cr7  = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[7];
++               cr13 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[13];
++               cr9  = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[9];
++            }
++                    tempbx = cr8;
++                    if(cr7 & 0x04)  tempbx |= 0x0100;
++                    if(cr7 & 0x80)  tempbx |= 0x0200;
++                    if(cr13 & 0x08) tempbx |= 0x0400;
++                    tempcx = (tempcx & 0xFF00) | (cr9 & 0x00FF);
+          }
+       }
+       temp = tempbx & 0x00FF;
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x10,temp);           /* TW: CRT2 Vertical Retrace Start */
++      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x10,temp);           /* CRT2 Vertical Retrace Start */
+       temp = ((tempbx & 0xFF00) >> 8) << 4;
+       temp |= (tempcx & 0x000F);
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x11,temp);           /* TW: CRT2 Vert. Retrace End; Overflow; "Enable CRTC Check" */
++      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x11,temp);           /* CRT2 Vert. Retrace End; Overflow; "Enable CRTC Check" */
+       /* 3. Panel compensation delay */
+@@ -590,18 +608,18 @@ SiS_SetGroup1(SiS_Private *SiS_Pr,USHORT
+                  temp = 0x10;
+                  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)  temp = 0x2c;
+                  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) temp = 0x20;
+-                 if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960)  temp = 0x24;
+               }
+               if(SiS_Pr->SiS_VBType & VB_SIS301) {
+                  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) temp = 0x20;
+               }
+               if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960)     temp = 0x24;
++              if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom)       temp = 0x2c;
+               if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)            temp = 0x08;
+               if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {
+                          if(SiS_Pr->SiS_VBInfo & SetInSlaveMode)      temp = 0x2c;
+                          else                                         temp = 0x20;
+               }
+-              if((ROMAddr) && (SiS_Pr->SiS_UseROM) && (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) {
++              if((ROMAddr) && (SiS_Pr->SiS_UseROM)) {
+                   if(ROMAddr[0x220] & 0x80) {
+                       if(SiS_Pr->SiS_VBInfo & (SetCRT2ToTV-SetCRT2ToHiVisionTV))
+                               temp = ROMAddr[0x221];
+@@ -636,19 +654,20 @@ SiS_SetGroup1(SiS_Private *SiS_Pr,USHORT
+               }
+          }
+-         SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,~0x03C,temp);         /* TW: Panel Link Delay Compensation; (Software Command Reset; Power Saving) */
++         SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,~0x03C,temp);         /* Panel Link Delay Compensation; (Software Command Reset; Power Saving) */
+ #endif  /* SIS300 */
+       } else {
+-#ifdef SIS315H   /* ----------- 310/325/330 series ---------------*/
++#ifdef SIS315H   /* --------------- 315/330 series ---------------*/
+          if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+                 temp = 0x10;
+                 if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)  temp = 0x2c;
+               if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) temp = 0x20;
+               if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960)  temp = 0x24;
++              if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom)    temp = 0x2c;
+               if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+                  temp = 0x08;
+                  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {
+@@ -664,7 +683,7 @@ SiS_SetGroup1(SiS_Private *SiS_Pr,USHORT
+                     }
+                  }
+               }
+-              if(SiS_Pr->SiS_VBType & VB_SIS301B302B) {
++              if((SiS_Pr->SiS_VBType & VB_SIS301B302B) && (!(SiS_Pr->SiS_VBType & VB_NoLCD))) {
+                  tempbl = 0x00;
+                  if((ROMAddr) && (SiS_Pr->SiS_UseROM)) {
+                     if(HwDeviceExtension->jChipType < SIS_330) {
+@@ -689,8 +708,16 @@ SiS_SetGroup1(SiS_Private *SiS_Pr,USHORT
+                     if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) tempbl = 0x0F;
+                  }
+               }
++
++              if(SiS_Pr->SiS_IF_DEF_DSTN || SiS_Pr->SiS_IF_DEF_FSTN) {
++                 temp = 0x08;
++                 tempbl = 0;
++                 if((ROMAddr) && (SiS_Pr->SiS_UseROM)) {
++                    if(ROMAddr[0x13c] & 0x80) tempbl = 0xf0;
++                 }
++              }
+          }
+-         SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2D,tempbl,temp);         /* TW: Panel Link Delay Compensation */
++         SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2D,tempbl,temp);         /* Panel Link Delay Compensation */
+          tempax = 0;
+          if (modeflag & DoubleScanMode) tempax |= 0x80;
+@@ -705,14 +732,13 @@ SiS_SetGroup1(SiS_Private *SiS_Pr,USHORT
+      if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+-        /* TW: For 301BDH, we set up the Panel Link */
+-        if( (SiS_Pr->SiS_VBType & VB_NoLCD) &&
+-          (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) ) {
++        /* For 301BDH with LCD, we set up the Panel Link */
++        if( (SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) ) {
+           SiS_SetGroup1_LVDS(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
+                              HwDeviceExtension,RefreshRateTableIndex);
+-        } else if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {                             
++        } else if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+           SiS_SetGroup1_301(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
+                             HwDeviceExtension,RefreshRateTableIndex);
+@@ -749,23 +775,27 @@ SiS_SetGroup1_301(SiS_Private *SiS_Pr, U
+   USHORT  push1,push2;
+   USHORT  tempax,tempbx,tempcx,temp;
+   USHORT  resinfo,modeflag;
++  unsigned char p1_7, p1_8;
+   if(ModeNo <= 0x13) {
+-      modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+-      resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
++     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;
++     } else {
+       modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+       resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
++     }
+   }
+-  /* TW: The following is only done if bridge is in slave mode: */
++  /* The following is only done if bridge is in slave mode: */
+   tempax = 0xFFFF;
+   if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV))  tempax = SiS_GetVGAHT2(SiS_Pr);
+-  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+-      modeflag |= Charx8Dot;
+-  }
++  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)  modeflag |= Charx8Dot;
+   if(modeflag & Charx8Dot) tempcx = 0x08;
+   else                     tempcx = 0x09;
+@@ -777,8 +807,7 @@ SiS_SetGroup1_301(SiS_Private *SiS_Pr, U
+   tempax = (tempax / tempcx) - 5;
+   tempbx = tempax & 0x00FF;
+-  temp = 0xFF;                                                  /* set MAX HT */
+-  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x03,temp);
++  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x03,0xff);                 /* set MAX HT */
+   tempax = SiS_Pr->SiS_VGAHDE;                                        /* 0x04 Horizontal Display End */
+   if(modeflag & HalfDCLK) tempax >>= 1;
+@@ -789,13 +818,13 @@ SiS_SetGroup1_301(SiS_Private *SiS_Pr, U
+   temp = (tempbx & 0xFF00) >> 8;
+   if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+-        if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) {        
+-          temp += 2;
+-        }
+-  }   
++     if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) {
++        temp += 2;
++     }
++  }
+   if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {
+      if(SiS_Pr->SiS_HiVision == 3) {
+-              if(resinfo == 7) temp -= 2;
++        if(resinfo == SIS_RI_800x600) temp -= 2;
+      }
+   }
+   SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x05,temp);                 /* 0x05 Horizontal Display Start */
+@@ -804,140 +833,133 @@ SiS_SetGroup1_301(SiS_Private *SiS_Pr, U
+   if((SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) &&
+      (SiS_Pr->SiS_HiVision == 3)) {
+-    temp = (tempbx & 0x00FF) - 1;
+-    if(!(modeflag & HalfDCLK)) {
+-      temp -= 6;
+-      if(SiS_Pr->SiS_SetFlag & TVSimuMode) {
+-        temp -= 2;
+-        if(ModeNo > 0x13) temp -= 10;
+-      }
+-    }
++     temp = (tempbx & 0x00FF) - 1;
++     if(!(modeflag & HalfDCLK)) {
++        temp -= 6;
++        if(SiS_Pr->SiS_SetFlag & TVSimuMode) {
++           temp -= 2;
++           if(ModeNo > 0x13) temp -= 10;
++        }
++     }
+   } else {
+-    tempcx = tempbx & 0x00FF;
+-    tempbx = (tempbx & 0xFF00) >> 8;
+-    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(HwDeviceExtension->jChipType >= SIS_315H) {
+-              if(SiS_Pr->SiS_VGAHDE == 800) temp += 2;
+-             }
+-          }
+-       }
+-    } else {
+-       if(!(modeflag & HalfDCLK)) {
+-          temp -= 4;
+-          if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x960) {
+-             if(SiS_Pr->SiS_VGAHDE >= 800) {
+-                temp -= 7;
+-              if(HwDeviceExtension->jChipType < SIS_315H) {
+-                 /* 650/301LV(x) does not do this, 630/301B, 300/301LV do */
+-                   if(SiS_Pr->SiS_ModeType == ModeEGA) {
+-                      if(SiS_Pr->SiS_VGAVDE == 1024) {
+-                         temp += 15;
+-                         if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x1024) 
+-                          temp += 7;
+-                      }
+-                   }
+-              }
+-                if(SiS_Pr->SiS_VGAHDE >= 1280) {
+-                   if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x960) {
+-                      if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) temp += 28;
+-                   }
+-                }
+-             }
+-          }
+-       }
+-    }
++     tempcx = tempbx & 0x00FF;
++     tempbx = (tempbx & 0xFF00) >> 8;
++     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(HwDeviceExtension->jChipType >= SIS_315H) {
++               if(SiS_Pr->SiS_VGAHDE == 800) temp += 2;
++              }
++           }
++        }
++     } else {
++        if(!(modeflag & HalfDCLK)) {
++           temp -= 4;
++           if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x960) {
++              if(SiS_Pr->SiS_VGAHDE >= 800) {
++                 temp -= 7;
++               if(HwDeviceExtension->jChipType < SIS_315H) {
++                  /* 650/301LV(x) does not do this, 630/301B, 300/301LV do */
++                    if(SiS_Pr->SiS_ModeType == ModeEGA) {
++                       if(SiS_Pr->SiS_VGAVDE == 1024) {
++                          temp += 15;
++                          if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x1024)
++                           temp += 7;
++                       }
++                    }
++               }
++                 if(SiS_Pr->SiS_VGAHDE >= 1280) {
++                    if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) temp += 28;
++                 }
++              }
++           }
++        }
++     }
+   }
+-  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07,temp);                       /* 0x07 Horizontal Retrace Start */
+-  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,0x00);                 /* 0x08 Horizontal Retrace End   */
++  p1_7 = temp;
++  p1_8 = 0x00;
+   if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+      if(SiS_Pr->SiS_SetFlag & TVSimuMode) {
+-            if(ModeNo <= 0x01) {
+-              SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07,0x2a);
+-              if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+-                  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,0x61);
+-              } else {
+-                  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,0x41);
+-              }
+-          } else if(SiS_Pr->SiS_ModeType == ModeText) {
+-              if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+-                  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07,0x54);
+-              } else {
+-                  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07,0x55);
+-              }
+-              SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,0x00);
+-          } else if(ModeNo <= 0x13) {
+-              if(modeflag & HalfDCLK) {
+-                  if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+-                      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07,0x30);
+-                      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,0x03);
+-                  } else {
+-                      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07,0x2f);
+-                      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,0x02);
+-                  }
+-              } else {
+-                  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07,0x5b);
+-                  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,0x03);
+-              }
+-          } else if( ((HwDeviceExtension->jChipType >= SIS_315H) && (ModeNo == 0x50)) ||
+-                     ((HwDeviceExtension->jChipType < SIS_315H) && (resinfo == 0 || resinfo == 1)) ) {
+-              if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+-                  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07,0x30);
+-                  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,0x03);
+-              } else {
+-                  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07,0x2f);
+-                  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,0x03);
+-              }
+-          }
+-
++        if(ModeNo <= 0x01) {
++         p1_7 = 0x2a;
++         if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) p1_8 = 0x61;
++         else                                 p1_8 = 0x41;
++      } else if(SiS_Pr->SiS_ModeType == ModeText) {
++         if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) p1_7 = 0x54;
++         else                                 p1_7 = 0x55;
++         p1_8 = 0x00;
++      } else if(ModeNo <= 0x13) {
++         if(modeflag & HalfDCLK) {
++            if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
++               p1_7 = 0x30;
++               p1_8 = 0x03;
++            } else {
++               p1_7 = 0x2f;
++               p1_8 = 0x02;
++            }
++         } else {
++            p1_7 = 0x5b;
++            p1_8 = 0x03;
++         }
++      } else if( ((HwDeviceExtension->jChipType >= SIS_315H) &&
++                  ((ModeNo == 0x50) || (ModeNo = 0x56) || (ModeNo = 0x53))) ||
++                 ((HwDeviceExtension->jChipType < SIS_315H) &&
++                  (resinfo == SIS_RI_320x200 || resinfo == SIS_RI_320x240)) ) {
++         if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
++            p1_7 = 0x30,
++            p1_8 = 0x03;
++         } else {
++            p1_7 = 0x2f;
++            p1_8 = 0x03;
++         }
++        }
+      }
+   }
++
+   if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {
+      if(SiS_Pr->SiS_HiVision & 0x03) {
+-        SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07,0xb2);
++      p1_7 = 0xb2;
+       if(SiS_Pr->SiS_HiVision & 0x02) {
+-         SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07,0xab);
++         p1_7 = 0xab;
+       }
+      }
+   }
++  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07,p1_7);                       /* 0x07 Horizontal Retrace Start */
++  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,p1_8);                       /* 0x08 Horizontal Retrace End   */
++
++
+   SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x18,0x03);                       /* 0x18 SR08 (FIFO Threshold?)   */
+   SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x19,0xF0);
+-  tempbx = SiS_Pr->SiS_VGAVT;
+-  push1 = tempbx;
+-
+   SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x09,0xFF);                       /* 0x09 Set Max VT    */
+   tempcx = 0x121;
+   tempbx = SiS_Pr->SiS_VGAVDE;                                /* 0x0E Vertical Display End */
+-  if(tempbx == 357) tempbx = 350;
+-  if(tempbx == 360) tempbx = 350;
+-  if(tempbx == 375) tempbx = 350;
+-  if(tempbx == 405) tempbx = 400;
+-  if(tempbx == 420) tempbx = 400;
+-  if(tempbx == 525) tempbx = 480;
++  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 == SiS_Pr->SiS_Panel1024x768) {
+-                      if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {
+-                      if(tempbx == 350) tempbx += 5;
+-                      if(tempbx == 480) tempbx += 5;
+-                      }
+-      }
++     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
++              if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {
++           if     (tempbx == 350) tempbx += 5;
++           else if(tempbx == 480) tempbx += 5;
++              }
++     }
+   }
+-  tempbx--;
+-  temp = tempbx & 0x00FF;
+-  tempbx--;
++  tempbx -= 2;
+   temp = tempbx & 0x00FF;
+   SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x10,temp);                       /* 0x10 vertical Blank Start */
+@@ -945,126 +967,91 @@ SiS_SetGroup1_301(SiS_Private *SiS_Pr, U
+   tempbx--;
+   temp = tempbx & 0x00FF;
+ #if 0
+-  /* TW: Missing code from 630/301B 2.04.5a and 650/302LV 1.10.6s (calles int 2f) */
++  /* 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_SetReg1(SiS_Pr->SiS_Part1Port,0x0E,temp);
+-  if(tempbx & 0x0100) {
+-      tempcx |= 0x0002;
+-      if(SiS_Pr->SiS_VBType & VB_SIS301) tempcx |= 0x000a;
+-  }
++  if(tempbx & 0x0100)  tempcx |= 0x0002;
+   tempax = 0x000B;
+   if(modeflag & DoubleScanMode) tempax |= 0x8000;
+-  if(tempbx & 0x0200) {
+-      tempcx |= 0x0040;
+-      if(SiS_Pr->SiS_VBType & VB_SIS301) tempax |= 0x2000;
+-  }
+-
+-  if(SiS_Pr->SiS_VBType & VB_SIS301) {
+-        if(SiS_Pr->SiS_VBInfo & SetPALTV) {
+-            if(SiS_Pr->SiS_VGAVDE == 480) {
+-                   tempax = (tempax & 0x00ff) | 0x2000;
+-                   if(modeflag & DoubleScanMode)  tempax |= 0x8000;
+-            }
+-      }
+-  }
++  if(tempbx & 0x0200)  tempcx |= 0x0040;
+   temp = (tempax & 0xFF00) >> 8;
+   SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0B,temp);
+-  if(tempbx & 0x0400) tempcx |= 0x0600;
++  if(tempbx & 0x0400)  tempcx |= 0x0600;
+   SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x11,0x00);                       /* 0x11 Vertical Blank End */
+-  tempax = push1;
+-  tempax -= tempbx;
+-  tempax >>= 2;
+-  push1 = tempax;
++  tempax = (SiS_Pr->SiS_VGAVT - tempbx) >> 2;
+-  if(HwDeviceExtension->jChipType >= SIS_315H) {
+-        /* TW: 650/30xLV 1.10.6s */
+-        if(ModeNo > 0x13) {
+-          if(resinfo != 0x09) {  /* 1280x1024 */
+-              tempax <<= 1;
+-              tempbx += tempax;
+-          }
+-      } else {
+-          if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1400x1050) {
+-              tempax <<= 1;
+-              tempbx += tempax;
+-          }
+-      }
+-  } else if((resinfo != 0x09) || (SiS_Pr->SiS_VBType & VB_SIS301)) {
+-      tempax <<= 1;
+-      tempbx += tempax;
++  if((ModeNo > 0x13) || (HwDeviceExtension->jChipType < SIS_315H)) {
++     if(resinfo != SIS_RI_1280x1024) {
++      tempbx += (tempax << 1);
++     }
++  } else if(HwDeviceExtension->jChipType >= SIS_315H) {
++     if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1400x1050) {
++      tempbx += (tempax << 1);
++     }
+   }
+-  if( (SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) &&
+-      (SiS_Pr->SiS_HiVision == 3) ) {
+-      tempbx -= 10;
++  if((SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) &&
++     (SiS_Pr->SiS_HiVision == 3)) {
++     tempbx -= 10;
+   } else {
+-      if(SiS_Pr->SiS_SetFlag & TVSimuMode) {
+-                 if(SiS_Pr->SiS_VBInfo & SetPALTV) {
+-             if(!(SiS_Pr->SiS_HiVision & 0x03)) {
+-                    tempbx += 40;
+-                  if(HwDeviceExtension->jChipType >= SIS_315H) {
+-                     if(SiS_Pr->SiS_VGAHDE == 800) tempbx += 10;
+-                  }
+-                     }
+-         }
+-      }
++     if(SiS_Pr->SiS_SetFlag & TVSimuMode) {
++        if(SiS_Pr->SiS_VBInfo & SetPALTV) {
++         if(!(SiS_Pr->SiS_HiVision & 0x03)) {
++              tempbx += 40;
++            if(HwDeviceExtension->jChipType >= SIS_315H) {
++               if(SiS_Pr->SiS_VGAHDE == 800) tempbx += 10;
++            }
++                 }
++      }
++     }
+   }
+-  tempax = push1;
+   tempax >>= 2;
+   tempax++;
+   tempax += tempbx;
+   push1 = tempax;
+   if(SiS_Pr->SiS_VBInfo & SetPALTV) {
+-      if(tempbx <= 513)  {
+-                      if(tempax >= 513) tempbx = 513;
+-      }
++     if(tempbx <= 513)  {
++      if(tempax >= 513) tempbx = 513;
++     }
+   }
+   temp = tempbx & 0x00FF;
+   SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0C,temp);                       /* 0x0C Vertical Retrace Start */
+-  if(!(SiS_Pr->SiS_VBType & VB_SIS301)) {
+-      tempbx--;
+-      temp = tempbx & 0x00FF;
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x10,temp);
+-
+-      if(tempbx & 0x0100) tempcx |= 0x0008;
++  tempbx--;
++  temp = tempbx & 0x00FF;
++  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x10,temp);
+-      if(tempbx & 0x0200) {
+-         SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x0B,0x20);
+-      }
++  if(tempbx & 0x0100) tempcx |= 0x0008;
+-      tempbx++;
++  if(tempbx & 0x0200) {
++     SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x0B,0x20);
+   }
++  tempbx++;
++
+   if(tempbx & 0x0100) tempcx |= 0x0004;
+   if(tempbx & 0x0200) tempcx |= 0x0080;
+   if(tempbx & 0x0400) {
+-        if(SiS_Pr->SiS_VBType & VB_SIS301) tempcx |= 0x0800;
+-      else                               tempcx |= 0x0C00;
++     if(SiS_Pr->SiS_VBType & VB_SIS301) tempcx |= 0x0800;
++     else                               tempcx |= 0x0C00;
+   }
+   tempbx = push1;
+-  temp = tempbx & 0x00FF;
+-  temp &= 0x0F;
++  temp = tempbx & 0x000F;
+   SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0D,temp);                       /* 0x0D vertical Retrace End */
+   if(tempbx & 0x0010) tempcx |= 0x2000;
+   temp = tempcx & 0x00FF;
+-  if(SiS_Pr->SiS_VBType & VB_SIS301) {
+-      if(SiS_Pr->SiS_VBInfo & SetPALTV) {
+-            if(SiS_Pr->SiS_VGAVDE == 480)  temp = 0xa3;
+-      }
+-  }
+   SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0A,temp);               /* 0x0A CR07 */
+   temp = (tempcx & 0xFF00) >> 8;
+@@ -1074,8 +1061,8 @@ SiS_SetGroup1_301(SiS_Private *SiS_Pr, U
+   temp = (tempax & 0xFF00) >> 8;
+   temp = (temp >> 1) & 0x09;
+   if(!(SiS_Pr->SiS_VBType & VB_SIS301)) {
+-       /* Only use 8 dot clock */
+-       temp |= 0x01;
++     /* Only use 8 dot clock */
++     temp |= 0x01;
+   }
+   SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x16,temp);               /* 0x16 SR01 */
+@@ -1084,16 +1071,15 @@ SiS_SetGroup1_301(SiS_Private *SiS_Pr, U
+   SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x12,0x00);               /* 0x12 CR17 */
+   if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) {
+-       if(IS_SIS650) {
+-           /* TW: 650/30xLV 1.10.6s */
+-           if(SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00) & 0x01) {
+-             temp = 0x80;
+-         }
+-       } else temp = 0x80;
+-  } else  temp = 0x00;
++     if(IS_SIS650) {
++        /* 650/30xLV 1.10.6s */
++        if(SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00) & 0x01) {
++         temp = 0x80;
++      }
++     } else temp = 0x80;
++  } else temp = 0x00;
+   SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1A,temp);                       /* 0x1A SR0E */
+-  return;
+ }
+ void
+@@ -1108,40 +1094,52 @@ SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr,U
+ #endif
+   ULONG  tempeax=0, tempebx, tempecx, tempvcfact=0;
++  /* This is not supported on LVDS */
++  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom) return;
++  if(SiS_Pr->UseCustomMode) return;
++
+   if(ModeNo <= 0x13) {
+-      modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+-      resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
++     modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
++     resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+   } else {
+-      modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+-      resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
++     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
++     resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+   }
+-  /* TW: Set up Panel Link */
++  /* Set up Panel Link */
+   /* 1. Horizontal setup */
+   tempax = SiS_Pr->SiS_LCDHDES;
+-  if( (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) &&
+-      (!(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 == SiS_Pr->SiS_Panel640x480) &&
++         (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ) {
++         tempax -= 8;
++     }
+   }
+   tempcx = SiS_Pr->SiS_HT;                                      /* Horiz. Total */
+   tempbx = SiS_Pr->SiS_HDE;                               /* Horiz. Display End */
++  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2 ||
++     SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3) {
++     tempbx >>= 1;
++  }
++
+   if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) {
+      if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+-        if((!SiS_Pr->SiS_IF_DEF_DSTN) && (SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480)) {
+-         if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600)        tempbx =  800;
+-         else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600)  tempbx = 1024;  /* TW */
+-         else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)  tempbx = 1024;
+-         else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768)  tempbx = 1152;  /* TW */
+-         else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768)  tempbx = 1280;
+-         else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) tempbx = 1280; 
+-         else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) tempbx = 1400; 
+-         else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) tempbx = 1600; 
++        if(SiS_Pr->SiS_IF_DEF_FSTN || SiS_Pr->SiS_IF_DEF_DSTN) {
++         tempbx = SiS_Pr->PanelXRes;
++      } else if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
++         tempbx = SiS_Pr->PanelXRes;
++         if(SiS_Pr->SiS_CustomT == CUT_BARCO1024) {
++            tempbx = 800;
++            if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel800x600) {
++               tempbx = 1024;
++            }
++         }
+         }
+      }
+   }
+@@ -1154,13 +1152,18 @@ SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr,U
+   if(tempax >= SiS_Pr->SiS_HT) tempax -= SiS_Pr->SiS_HT;
+   push2 = tempax;
+-  
+-  if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { 
+-     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+-        if((!SiS_Pr->SiS_IF_DEF_DSTN) && (SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480)) {
+-         if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600)        tempcx = 0x0028;
+-         else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600)  tempcx = 0x0018;
+-         else if( (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) ||
++
++  if((!SiS_Pr->SiS_IF_DEF_FSTN) &&
++     (!SiS_Pr->SiS_IF_DEF_DSTN) &&
++     (SiS_Pr->SiS_CustomT != CUT_BARCO1366) &&
++     (SiS_Pr->SiS_CustomT != CUT_BARCO1024) &&
++     (SiS_Pr->SiS_CustomT != CUT_PANEL848)) {
++     if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) {
++        if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
++           if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
++            if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600)        tempcx = 0x0028;
++            else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600)  tempcx = 0x0018;
++            else if( (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) ||
+                   (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768) ) {
+                  if(HwDeviceExtension->jChipType < SIS_315H) {
+                     if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+@@ -1174,11 +1177,12 @@ SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr,U
+                  } else {
+                     tempcx = 0x0018;
+                  }
++            }
++            else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768)  tempcx = 0x0028;
++            else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) tempcx = 0x0030;
++            else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) tempcx = 0x0030;
++            else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) tempcx = 0x0040;
+          }
+-         else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768)  tempcx = 0x0028;
+-         else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) tempcx = 0x0030;
+-         else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) tempcx = 0x0030;
+-         else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) tempcx = 0x0040;
+         }
+      }
+   }
+@@ -1188,14 +1192,18 @@ SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr,U
+   tempax = tempcx >> 3;                          /* BPLHRS */
+   temp = tempax & 0x00FF;
+-  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x14,temp);                /* Part1_14h; TW: Panel Link Horizontal Retrace Start  */
++  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x14,temp);                /* Part1_14h; Panel Link Horizontal Retrace Start  */
+   if(SiS_Pr->SiS_LCDInfo & LCDPass11) {
+      temp = (tempax & 0x00FF) + 2;
+   } else {
+      temp = (tempax & 0x00FF) + 10;
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+-        if(!SiS_Pr->SiS_IF_DEF_DSTN) {
++        if((!SiS_Pr->SiS_IF_DEF_DSTN) &&
++         (!SiS_Pr->SiS_IF_DEF_FSTN) &&
++         (SiS_Pr->SiS_CustomT != CUT_BARCO1366) &&
++         (SiS_Pr->SiS_CustomT != CUT_BARCO1024) &&
++         (SiS_Pr->SiS_CustomT != CUT_PANEL848)) {
+            if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
+             temp += 6;
+               if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel800x600) {
+@@ -1219,47 +1227,57 @@ SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr,U
+   temp &= 0x1F;
+   temp |= ((tempcx & 0x0007) << 5);
+-  if(SiS_Pr->SiS_IF_DEF_FSTN) temp = 0x20;
+-  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x15,temp);        /* Part1_15h; TW: Panel Link Horizontal Retrace End/Skew */
++#if 0
++  if(SiS_Pr->SiS_IF_DEF_FSTN) temp = 0x20;       /* WRONG? BIOS loads cl, not ah */
++#endif
++  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x15,temp);        /* Part1_15h; Panel Link Horizontal Retrace End/Skew */
+   tempbx = push2;
+   tempcx = push1;                                /* lcdhdes  */
+   temp = (tempcx & 0x0007);                      /* BPLHDESKEW  */
+-  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1A,temp);        /* Part1_1Ah; TW: Panel Link Vertical Retrace Start (2:0) */
++  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1A,temp);        /* Part1_1Ah; Panel Link Vertical Retrace Start (2:0) */
+   tempcx >>= 3;                                  /* BPLHDES */
+   temp = (tempcx & 0x00FF);
+-  if(ModeNo == 0x5b) temp--;                     
+-  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x16,temp);        /* Part1_16h; TW: Panel Link Horizontal Display Enable Start  */
++#if 0 /* Not 550 FSTN */
++  if(HwDeviceExtension->jChipType >= SIS_315H) {
++     if(ModeNo == 0x5b) temp--; */
++  }
++#endif
++  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x16,temp);        /* Part1_16h; Panel Link Horizontal Display Enable Start  */
+-  if(HwDeviceExtension->jChipType < SIS_315H) {  
++  if((HwDeviceExtension->jChipType < SIS_315H) ||
++     (SiS_Pr->SiS_IF_DEF_FSTN) ||
++     (SiS_Pr->SiS_IF_DEF_DSTN)) {
+      if(tempbx & 0x07) tempbx += 8;              
+   }
+   tempbx >>= 3;                                  /* BPLHDEE  */
+   temp = tempbx & 0x00FF;
+-  if(ModeNo == 0x5b) temp--;                   
+-  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x17,temp);        /* Part1_17h; TW: Panel Link Horizontal Display Enable End  */
++#if 0 /* Not 550 FSTN */
++  if(HwDeviceExtension->jChipType >= SIS_315H) {
++     if(ModeNo == 0x5b) temp--;
++  }
++#endif
++  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x17,temp);        /* Part1_17h; Panel Link Horizontal Display Enable End  */
+   /* 2. Vertical setup */
+   if(HwDeviceExtension->jChipType < SIS_315H) {
+      tempcx = SiS_Pr->SiS_VGAVT;
+      tempbx = SiS_Pr->SiS_VGAVDE;
+-     if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+-        if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
+-         if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600)       tempbx =  600;
+-         else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) tempbx =  600;
+-         else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) tempbx =  768;
+-         else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768) tempbx =  768;
+-         else                                                         tempbx = 1024;
+-        }
++     if((SiS_Pr->SiS_CustomT != CUT_BARCO1366) && (SiS_Pr->SiS_CustomT != CUT_BARCO1024)) {
++        if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
++           if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
++            tempbx = SiS_Pr->PanelYRes;
++           }
++      }
+      }
+      tempcx -= tempbx;
+   } else {
+-     tempcx = SiS_Pr->SiS_VGAVT - SiS_Pr->SiS_VGAVDE;          /* VGAVT-VGAVDE  */
++     tempcx = SiS_Pr->SiS_VGAVT - SiS_Pr->SiS_VGAVDE;           /* VGAVT-VGAVDE  */
+   }
+@@ -1268,18 +1286,20 @@ SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr,U
+   tempax = SiS_Pr->SiS_VGAVDE;
+-  if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (!SiS_Pr->SiS_IF_DEF_DSTN)) {
+-     if( (SiS_Pr->SiS_IF_DEF_TRUMPION == 0)   && 
+-         (!(SiS_Pr->SiS_LCDInfo & LCDPass11)) &&
+-         (SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) ) {
+-        if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600)        tempax =  600;
+-        else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600)  tempax =  600;  
+-        else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)  tempax =  768;
+-        else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768)  tempax =  768;  
+-        else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768)  tempax =  768;  
+-        else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) tempax = 1024; 
+-        else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) tempax = 1050; 
+-        else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) tempax = 1200; 
++  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
++     if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) || (SiS_Pr->SiS_CustomT == CUT_BARCO1024)) {
++        if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
++           tempax = 600;
++         if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel800x600) {
++            tempax = 768;
++         }
++      }
++     } else if( (SiS_Pr->SiS_IF_DEF_TRUMPION == 0)   &&
++                (!(SiS_Pr->SiS_LCDInfo & LCDPass11)) &&
++                ((SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) ||
++               (SiS_Pr->SiS_IF_DEF_FSTN) ||
++               (SiS_Pr->SiS_IF_DEF_DSTN)) ) {
++      tempax = SiS_Pr->PanelYRes;
+      }
+   }
+@@ -1290,11 +1310,25 @@ SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr,U
+   tempcx >>= 1;
+-  if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480)) {
+-     if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) {
+-        if(!SiS_Pr->SiS_IF_DEF_DSTN) {
+-         if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600)        tempcx = 0x0001;
+-         else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600)  tempcx = 0x0001;
++  if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) &&
++     (SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) &&
++     (SiS_Pr->SiS_CustomT != CUT_BARCO1366) &&
++     (SiS_Pr->SiS_CustomT != CUT_BARCO1024) &&
++     (SiS_Pr->SiS_CustomT != CUT_PANEL848)) {
++     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2 ||
++        SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3) {
++      tempcx = 0x0017;
++     } else if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) {
++        if(SiS_Pr->SiS_IF_DEF_FSTN || SiS_Pr->SiS_IF_DEF_DSTN) {
++         if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600)         tempcx = 0x0003;
++         else if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) ||
++                 (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768)) tempcx = 0x0003;
++           else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024)  tempcx = 0x0001;
++           else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050)  tempcx = 0x0001;
++         else                                                           tempcx = 0x0057;
++        } else  {
++         if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600)         tempcx = 0x0001;
++         else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600)   tempcx = 0x0001;
+          else if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) ||
+                  (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768)) {
+                  if(HwDeviceExtension->jChipType < SIS_315H) {
+@@ -1304,7 +1338,7 @@ SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr,U
+                           tempcx = 0x0003;
+ #endif
+                     } else {
+-                          tempcx = 0x0002;   /* TW: A901; sometimes 0x0003; */
++                          tempcx = 0x0002;   /* A901; sometimes 0x0003; */
+                     }
+                  } else tempcx = 0x0003;
+            }
+@@ -1319,26 +1353,33 @@ SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr,U
+   tempbx += tempcx;                           /* BPLVRS  */
+-  if(HwDeviceExtension->jChipType < SIS_315H) {
+-      tempbx++;
++  if((HwDeviceExtension->jChipType < SIS_315H) ||
++     (SiS_Pr->SiS_IF_DEF_FSTN) ||
++     (SiS_Pr->SiS_IF_DEF_DSTN)) {
++     tempbx++;
+   }
+   if(tempbx >= SiS_Pr->SiS_VT) tempbx -= SiS_Pr->SiS_VT;
+   temp = tempbx & 0x00FF;
+-  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x18,temp);                /* Part1_18h; TW: Panel Link Vertical Retrace Start  */
++  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x18,temp);                /* Part1_18h; Panel Link Vertical Retrace Start  */
+   tempcx >>= 3;
+-  if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) {
++  if((!(SiS_Pr->SiS_LCDInfo & LCDPass11)) &&
++     (SiS_Pr->SiS_CustomT != CUT_BARCO1366) &&
++     (SiS_Pr->SiS_CustomT != CUT_BARCO1024) &&
++     (SiS_Pr->SiS_CustomT != CUT_PANEL848)) {
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+         if( (HwDeviceExtension->jChipType < SIS_315H) &&
+             (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) )     tempcx = 0x0001;
++      else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2)  tempcx = 0x0002;
++      else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3)  tempcx = 0x0002;
+         else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600)    tempcx = 0x0003;
+         else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600)   tempcx = 0x0005;
+         else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768)   tempcx = 0x0005;
+       else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768)   tempcx = 0x0011;
+-        else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024)  tempcx = 0x0005;        
++        else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024)  tempcx = 0x0005;
+         else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050)  tempcx = 0x0002;
+         else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200)  tempcx = 0x0011;
+         else if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480)  {
+@@ -1360,26 +1401,37 @@ SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr,U
+   tempcx = tempcx + tempbx + 1;                  /* BPLVRE  */
+   temp = tempcx & 0x000F;
+-  SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0xf0,temp); /* Part1_19h; TW: Panel Link Vertical Retrace End (3:0); Misc.  */
++  if(SiS_Pr->SiS_IF_DEF_FSTN ||
++     SiS_Pr->SiS_IF_DEF_DSTN ||
++     (SiS_Pr->SiS_CustomT == CUT_BARCO1366) ||
++     (SiS_Pr->SiS_CustomT == CUT_BARCO1024) ||
++     (SiS_Pr->SiS_CustomT == CUT_PANEL848)) {
++     temp |= 0x30;
++  }
++  SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0xf0,temp); /* Part1_19h; Panel Link Vertical Retrace End (3:0); Misc.  */
+   temp = ((tempbx & 0x0700) >> 8) << 3;          /* BPLDESKEW =0 */
+-  if(SiS_Pr->SiS_VGAVDE != SiS_Pr->SiS_VDE)  temp |= 0x40;
+-  if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA)    temp |= 0x40;
++  if(SiS_Pr->SiS_IF_DEF_FSTN || SiS_Pr->SiS_IF_DEF_DSTN) {
++     if(SiS_Pr->SiS_HDE != 640) {
++        if(SiS_Pr->SiS_VGAVDE != SiS_Pr->SiS_VDE)   temp |= 0x40;
++     }
++  } else if(SiS_Pr->SiS_VGAVDE != SiS_Pr->SiS_VDE)  temp |= 0x40;
++  if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA)           temp |= 0x40;
+   if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) {
+-      if(HwDeviceExtension->jChipType >= SIS_315H) {
+-         if(SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00) & 0x01) {
+-            temp |= 0x80;
+-         }
+-      } else {
+-       if( (HwDeviceExtension->jChipType == SIS_630) ||
+-           (HwDeviceExtension->jChipType == SIS_730) ) {
+-          if(HwDeviceExtension->jChipRevision >= 0x30) {
+-             temp |= 0x80;
+-          }
+-       }
+-      }
++     if(HwDeviceExtension->jChipType >= SIS_315H) {
++        if(SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00) & 0x01) {
++           temp |= 0x80;
++        }
++     } else {
++      if( (HwDeviceExtension->jChipType == SIS_630) ||
++          (HwDeviceExtension->jChipType == SIS_730) ) {
++         if(HwDeviceExtension->jChipRevision >= 0x30) {
++            temp |= 0x80;
++         }
++      }
++     }
+   }
+-  SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x1A,0x87,temp);  /* Part1_1Ah; TW: Panel Link Control Signal (7:3); Vertical Retrace Start (2:0) */
++  SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x1A,0x87,temp);  /* Part1_1Ah; Panel Link Control Signal (7:3); Vertical Retrace Start (2:0) */
+   if (HwDeviceExtension->jChipType < SIS_315H) {
+@@ -1396,19 +1448,19 @@ SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr,U
+       }
+       temp = (USHORT)(tempebx & 0x00FF);
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1E,temp);      /* Part1_1Eh; TW: Panel Link Vertical Scaling Factor */
++      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1E,temp);      /* Part1_1Eh; Panel Link Vertical Scaling Factor */
+ #endif /* SIS300 */
+   } else {
+-#ifdef SIS315H  /* 310/325 series */
++#ifdef SIS315H  /* 315 series */
+-#ifdef NEWCH701x
+-        SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x03);
+-#else
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1E,0x23);
+-#endif        
++        if(HwDeviceExtension->jChipType == SIS_740) {
++           SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x03);
++        } else {
++         SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1E,0x23);
++      }
+       tempeax = SiS_Pr->SiS_VGAVDE << 18;
+       temp = (USHORT)(tempeax % (ULONG)SiS_Pr->SiS_VDE);
+@@ -1417,12 +1469,13 @@ SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr,U
+       tempebx = tempeax;                         /* BPLVCFACT  */
+         tempvcfact = tempeax;
+       temp = (USHORT)(tempebx & 0x00FF);
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x37,temp);      /* Part1_37h; TW: Panel Link Vertical Scaling Factor */
++      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x37,temp);      /* Part1_37h; Panel Link Vertical Scaling Factor */
+       temp = (USHORT)((tempebx & 0x00FF00) >> 8);
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x36,temp);      /* Part1_36h; TW: Panel Link Vertical Scaling Factor */
++      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x36,temp);      /* Part1_36h; Panel Link Vertical Scaling Factor */
+       temp = (USHORT)((tempebx & 0x00030000) >> 16);
++      temp &= 0x03;
+       if(SiS_Pr->SiS_VDE == SiS_Pr->SiS_VGAVDE) temp |= 0x04;
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x35,temp);      /* Part1_35h; TW: Panel Link Vertical Scaling Factor */
++      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x35,temp);      /* Part1_35h; Panel Link Vertical Scaling Factor */
+ #endif /* SIS315H */
+@@ -1434,47 +1487,50 @@ SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr,U
+   push1 = temp;                                          
+   if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+-      if(!SiS_Pr->SiS_IF_DEF_DSTN){
++      if(!SiS_Pr->SiS_IF_DEF_FSTN && !SiS_Pr->SiS_IF_DEF_DSTN) {
+               if(HwDeviceExtension->jChipType < SIS_315H) {
+                       if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) {
+-                                      if(resinfo == 15) tempcx++;
++                                      if(resinfo == SIS_RI_1024x600) tempcx++;
+                               if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+-                                      if(resinfo == 7) tempcx++;
++                                      if(resinfo == SIS_RI_800x600) tempcx++;
+                               }
+                       } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) {
+-                                      if(resinfo == 7) tempcx++;
+-                              if(resinfo == 8) tempcx++; /* TW: Doesnt make sense anyway... */
+-                      } else  if(resinfo == 8) tempcx++;
++                                      if(resinfo == SIS_RI_800x600)  tempcx++;
++                              if(resinfo == SIS_RI_1024x768) tempcx++; /* Doesnt make sense anyway... */
++                      } else  if(resinfo == SIS_RI_1024x768) tempcx++;
+               } else {
+                       if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) {
+-                                      if(resinfo == 7) tempcx++;
++                                      if(resinfo == SIS_RI_800x600)  tempcx++;
+                       }
+               }
+       }
+   }
+   if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) {
+-     tempcx = SiS_Pr->SiS_VGAVDE;
+-     tempbx = SiS_Pr->SiS_VGAVDE - 1;
++     if((!SiS_Pr->SiS_IF_DEF_FSTN) && (!SiS_Pr->SiS_IF_DEF_DSTN)) {
++        tempcx = SiS_Pr->SiS_VGAVDE;
++        tempbx = SiS_Pr->SiS_VGAVDE - 1;
++     }
+   }
+   temp = ((tempbx & 0x0700) >> 8) << 3;
+   temp |= ((tempcx & 0x0700) >> 8);
+-  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1D,temp);       /* Part1_1Dh; TW: Vertical Display Overflow; Control Signal */
++  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1D,temp);       /* Part1_1Dh; Vertical Display Overflow; Control Signal */
+   temp = tempbx & 0x00FF;
+-  if(SiS_Pr->SiS_IF_DEF_FSTN) temp++;
+-  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1C,temp);       /* Part1_1Ch; TW: Panel Link Vertical Display Enable End  */
++  /* if(SiS_Pr->SiS_IF_DEF_FSTN) temp++;  */
++  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1C,temp);       /* Part1_1Ch; Panel Link Vertical Display Enable End  */
+   temp = tempcx & 0x00FF;
+-  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1B,temp);       /* Part1_1Bh; TW: Panel Link Vertical Display Enable Start  */
++  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1B,temp);       /* Part1_1Bh; Panel Link Vertical Display Enable Start  */
+   /* 3. Additional horizontal setup (scaling, etc) */
+   tempecx = SiS_Pr->SiS_VGAHDE;
+   if(HwDeviceExtension->jChipType >= SIS_315H) {
+-     if(modeflag & HalfDCLK)
+-        tempecx >>= 1;
++     if((!SiS_Pr->SiS_IF_DEF_FSTN) && (!SiS_Pr->SiS_IF_DEF_DSTN)) {
++        if(modeflag & HalfDCLK) tempecx >>= 1;
++     }
+   }
+   tempebx = SiS_Pr->SiS_HDE;
+   if(tempecx == tempebx) tempeax = 0xFFFF;
+@@ -1484,139 +1540,165 @@ SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr,U
+      temp = (USHORT)(tempeax % tempebx);
+      tempeax = tempeax / tempebx;
+      if(HwDeviceExtension->jChipType >= SIS_315H) {
+-         if(temp) tempeax++;
++        if(temp) tempeax++;
+      }
+   }
+   tempecx = tempeax;
+   if(HwDeviceExtension->jChipType >= SIS_315H) {
+-      tempeax = SiS_Pr->SiS_VGAHDE;
+-      if(modeflag & HalfDCLK) tempeax >>= 1;
+-      tempeax <<= 16;
+-      tempeax = (tempeax / tempecx) - 1;
++     tempeax = SiS_Pr->SiS_VGAHDE;
++     if((!SiS_Pr->SiS_IF_DEF_FSTN) && (!SiS_Pr->SiS_IF_DEF_DSTN)) {
++        if(modeflag & HalfDCLK) tempeax >>= 1;
++     }
++     tempeax <<= 16;
++     tempeax = (tempeax / tempecx) - 1;
+   } else {
+-      tempeax = ((SiS_Pr->SiS_VGAHT << 16) / tempecx) - 1;
++     tempeax = ((SiS_Pr->SiS_VGAHT << 16) / tempecx) - 1;
+   }
+   tempecx <<= 16;
+   tempecx |= (tempeax & 0xFFFF);
+   temp = (USHORT)(tempecx & 0x00FF);
+-  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1F,temp);        /* Part1_1Fh; TW: Panel Link DDA Operational Number in each horiz. line */
++  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1F,temp);        /* Part1_1Fh; Panel Link DDA Operational Number in each horiz. line */
+   tempbx = SiS_Pr->SiS_VDE;
+   if(HwDeviceExtension->jChipType >= SIS_315H) {
+-      tempeax = (SiS_Pr->SiS_VGAVDE << 18) / tempvcfact;
+-      tempbx = (USHORT)(tempeax & 0x0FFFF);
++     tempeax = (SiS_Pr->SiS_VGAVDE << 18) / tempvcfact;
++     tempbx = (USHORT)(tempeax & 0x0FFFF);
+   } else {
+-      tempax = SiS_Pr->SiS_VGAVDE << 6;
+-      tempbx = push1;
+-      tempbx &= 0x3f;
+-      if(tempbx == 0) tempbx = 64;
+-      tempax = tempax / tempbx;
+-      tempbx = tempax;
++     tempeax = SiS_Pr->SiS_VGAVDE << 6;
++     tempbx = push1 & 0x3f;
++     if(tempbx == 0) tempbx = 64;
++     tempeax /= tempbx;
++     tempbx = (USHORT)(tempeax & 0x0FFFF);
+   }
+   if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) tempbx--;
+-  if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA)                 tempbx = 1;
++  if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA) {
++     if((!SiS_Pr->SiS_IF_DEF_FSTN) && (!SiS_Pr->SiS_IF_DEF_DSTN)) tempbx = 1;
++     else if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480)  tempbx = 1;
++  }
+   temp = ((tempbx & 0xFF00) >> 8) << 3;
+   temp |= (USHORT)((tempecx & 0x0700) >> 8);
+-  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x20,temp);       /* Part1_20h; TW: Overflow register */
++  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x20,temp);       /* Part1_20h; Overflow register */
+   temp = tempbx & 0x00FF;
+-  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x21,temp);       /* Part1_21h; TW: Panel Link Vertical Accumulator Register */
++  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x21,temp);       /* Part1_21h; Panel Link Vertical Accumulator Register */
+   tempecx >>= 16;                               /* BPLHCFACT  */
+-  if(HwDeviceExtension->jChipType < SIS_315H) {
+-      if(modeflag & HalfDCLK) tempecx >>= 1;
++  if((HwDeviceExtension->jChipType < SIS_315H) || (SiS_Pr->SiS_IF_DEF_FSTN) || (SiS_Pr->SiS_IF_DEF_DSTN)) {
++     if(modeflag & HalfDCLK) tempecx >>= 1;
+   }
+   temp = (USHORT)((tempecx & 0xFF00) >> 8);
+-  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x22,temp);       /* Part1_22h; TW: Panel Link Horizontal Scaling Factor High */
++  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x22,temp);       /* Part1_22h; Panel Link Horizontal Scaling Factor High */
+   temp = (USHORT)(tempecx & 0x00FF);
+-  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x23,temp);         /* Part1_22h; TW: Panel Link Horizontal Scaling Factor Low */
++  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x23,temp);         /* Part1_22h; Panel Link Horizontal Scaling Factor Low */
+   /* 630/301B and 630/LVDS do something for 640x480 panels here */
+ #ifdef SIS315H
+-  /* TW: DSTN/FSTN initialisation - hardcoded for 320x480 panel */
+-  if(SiS_Pr->SiS_IF_DEF_DSTN) {
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1E,0x01);
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x25,0x00);
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x26,0x00);
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x27,0x00);
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x28,0x87);
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x29,0x5A);
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2A,0x4B);
+-      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x44,~0x007,0x03);
+-      tempbx = SiS_Pr->SiS_HDE + 64;                          /*Blps = lcdhdee(lcdhdes+HDE) + 64*/
+-      temp = tempbx & 0x00FF;
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x38,temp);
+-      temp=((tempbx & 0xFF00) >> 8) << 3;
+-      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x35,~0x078,temp);
+-      tempbx += 32;                                           /*Blpe=lBlps+32*/
+-      temp = tempbx & 0x00FF;
+-      if(SiS_Pr->SiS_IF_DEF_FSTN)  temp=0;
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x39,temp);
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x3A,0x00);           /*Bflml=0*/
+-      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x007,0x00);
+-      tempbx = SiS_Pr->SiS_VDE / 2;
+-      temp = tempbx & 0x00FF;
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x3B,temp);
+-      temp = ((tempbx & 0xFF00) >> 8) << 3;
+-      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x038,temp);
+-      tempeax = SiS_Pr->SiS_HDE << 2;                         /* BDxFIFOSTOP = (HDE*4)/128 */
+-      tempebx = 128;
+-      temp = (USHORT)(tempeax % tempebx);
+-      tempeax = tempeax / tempebx;
+-      if(temp != 0)  tempeax++;
+-      temp = (USHORT)(tempeax & 0x003F);
+-      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x45,~0x0FF,temp);
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x3F,0x00);           /* BDxWadrst0 */
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x3E,0x00);
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x3D,0x10);
+-      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x040,0x00);
+-      tempax = SiS_Pr->SiS_HDE >> 4;                          /* BDxWadroff = HDE*4/8/8 */
+-      pushcx = tempax;
+-      temp = tempax & 0x00FF;
+-      SiS_SetReg1(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 */
+-      tempeax = (tempax * pushcx);
+-      tempebx = 0x00100000 + tempeax;
+-      temp = (USHORT)tempebx & 0x000000FF;
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x42,temp);
+-      temp = (USHORT)((tempebx & 0x0000FF00)>>8);
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x41,temp);
+-      temp = (USHORT)((tempebx & 0x00FF0000)>>16);
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x40,temp);
+-      temp = (USHORT)(((tempebx & 0x01000000)>>24) << 7);
+-      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x080,temp);
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2F,0x03);
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x03,0x50);
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x04,0x00);
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2F,0x01);
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x13,0x00);
+-      SiS_SetReg1(SiS_Pr->SiS_P3c4,0x05,0x86);        /* Unlock */
+-      SiS_SetReg1(SiS_Pr->SiS_P3c4,0x1e,0x62);
+-      if(SiS_Pr->SiS_IF_DEF_FSTN){
+-              SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2b,0x1b);
+-              SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2c,0xe3);
+-              SiS_SetReg1(SiS_Pr->SiS_P3c4,0x1e,0x62);
+-              SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2e,0x04);
+-              SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2f,0x42);
+-              SiS_SetReg1(SiS_Pr->SiS_P3c4,0x32,0x01);
+-              SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2b,0x02);
+-              SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2c,0x00);
+-              SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2d,0x00);
+-      }
+-      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0f,0x30);
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1e,0x7d);
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2e,0xe0);
++  if(SiS_Pr->SiS_IF_DEF_FSTN || SiS_Pr->SiS_IF_DEF_DSTN) {
++     SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x25,0x00);
++     SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x26,0x00);
++     SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x27,0x00);
++     SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x28,0x87);
++     SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x29,0x5A);
++     SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2A,0x4B);
++     SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x44,~0x007,0x03);
++     tempax = SiS_Pr->SiS_HDE;                                /* Blps = lcdhdee(lcdhdes+HDE) + 64 */
++     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2 ||
++        SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3) tempax >>= 1;
++     tempax += 64;
++     temp = tempax & 0x00FF;
++     SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x38,temp);
++     temp = ((tempax & 0xFF00) >> 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_SetReg1(SiS_Pr->SiS_Part1Port,0x39,temp);
++     SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x3A,0x00);            /* Bflml=0 */
++     SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x007,0x00);
++
++     tempax = SiS_Pr->SiS_VDE;
++     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2 ||
++        SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3) tempax >>= 1;
++     tempax >>= 1;
++     temp = tempax & 0x00FF;
++     SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x3B,temp);
++     temp = ((tempax & 0xFF00) >> 8) << 3;
++     SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x038,temp);
++
++     tempeax = SiS_Pr->SiS_HDE;
++     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2 ||
++        SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3) tempeax >>= 1;
++     tempeax <<= 2;                                           /* BDxFIFOSTOP = (HDE*4)/128 */
++     tempebx = 128;
++     temp = (USHORT)(tempeax % tempebx);
++     tempeax = tempeax / tempebx;
++     if(temp) tempeax++;
++     temp = (USHORT)(tempeax & 0x003F);
++     SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x45,~0x0FF,temp);
++     SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x3F,0x00);            /* BDxWadrst0 */
++     SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x3E,0x00);
++     SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x3D,0x10);
++     SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x040,0x00);
++
++     tempax = SiS_Pr->SiS_HDE;
++     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2 ||
++        SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3) tempax >>= 1;
++     tempax >>= 4;                                            /* BDxWadroff = HDE*4/8/8 */
++     pushcx = tempax;
++     temp = tempax & 0x00FF;
++     SiS_SetReg1(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 == SiS_Pr->SiS_Panel640x480_2 ||
++        SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3) tempax >>= 1;
++     tempeax = (tempax * pushcx);
++     tempebx = 0x00100000 + tempeax;
++     temp = (USHORT)tempebx & 0x000000FF;
++     SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x42,temp);
++     temp = (USHORT)((tempebx & 0x0000FF00) >> 8);
++     SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x41,temp);
++     temp = (USHORT)((tempebx & 0x00FF0000) >> 16);
++     SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x40,temp);
++     temp = (USHORT)(((tempebx & 0x01000000) >> 24) << 7);
++     SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x080,temp);
++
++     SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2F,0x03);
++     SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x03,0x50);
++     SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x04,0x00);
++     SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2F,0x01);
++     SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x19,0x38);
++
++     if(SiS_Pr->SiS_IF_DEF_FSTN) {
++        SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2b,0x02);
++        SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2c,0x00);
++        SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2d,0x00);
++        SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x35,0x0c);
++        SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x36,0x00);
++        SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x37,0x00);
++        SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x38,0x80);
++        SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x39,0xA0);
++        SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x3a,0x00);
++        SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x3b,0xf0);
++        SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x3c,0x00);
++        SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x3d,0x10);
++        SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x3e,0x00);
++        SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x3f,0x00);
++        SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x40,0x10);
++        SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x41,0x25);
++        SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x42,0x80);
++        SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x43,0x14);
++        SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x44,0x03);
++        SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x45,0x0a);
++     }
+   }
+ #endif  /* SIS315H */
+-  return;
+-
+ }
+ #ifdef SIS315H
+@@ -1629,7 +1711,7 @@ SiS_CRT2AutoThreshold(SiS_Private *SiS_P
+ #ifdef SIS315H
+-/* TW: For LVDS / 302B/30xLV - LCDA (this must only be called on 310/325 series!) */
++/* For LVDS / 302B/30xLV - LCDA (this must only be called on 315 series!) */
+ void
+ SiS_SetGroup1_LCDA(SiS_Private *SiS_Pr, USHORT  BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                    PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex)
+@@ -1638,6 +1720,10 @@ SiS_SetGroup1_LCDA(SiS_Private *SiS_Pr, 
+   USHORT push1,push2,tempax,tempbx,tempcx,temp;
+   ULONG tempeax=0,tempebx,tempecx,tempvcfact;
++  /* This is not supported with LCDA */
++  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom) return;
++  if(SiS_Pr->UseCustomMode) return;
++
+   if(IS_SIS330) {
+      SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x10);                   /* Xabre 1.01.03 */
+   } else if(IS_SIS740) {
+@@ -1645,7 +1731,7 @@ SiS_SetGroup1_LCDA(SiS_Private *SiS_Pr, 
+         SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,0xfb,0x04);        /* 740/LVDS */
+       SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x03);
+      } else {
+-        SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x10);                        /* 740/301LV 1.10.1i */
++        SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x10);                        /* 740/301LV, 301BDH */
+      }
+   } else {
+      if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {                                       /* 650/LVDS */
+@@ -1669,10 +1755,7 @@ SiS_SetGroup1_LCDA(SiS_Private *SiS_Pr, 
+   tempcx = SiS_Pr->SiS_HT;
+   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+-        if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)       tempbx = 1024;
+-      else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) tempbx = 1400;
+-      else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) tempbx = 1600;
+-      else                                                          tempbx = 1280;
++        tempbx = SiS_Pr->PanelXRes;
+   }
+   tempcx -= tempbx;                                           /* HT-HDE  */
+   push1 = tempax;
+@@ -1684,7 +1767,7 @@ SiS_SetGroup1_LCDA(SiS_Private *SiS_Pr, 
+   tempcx >>= 2;
+-  /* TW: 650/30xLV 1.10.6s, 740/LVDS */
++  /* 650/30xLV 1.10.6s, 740/LVDS */
+   if( ((SiS_Pr->SiS_IF_DEF_LVDS == 0) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) ||
+       ((SiS_Pr->SiS_IF_DEF_LVDS == 1) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) ) {
+      if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
+@@ -1748,13 +1831,10 @@ SiS_SetGroup1_LCDA(SiS_Private *SiS_Pr, 
+   tempbx = SiS_Pr->SiS_LCDVDES;                                       /* VGAVDES  */
+   push1 = tempbx;                                                     
+   if(SiS_Pr->SiS_IF_DEF_TRUMPION == 0) {
+-    if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)        tempax = 768;
+-    else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768)   tempax = 768;
+-    else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024)  tempax = 1024;
+-    else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050)  tempax = 1050;
+-    else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200)  tempax = 1200;
+-    else                                                           tempax = 960;
+-  } else tempax = SiS_Pr->SiS_VGAVDE;  /* Trumpion */
++     tempax = SiS_Pr->PanelYRes;
++  } else {
++     tempax = SiS_Pr->SiS_VGAVDE;
++  }
+   tempbx += tempax;
+   tempax = SiS_Pr->SiS_VT;                                            /* VT  */
+@@ -1764,7 +1844,7 @@ SiS_SetGroup1_LCDA(SiS_Private *SiS_Pr, 
+  
+   tempcx >>= 2;       
+-  /* TW: 650/30xLV 1.10.6s, 740/LVDS */
++  /* 650/30xLV 1.10.6s, 740/LVDS */
+   if( ((SiS_Pr->SiS_IF_DEF_LVDS == 0) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) ||
+       ((SiS_Pr->SiS_IF_DEF_LVDS == 1) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) ) {
+      if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
+@@ -1806,7 +1886,7 @@ SiS_SetGroup1_LCDA(SiS_Private *SiS_Pr, 
+   if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0xF0,temp);
+   } else {
+-     /* TW: 650/30xLV 1.10.6s, Xabre */
++     /* 650/30xLV 1.10.6s, Xabre */
+      temp |= 0xC0;
+      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0xF0,temp);             /* Part1_19h  */
+   }
+@@ -1823,7 +1903,7 @@ SiS_SetGroup1_LCDA(SiS_Private *SiS_Pr, 
+      }
+   } else {
+      if(IS_SIS650) {
+-        /* TW: 650/30xLV 1.10.6s */
++        /* 650/30xLV 1.10.6s */
+         if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) {
+            if(SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00) & 0x01) temp |= 0x80;
+         }
+@@ -1839,7 +1919,7 @@ SiS_SetGroup1_LCDA(SiS_Private *SiS_Pr, 
+   if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) {
+-      if(resinfo == 7) tempcx++;
++      if(resinfo == SIS_RI_800x600) tempcx++;
+     }
+   }
+   if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) {
+@@ -1925,18 +2005,17 @@ SiS_SetGroup1_LCDA(SiS_Private *SiS_Pr, 
+   SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x23,temp);
+ #if 0
+-  /* TW: Missing code (calles int 2f) (650/302LV 1.10.6s; 1.10.7w doesn't do this) */
++  /* Missing code (calles int 2f) (650/302LV 1.10.6s; 1.10.7w doesn't do this) */
+   if(xxx()) {
+       SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0e,0xda);
+   }
+ #endif
+-  /* TW: Only for LVDS and 301LV/302LV */
++  /* Only for LVDS and 301LV/302LV */
+   if((SiS_Pr->SiS_IF_DEF_LVDS == 1) || (SiS_Pr->SiS_VBInfo & VB_SIS301LV302LV)){
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1e,0x20);
++     SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1e,0x20);
+   }
+-  return;
+ }
+ #endif  /* SIS 315 */
+@@ -1951,10 +2030,10 @@ void SiS_SetCRT2Offset(SiS_Private *SiS_
+   offset = SiS_GetOffset(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+                          HwDeviceExtension);
+-#if 0
+-  if(SiS_Pr->LCDResInfo == 13) offset >>= 1;
+-  if(SiS_Pr->LCDResInfo == 12) offset >>= 1;
+-#endif                         
++
++  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2 ||
++     SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3) offset >>= 1;
++
+   temp = (UCHAR)(offset & 0xFF);
+   SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07,temp);
+   temp = (UCHAR)((offset & 0xFF00) >> 8);
+@@ -1976,13 +2055,7 @@ SiS_GetOffset(SiS_Private *SiS_Pr, UCHAR
+   } else {
+      infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
+      modeinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeInfo;
+-  
+-     if(HwDeviceExtension->jChipType < SIS_315H ) {
+-      index = (modeinfo >> 4) & 0xFF;
+-     } else {
+-      index = (modeinfo >> 8) & 0xFF;
+-     }
+-
++     index = (modeinfo >> 8) & 0xFF;
+      temp = SiS_Pr->SiS_ScreenOffset[index];
+   }
+   
+@@ -1992,9 +2065,8 @@ SiS_GetOffset(SiS_Private *SiS_Pr, UCHAR
+   temp *= colordepth;
+-  /* TW: For 1400x1050 and 856x480 */
+-  if( ( ((ModeNo >= 0x26) && (ModeNo <= 0x28)) || 
+-        ModeNo == 0x3f || 
++  if( ( ((ModeNo >= 0x26) && (ModeNo <= 0x28)) ||
++        ModeNo == 0x3f ||
+       ModeNo == 0x42 || 
+       ModeNo == 0x45 ) ||
+       (SiS_Pr->UseCustomMode && (SiS_Pr->CHDisplay % 16)) ) {
+@@ -2012,7 +2084,8 @@ SiS_GetColorDepth(SiS_Private *SiS_Pr, U
+   SHORT  index;
+   USHORT modeflag;
+-  if(SiS_Pr->UseCustomMode) {
++  /* Do NOT check UseCustomMode, will skrew up FIFO */
++  if(ModeNo == 0xfe) {
+      modeflag = SiS_Pr->CModeFlag;
+   } else {
+      if(ModeNo <= 0x13)
+@@ -2035,7 +2108,11 @@ SiS_SetCRT2Sync(SiS_Private *SiS_Pr, USH
+   flag = 0;
+   tempbl = 0xC0;
+-  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 */
+@@ -2044,12 +2121,19 @@ SiS_SetCRT2Sync(SiS_Private *SiS_Pr, USH
+     } 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 |= 0xc0;
++       }
++    }
++
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+        if(HwDeviceExtension->jChipType >= SIS_315H) {
+           tempah >>= 3;
+@@ -2079,9 +2163,11 @@ SiS_SetCRT2Sync(SiS_Private *SiS_Pr, USH
+             tempah |= 0x20;
+             if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10;
++#if 0
+             if (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) {
+-              /* TW: BIOS does something here @@@ */
++              /* BIOS does something here @@@ */
+             }
++#endif
+           tempah &= 0x3f;
+           tempah |= tempbl;
+@@ -2089,16 +2175,11 @@ SiS_SetCRT2Sync(SiS_Private *SiS_Pr, USH
+          } else {                                                     /* 630 - 301 */
+-            if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+-               tempah = SiS_Pr->SiS_LCDInfo;
+-             if(SiS_Pr->SiS_LCDInfo & DontExpandLCDShift) { /* ! */
+-                flag = 1;
+-             }
+-            }
+-            if(flag != 1) tempah = infoflag >> 8;
++            tempah = infoflag >> 8;
+             tempah &= 0xC0;
+-            tempah |= 0x30;
+-            SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x3F,tempah);
++            tempah |= 0x20;
++          if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10;
++            SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah);
+          }
+@@ -2106,34 +2187,50 @@ SiS_SetCRT2Sync(SiS_Private *SiS_Pr, USH
+       } else {
+-#ifdef SIS315H  /* ----- 310/325 series ---- */
++#ifdef SIS315H  /* ------- 315 series ------ */
+-         if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {                  /* 310/325 - 30xLV */
++         if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {                  /* 315 - 30xLV */
++
++          if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
++             tempah = infoflag >> 8;
++             if(SiS_Pr->SiS_LCDInfo & LCDSync) {
++                tempah = SiS_Pr->SiS_LCDInfo;
++             }
++          } else {
++               tempah = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x37);
++          }
++          tempah &= 0xC0;
+-            tempah = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x37);
+-            tempah &= 0xC0;
+             tempah |= 0x20;
+             if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10;
+             SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah);
+-         } else {                                                     /* 310/325 - 301, 301B */
++         } else {                                                     /* 315 - 301, 301B */
+             tempah = infoflag >> 8;
+-            tempah &= 0xC0;
+-          if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+-             if(SiS_Pr->SiS_LCDInfo & LCDSync) {
+-                tempah = SiS_Pr->SiS_LCDInfo;
+-                tempah &= 0xC0;
++          if(!SiS_Pr->UseCustomMode) {
++             if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
++                if(SiS_Pr->SiS_LCDInfo & LCDSync) {
++                   tempah = SiS_Pr->SiS_LCDInfo;
++                }
+              }
+           }
++          tempah &= 0xC0;
+           
+             tempah |= 0x20;
+             if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10;
++
+ #if 0
+             if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) {
+-              /* TW: BIOS does something here @@@ */
++              /* BIOS does something here @@@ */
+             }
+-#endif            
++#endif
++
++          if(SiS_Pr->SiS_VBType & VB_NoLCD) {                 /* TEST, imitate BIOS bug */
++             if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
++                tempah |= 0xc0;
++             }
++          }
+             SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah);
+          } 
+@@ -2143,7 +2240,7 @@ SiS_SetCRT2Sync(SiS_Private *SiS_Pr, USH
+    }
+ }
+-/* TW: Set CRT2 FIFO on 300/630/730 */
++/* Set CRT2 FIFO on 300/630/730 */
+ #ifdef SIS300
+ void
+ SiS_SetCRT2FIFO_300(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,
+@@ -2197,7 +2294,7 @@ SiS_SetCRT2FIFO_300(SiS_Private *SiS_Pr,
+   if(!SiS_Pr->CRT1UsesCustomMode) {
+   
+-     CRT1ModeNo = SiS_Pr->SiS_CRT1Mode;                                 /* get CRT1 ModeNo */
++     CRT1ModeNo = SiS_Pr->SiS_CRT1Mode;                                       /* get CRT1 ModeNo */
+      SiS_SearchModeID(SiS_Pr,ROMAddr,&CRT1ModeNo,&modeidindex);
+      SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2);
+      SiS_Pr->SiS_SelectCRT2Rate = 0;
+@@ -2205,20 +2302,32 @@ SiS_SetCRT2FIFO_300(SiS_Private *SiS_Pr,
+                                               modeidindex,HwDeviceExtension);
+      if(CRT1ModeNo >= 0x13) {
+-       index = SiS_Pr->SiS_RefIndex[refreshratetableindex].Ext_CRTVCLK;
+-       index &= 0x3F;
+-       VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;                      /* Get VCLK */
+-       data2 = SiS_Pr->SiS_ModeType - 2;
++        index = SiS_Pr->SiS_RefIndex[refreshratetableindex].Ext_CRTVCLK;
++        index &= 0x3F;
++        VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;                             /* Get VCLK */
++
++      colorth = SiS_GetColorDepth(SiS_Pr,ROMAddr,CRT1ModeNo,modeidindex);     /* Get colordepth */
++        colorth >>= 1;
++        if(!colorth) colorth++;
+      }
+-     
++
+   } else {
+   
+      CRT1ModeNo = 0xfe;
+-     VCLK = SiS_Pr->CSRClock;                                         /* Get VCLK */
+-     data2 = (SiS_Pr->CModeFlag & ModeInfoFlag) - 2;
+-  
+-  }                   
+-     
++     VCLK = SiS_Pr->CSRClock_CRT1;                                            /* Get VCLK */
++     data2 = (SiS_Pr->CModeFlag_CRT1 & ModeInfoFlag) - 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;
++     }
++
++  }
++
+   if(CRT1ModeNo >= 0x13) {
+     if(HwDeviceExtension->jChipType == SIS_300) {
+        index = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x3A);
+@@ -2227,22 +2336,8 @@ SiS_SetCRT2FIFO_300(SiS_Private *SiS_Pr,
+     }
+     index &= 0x07;
+     MCLK = SiS_Pr->SiS_MCLKData_0[index].CLOCK;                               /* Get MCLK */
+-    
+-#ifdef TWDEBUG
+-    xf86DrvMsg(0, X_INFO, "FIFO2: CRT1Mode 0x%x VCLK %d MCLK %d modetype-2 = %d\n",
+-      CRT1ModeNo, VCLK, MCLK, data2);
+-#endif  
+-  
+-    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; break;
+-    }
+-    data2 = (colorth * VCLK) / MCLK;  
++
++    data2 = (colorth * VCLK) / MCLK;
+     temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
+     temp = ((temp & 0x00FF) >> 6) << 1;
+@@ -2252,22 +2347,12 @@ SiS_SetCRT2FIFO_300(SiS_Private *SiS_Pr,
+     data2 = temp - data2;
+     
+-#ifdef TWDEBUG
+-    xf86DrvMsg(0, X_INFO, "FIFO2: data2 (step1) = %d\n",
+-      data2);
+-#endif    
+-
+     if((28 * 16) % data2) {
+               data2 = (28 * 16) / data2;
+               data2++;
+     } else {
+               data2 = (28 * 16) / data2;
+     }
+-    
+-#ifdef TWDEBUG
+-    xf86DrvMsg(0, X_INFO, "FIFO2: data2 (step2) = %d\n",
+-      data2);
+-#endif
+     if(HwDeviceExtension->jChipType == SIS_300) {
+@@ -2313,10 +2398,6 @@ SiS_SetCRT2FIFO_300(SiS_Private *SiS_Pr,
+        temp &= 0x0F;   
+        tempal |= temp;
+-#ifdef TWDEBUG
+-       xf86DrvMsg(0, X_INFO, "FIFO2: Latencyfactorindex = 0x%x\n", tempal);
+-#endif
+-      
+        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;
+@@ -2341,7 +2422,7 @@ SiS_SetCRT2FIFO_300(SiS_Private *SiS_Pr,
+        SiS_SetReg4(0xcf8,0x800000A0);
+        eax = SiS_GetReg3(0xcfc);
+ #else
+-       /* TW: We use pci functions X offers. We use tag 0, because
++       /* 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.
+         */
+@@ -2368,43 +2449,41 @@ SiS_SetCRT2FIFO_300(SiS_Private *SiS_Pr,
+        if(!(temp & 0x80)) data += 5;
+     }
+     
+-#ifdef TWDEBUG    
+-    xf86DrvMsg(0, X_INFO, "FIFO2: latencyfactor (CRT1) = %d\n", data);
+-#endif
+-
+     data += data2;                            /* CRT1 Request Period */
+     
+-#ifdef TWDEBUG    
+-    xf86DrvMsg(0, X_INFO, "FIFO2: CRT1 request period = %d\n", data);
+-#endif
+-
+-    CRT2ModeNo = ModeNo;
+     SiS_Pr->SiS_SetFlag |= ProgrammingCRT2;
+     SiS_Pr->SiS_SelectCRT2Rate = SelectRate_backup;
+-    SiS_SearchModeID(SiS_Pr,ROMAddr,&CRT2ModeNo,&modeidindex);    
+-    refreshratetableindex = SiS_GetRatePtrCRT2(SiS_Pr,ROMAddr,CRT2ModeNo,
+-                                               modeidindex,HwDeviceExtension);
++    if(!SiS_Pr->UseCustomMode) {
++
++       CRT2ModeNo = ModeNo;
++       SiS_SearchModeID(SiS_Pr,ROMAddr,&CRT2ModeNo,&modeidindex);
++
++       refreshratetableindex = SiS_GetRatePtrCRT2(SiS_Pr,ROMAddr,CRT2ModeNo,
++                                                  modeidindex,HwDeviceExtension);
++
++       index = SiS_GetVCLK2Ptr(SiS_Pr,ROMAddr,CRT2ModeNo,modeidindex,
++                               refreshratetableindex,HwDeviceExtension);
++       VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;                              /* Get VCLK  */
++
++       if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) || (SiS_Pr->SiS_CustomT == CUT_BARCO1024)) {
++          if((ROMAddr) && SiS_Pr->SiS_UseROM) {
++           if(ROMAddr[0x220] & 0x01) {
++                VCLK = ROMAddr[0x229] | (ROMAddr[0x22a] << 8);
++           }
++          }
++       }
++
++    } else {
++
++       CRT2ModeNo = 0xfe;
++       VCLK = SiS_Pr->CSRClock;                                                       /* Get VCLK */
+-    index = SiS_GetVCLK2Ptr(SiS_Pr,ROMAddr,CRT2ModeNo,modeidindex,
+-                            refreshratetableindex,HwDeviceExtension);
+-    VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;                                 /* Get VCLK  */
+-    
+-    data2 = SiS_Pr->SiS_ModeType - 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; break;
+     }
+-    
+-#ifdef TWDEBUG    
+-    xf86DrvMsg(0, X_INFO, "FIFO2: CRT2Mode 0x%x VCLK %d MCLK %d modetype-2 = %d, colorth %d\n",
+-      CRT2ModeNo, VCLK, MCLK, data2, colorth);
+-#endif
++
++    colorth = SiS_GetColorDepth(SiS_Pr,ROMAddr,CRT2ModeNo,modeidindex);       /* Get colordepth */
++    colorth >>= 1;
++    if(!colorth) colorth++;
+     data = data * VCLK * colorth;
+     if(data % (MCLK << 4)) {
+@@ -2414,10 +2493,6 @@ SiS_SetCRT2FIFO_300(SiS_Private *SiS_Pr,
+               data = data / (MCLK << 4);
+     }
+     
+-#ifdef TWDEBUG    
+-    xf86DrvMsg(0, X_INFO, "FIFO2: data (unclipped) = 0x%x\n", data);
+-#endif    
+-    
+     if(data <= 6) data = 6;
+     if(data > 0x14) data = 0x14;
+@@ -2456,13 +2531,13 @@ SiS_SetCRT2FIFO_300(SiS_Private *SiS_Pr,
+ }
+ #endif
+-/* TW: Set FIFO on 310/325/330 series */
++/* Set FIFO on 315/330 series */
+ #ifdef SIS315H
+ void
+ SiS_SetCRT2FIFO_310(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,
+                     PSIS_HW_DEVICE_INFO HwDeviceExtension)
+ {
+-
++#if 0   /* This code is obsolete */
+   UCHAR CombCode[]  = { 1, 1, 1, 4, 3, 1, 3, 4,
+                         4, 1, 4, 4, 5, 1, 5, 4};
+   UCHAR CRT2ThLow[] = { 39, 63, 55, 79, 78,102, 90,114,
+@@ -2474,11 +2549,13 @@ SiS_SetCRT2FIFO_310(SiS_Private *SiS_Pr,
+   USHORT ModeIdIndex;
+   USHORT RefreshRateTableIndex;
+   USHORT SelectRate_backup;
+-  
++
+   SelectRate_backup = SiS_Pr->SiS_SelectCRT2Rate;
+-  
++#endif
++
+   SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x01,0x3B);
++#if 0
+   if(!SiS_Pr->CRT1UsesCustomMode) {
+   
+      CRT1ModeNo = SiS_Pr->SiS_CRT1Mode;                                 /* get CRT1 ModeNo */
+@@ -2489,28 +2566,27 @@ SiS_SetCRT2FIFO_310(SiS_Private *SiS_Pr,
+      /* Get REFIndex for crt1 refreshrate */
+      RefreshRateTableIndex = SiS_GetRatePtrCRT2(SiS_Pr,ROMAddr,CRT1ModeNo,
+-                                             ModeIdIndex,HwDeviceExtension);
++                                                ModeIdIndex,HwDeviceExtension);
++     index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
++     tempax = SiS_Pr->SiS_VCLKData[index].CLOCK;                      /* Get VCLK */
+-     index = SiS_GetVCLK2Ptr(SiS_Pr,ROMAddr,CRT1ModeNo,ModeIdIndex,
+-                          RefreshRateTableIndex,HwDeviceExtension);
+-     tempax = SiS_Pr->SiS_VCLKData[index].CLOCK;                        /* Get VCLK */
+-     
+      tempbx = SiS_GetColorDepth(SiS_Pr,ROMAddr,CRT1ModeNo,ModeIdIndex); /* Get colordepth */
+      tempbx >>= 1;
+-     if(!tempbx) tempbx++; 
+-     
++     if(!tempbx) tempbx++;
++
+   } else {
+-  
+-     tempax = SiS_Pr->CSRClock;                                               /* Get VCLK */
+-     tempbx = (SiS_Pr->CModeFlag & ModeInfoFlag) - 2;
++
++     CRT1ModeNo = 0xfe;
++     tempax = SiS_Pr->CSRClock_CRT1;                                  /* Get VCLK */
++     tempbx = (SiS_Pr->CModeFlag_CRT1 & ModeInfoFlag) - 2;
+      switch(tempbx) {                                                 /* Get color depth */
+-       case 0 :       tempbx = 1; break;
+-       case 1 :       tempbx = 1; break;
+-       case 2 :       tempbx = 2; break;
+-       case 3 :       tempbx = 2; break;
+-       case 4 :       tempbx = 3; break;
+-       case 5 :       tempbx = 4; break;
+-       default:       tempbx = 2; break;
++       case 0 : tempbx = 1; break;
++       case 1 : tempbx = 1; break;
++       case 2 : tempbx = 2; break;
++       case 3 : tempbx = 2; break;
++       case 4 : tempbx = 3; break;
++       case 5 : tempbx = 4; break;
++       default: tempbx = 2;
+      }
+   
+   }
+@@ -2523,13 +2599,6 @@ SiS_SetCRT2FIFO_310(SiS_Private *SiS_Pr,
+   tempbx = tempax;
+-#if 0 /* TW: BIOS code is skrewed */
+-  if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14) & 0x02) {
+-      tempax = 16;
+-  } else {
+-      tempax = 8;
+-  }
+-#endif
+   tempax = 16;
+   tempax -= tempbx;
+@@ -2556,24 +2625,33 @@ SiS_SetCRT2FIFO_310(SiS_Private *SiS_Pr,
+   tempcx +=  temp3;                                      /* CRT1 Request Period */
+-  CRT2ModeNo = ModeNo;                                                 /* get CRT2 ModeNo */
+-  SiS_SearchModeID(SiS_Pr,ROMAddr,&CRT2ModeNo,&ModeIdIndex);           /* Get ModeID Table */
+-
+   SiS_Pr->SiS_SetFlag |= ProgrammingCRT2;
+   SiS_Pr->SiS_SelectCRT2Rate = SelectRate_backup;
+-  RefreshRateTableIndex = SiS_GetRatePtrCRT2(SiS_Pr,ROMAddr,CRT2ModeNo,
+-                                           ModeIdIndex,HwDeviceExtension);
++  if(!SiS_Pr->UseCustomMode) {
++
++     CRT2ModeNo = ModeNo;                                                 /* get CRT2 ModeNo */
++     SiS_SearchModeID(SiS_Pr,ROMAddr,&CRT2ModeNo,&ModeIdIndex);
++
++     RefreshRateTableIndex = SiS_GetRatePtrCRT2(SiS_Pr,ROMAddr,CRT2ModeNo,
++                                                ModeIdIndex,HwDeviceExtension);
++
++     index = SiS_GetVCLK2Ptr(SiS_Pr,ROMAddr,CRT2ModeNo,ModeIdIndex,
++                             RefreshRateTableIndex,HwDeviceExtension);
++     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
++        tempax = SiS_Pr->SiS_VCLKData[index].CLOCK;                       /* Get VCLK  */
++     } else {
++        tempax = SiS_Pr->SiS_VBVCLKData[index].CLOCK;
++     }
+-  index = SiS_GetVCLK2Ptr(SiS_Pr,ROMAddr,CRT2ModeNo,ModeIdIndex,
+-                          RefreshRateTableIndex,HwDeviceExtension);
+-  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+-     tempax = SiS_Pr->SiS_VCLKData[index].CLOCK;                       /* Get VCLK  */
+   } else {
+-     tempax = SiS_Pr->SiS_VBVCLKData[index].CLOCK;                     /* Get VCLK  */
++
++     CRT2ModeNo = 0xfe;                                                         /* Get VCLK  */
++     tempax = SiS_Pr->CSRClock;
++
+   }
+-  tempbx = SiS_GetColorDepth(SiS_Pr,ROMAddr,CRT2ModeNo,ModeIdIndex);   /* Get colordepth */
++  tempbx = SiS_GetColorDepth(SiS_Pr,ROMAddr,CRT2ModeNo,ModeIdIndex);            /* Get colordepth */
+   tempbx >>= 1;
+   if(!tempbx) tempbx++;
+@@ -2590,12 +2668,16 @@ SiS_SetCRT2FIFO_310(SiS_Private *SiS_Pr,
+   if (tempax > 0x37)  tempax = 0x37;
+-  /* TW: 650/LVDS (1.10.07, 1.10.00), 650/301LV, 740, 330 overrule calculated value; 315 does not */
++  /* 650/LVDS, 650/301LV, 740, 330 overrule calculated value; 315 does not */
+   if(HwDeviceExtension->jChipType >= SIS_650) {
+       tempax = 0x04;
+   }
+-  
+   SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x02,~0x3F,tempax);
++#else
++
++  SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x02,~0x3F,0x04);
++
++#endif
+ }
+ USHORT
+@@ -2611,9 +2693,10 @@ SiS_GetMCLK(SiS_Private *SiS_Pr, UCHAR *
+     return(SiS_Pr->SiS_MCLKData_0[index].CLOCK);
+   }
+ }
++
+ #endif
+-/* TW: Checked against 650/LVDS 1.10.07 BIOS */
++/* Checked against 650/LVDS 1.10.07 BIOS */
+ void
+ SiS_GetLVDSDesData(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                    USHORT RefreshRateTableIndex,
+@@ -2623,7 +2706,15 @@ SiS_GetLVDSDesData(SiS_Private *SiS_Pr, 
+   USHORT PanelIndex,ResIndex;
+   const  SiS_LVDSDesStruct *PanelDesPtr = NULL;
+-  if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) ) {
++  if((SiS_Pr->UseCustomMode) ||
++     (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom) ||
++     (SiS_Pr->SiS_CustomT == CUT_PANEL848)) {
++     SiS_Pr->SiS_LCDHDES = 0;
++     SiS_Pr->SiS_LCDVDES = 0;
++     return;
++  }
++
++  if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+ #ifdef SIS315H  
+      SiS_GetLVDSDesPtrA(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+@@ -2689,11 +2780,11 @@ SiS_GetLVDSDesData(SiS_Private *SiS_Pr, 
+       case 52: PanelDesPtr = SiS_Pr->SiS_CHTVUPALDesData;    break;
+       case 53: PanelDesPtr = SiS_Pr->SiS_CHTVOPALDesData;    break;
+       default:
+-              if(HwDeviceExtension->jChipType < SIS_315H)
+-                 PanelDesPtr = SiS_Pr->SiS_PanelType0e_1;
+-              else
+-                 PanelDesPtr = SiS_Pr->SiS_PanelType01_1;
+-              break;
++               if(HwDeviceExtension->jChipType < SIS_315H)
++                  PanelDesPtr = SiS_Pr->SiS_PanelType0e_1;
++               else
++                  PanelDesPtr = SiS_Pr->SiS_PanelType01_1;
++               break;
+      }
+   }
+   SiS_Pr->SiS_LCDHDES = (PanelDesPtr+ResIndex)->LCDHDES;
+@@ -2710,7 +2801,7 @@ SiS_GetLVDSDesData(SiS_Private *SiS_Pr, 
+      } else {
+         if(!(SiS_Pr->SiS_SetFlag & SetDOSMode)) {
+            if( (HwDeviceExtension->jChipType < SIS_315H) || 
+-             (SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x1024) ) {  
++             (SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x1024) ) {
+               if(SiS_Pr->SiS_LCDResInfo >= SiS_Pr->SiS_Panel1024x768){
+                  if(ModeNo <= 0x13) {
+                   modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+@@ -2737,7 +2828,7 @@ SiS_GetLVDSDesData(SiS_Private *SiS_Pr, 
+         }
+      }
+   }
+-  return;
++
+ }
+ void
+@@ -2757,11 +2848,11 @@ SiS_GetLVDSDesPtr(SiS_Private *SiS_Pr, U
+   tempbx = 0;
+   if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+-     if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) {
++     if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+         tempbx = 50;
+         if((SiS_Pr->SiS_VBInfo & SetPALTV) && (!SiS_Pr->SiS_CHPALM)) tempbx += 2;
+         if(SiS_Pr->SiS_VBInfo & SetCHTVOverScan) tempbx += 1;
+-        /* TW: Nothing special needed for SOverscan    */
++        /* Nothing special needed for SOverscan    */
+         /*     PALM uses NTSC data, PALN uses PAL data */
+      }
+   }
+@@ -2773,7 +2864,7 @@ SiS_GetLVDSDesPtr(SiS_Private *SiS_Pr, U
+         if(modeflag & HalfDCLK) tempbx++;
+      }
+   }
+-  /* TW: 630/LVDS and 650/LVDS (1.10.07) BIOS */
++  /* 630/LVDS and 650/LVDS (1.10.07) BIOS */
+   if(SiS_Pr->SiS_SetFlag & SetDOSMode) {
+      if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480)  {
+         tempal = 0x07;
+@@ -2833,14 +2924,13 @@ SiS_SetCRT2ModeRegs(SiS_Private *SiS_Pr,
+      }
+   }
+   
+-  /* TW: BIOS does not do this (neither 301 nor LVDS) */
++  /* BIOS does not do this (neither 301 nor LVDS) */
+   /*     (But it's harmless; see SetCRT2Offset) */
+   SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x03,0x00);   /* fix write part1 index 0  BTDRAM bit Bug */
+-  /* TW: Removed 301B302B301LV302LV check here to match 650/LVDS BIOS */
+   if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+-      /* TW:   1. for LVDS/302B/302LV **LCDA** */
++      /*   1. for LVDS/302B/302LV **LCDA** */
+       SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x00,0xAF,0x40); /* FUNCTION CONTROL */
+       SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2E,0xF7);
+@@ -2855,23 +2945,23 @@ SiS_SetCRT2ModeRegs(SiS_Private *SiS_Pr,
+ #ifdef SIS300    /* ---- 300 series ---- */
+-      /* For 301BDH: */
++      /* For 301BDH: (with LCD via LVDS) */
+       if(SiS_Pr->SiS_VBType & VB_NoLCD) {
+-        temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x32);
+-        temp &= 0xef;
+-        temp |= 0x02;
+-        if((SiS_Pr->SiS_VBInfo & SetCRT2ToTV) || (SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) {
+-           temp |= 0x10;
+-           temp &= 0xfd;
+-        }
+-        SiS_SetReg1(SiS_Pr->SiS_P3c4,0x32,temp);
++       temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x32);
++       temp &= 0xef;
++       temp |= 0x02;
++       if((SiS_Pr->SiS_VBInfo & SetCRT2ToTV) || (SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) {
++          temp |= 0x10;
++          temp &= 0xfd;
++       }
++       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x32,temp);
+       }
+       if(ModeNo > 0x13) {
+-        tempcl -= ModeVGA;
+-        if((tempcl > 0) || (tempcl == 0)) {      /* TW: tempcl is USHORT -> always true! */
+-           tempah = ((0x10 >> tempcl) | 0x80);
+-        }
++         tempcl -= ModeVGA;
++         if((tempcl > 0) || (tempcl == 0)) {      /* tempcl is USHORT -> always true! */
++            tempah = ((0x10 >> tempcl) | 0x80);
++         }
+       } else tempah = 0x80;
+       if(SiS_Pr->SiS_VBInfo & SetInSlaveMode)  tempah ^= 0xA0;
+@@ -2880,7 +2970,7 @@ SiS_SetCRT2ModeRegs(SiS_Private *SiS_Pr,
+     } else {
+-#ifdef SIS315H    /* ---- 310/325/330 series ---- */
++#ifdef SIS315H    /* ------- 315/330 series ------ */
+       if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+          if(SiS_Pr->SiS_VBInfo & CRT2DisplayFlag) {
+@@ -2889,12 +2979,12 @@ SiS_SetCRT2ModeRegs(SiS_Private *SiS_Pr,
+       }
+       if(ModeNo > 0x13) {
+-        tempcl -= ModeVGA;
+-        if((tempcl > 0) || (tempcl == 0)) {  /* TW: tempcl is USHORT -> always true! */
+-           tempah = (0x08 >> tempcl);
+-           if (tempah == 0) tempah = 1;
+-           tempah |= 0x40;
+-        }
++         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(SiS_Pr->SiS_VBInfo & SetInSlaveMode)  tempah ^= 0x50;
+@@ -2921,7 +3011,7 @@ SiS_SetCRT2ModeRegs(SiS_Private *SiS_Pr,
+     if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+-      /* TW:   2. for 301 (301B, 302B 301LV, 302LV non-LCDA) */
++      /*   2. for 301 (301B, 302B 301LV, 302LV non-LCDA) */
+       tempah = 0x01;
+       if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+@@ -2938,7 +3028,7 @@ SiS_SetCRT2ModeRegs(SiS_Private *SiS_Pr,
+       if(HwDeviceExtension->jChipType < SIS_315H) {
+-              /* --- 300 series --- */
++              /* ---- 300 series ---- */
+                       tempah = (tempah << 5) & 0xFF;
+                       SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x01,tempah);
+@@ -2946,7 +3036,7 @@ SiS_SetCRT2ModeRegs(SiS_Private *SiS_Pr,
+       } else {
+-              /* --- 310 series --- */
++              /* ---- 315 series ---- */
+                       SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2E,0xF8,tempah);
+@@ -2956,9 +3046,9 @@ SiS_SetCRT2ModeRegs(SiS_Private *SiS_Pr,
+                       tempah |= 0x10;
+       }
+-      /* TW: 630/301 BIOS */
+       if((HwDeviceExtension->jChipType < SIS_315H) && (SiS_Pr->SiS_VBType & VB_SIS301)) {
+-              if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
++              if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) ||
++                 (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960)) {
+                       tempah |= 0x80;
+               }
+       } else {
+@@ -2996,28 +3086,31 @@ SiS_SetCRT2ModeRegs(SiS_Private *SiS_Pr,
+                     }
+          }
+       }
+-      /* TW: For 302LV dual-channel */
++
++      /* For 302LV dual-channel */
+       if(HwDeviceExtension->jChipType >= SIS_315H) {
+-          if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+-              if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04)
+-                  tempah |= 0x40;
+-          }
++         if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
++            if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04)
++               tempah |= 0x40;
++         }
+       }
+       if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) ||
+-         (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960)) {
+-              tempah |= 0x80;
++         (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960)  ||
++         ((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom) &&
++          (SiS_Pr->CP_MaxX >= 1280) && (SiS_Pr->CP_MaxY >= 960))) {
++         tempah |= 0x80;
+       }
+       SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0C,tempah);
+     } else {
+-      /* TW: 3. for LVDS */
++      /* 3. for LVDS */
+       if(HwDeviceExtension->jChipType >= SIS_315H) {
+-         /* TW: Inserted this entire section (BIOS 650/LVDS); added ModeType check
++         /* Inserted this entire section (BIOS 650/LVDS); added ModeType check
+           *     (LVDS can only be slave in 8bpp modes)
+           */
+          tempah = 0x80;
+@@ -3043,7 +3136,7 @@ SiS_SetCRT2ModeRegs(SiS_Private *SiS_Pr,
+       } else {
+-         /* TW: (added ModeType check) */
++         /* (added ModeType check) */
+          tempah = 0;
+          if( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) && (SiS_Pr->SiS_ModeType > ModeVGA) ) {
+                         tempah |= 0x02;
+@@ -3060,50 +3153,69 @@ SiS_SetCRT2ModeRegs(SiS_Private *SiS_Pr,
+   }
+-  /* TW: Inserted the entire following section */
++  /* Inserted the entire following section */
+   if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+       if(HwDeviceExtension->jChipType >= SIS_315H) {
+ #ifdef SIS315H
++
++         unsigned char bridgerev = SiS_GetReg1(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
++        * maker. Some BIOSes simply set the registers (like in the
++        * NoLCD-if-statements here), some set them according to the
++        * LCDA stuff. It is very likely that some machines are not
++        * treated correctly in the following, very case-orientated
++        * code. What do I do then...?
++        */
++
++       /* 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, HwDeviceExtension, BaseAddr))
++             if(SiS_IsDualEdge(SiS_Pr, HwDeviceExtension, BaseAddr)) {
+                 tempbl = 0xff;
++             }
+             }
+             SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,tempbl,tempah);   
+        }
+-       
+-       if(IS_SIS740) {                                                
++
++       /* 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); the b1 version in a
++        * 650 box (Jake). What is the criteria?
++        */
++
++       if(IS_SIS740) {
+           tempah = 0x30;
+           tempbl = 0xcf;
+           if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) {
+              tempah = 0x00;
+           }
+-          SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2c,tempbl,tempah);    
++          SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2c,tempbl,tempah);
++       } 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   */
++       } else if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
++          SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2c,0xCF,0x30);   /* For 30xLV */
++       } else if((SiS_Pr->SiS_VBType & VB_NoLCD) && (bridgerev == 0xb0)) {
++          SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2c,0xCF,0x30);   /* For 30xB-DH rev b0 (or "DH on 651"?) */
+        } else {
+-          /* TW: This in order to fix "TV-blue-bug" on 315+301 */
+-            if(SiS_Pr->SiS_VBType & VB_SIS301) {
+-             SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2c,0xCF);             /* For 301   */
+-          } else {
+-             if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+-                SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2c,0xCF,0x30);   /* For 30xLV */
+-             } else {
+-                tempah = 0x30;                                           /* For 301B  */
+-                tempbl = 0xcf;
+-                if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+-                   tempah = 0x00;
+-                   if(SiS_IsDualEdge(SiS_Pr, HwDeviceExtension, BaseAddr)) {
+-                      tempbl = 0xff;
+-                   }
+-                }
+-                SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2c,tempbl,tempah);    
++          tempah = 0x30;                                           /* For 30xB (and 301BDH rev b1) */
++          tempbl = 0xcf;
++          if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
++             tempah = 0x00;
++             if(SiS_IsDualEdge(SiS_Pr, HwDeviceExtension, BaseAddr)) {
++                tempbl = 0xff;
+              }
+           }
++          SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2c,tempbl,tempah);
+        }
+        if(IS_SIS740) {
+@@ -3111,25 +3223,25 @@ SiS_SetCRT2ModeRegs(SiS_Private *SiS_Pr,
+           tempbl = 0x3f;
+           if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) {
+              tempah = 0x00;
+-          } 
+-          SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x21,tempbl,tempah);     
++          }
++          SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x21,tempbl,tempah);
++       } else if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
++          SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x21,0x3f,0xc0);      /* For 30xLV */
++       } else if((SiS_Pr->SiS_VBType & VB_NoLCD) && (bridgerev == 0xb0)) {
++          SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x21,0x3f,0xc0);      /* For 30xB-DH rev b0 (or "DH on 651"? */
+        } else {
+-          if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {                 /* For 30xLV */
+-             SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x21,0x3f,0xc0);
+-          } else {                                                    /* For 301, 301B */ 
+-              tempah = 0xc0;
+-              tempbl = 0x3f;
+-              if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+-                 tempah = 0x00;
+-                 if(SiS_IsDualEdge(SiS_Pr, HwDeviceExtension, BaseAddr)) {
+-                    tempbl = 0xff;
+-                 }
+-              }
+-              SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x21,tempbl,tempah);     
++          tempah = 0xc0;                                              /* For 301, 301B (and 301BDH rev b1) */
++          tempbl = 0x3f;
++          if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
++             tempah = 0x00;
++             if(SiS_IsDualEdge(SiS_Pr, HwDeviceExtension, BaseAddr)) {
++                tempbl = 0xff;
++             }
+           }
++          SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x21,tempbl,tempah);
+        }
+-       if(IS_SIS740) {                                                
++       if(IS_SIS740) {
+           tempah = 0x80;
+           tempbl = 0x7f;
+           if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) {
+@@ -3141,8 +3253,9 @@ SiS_SetCRT2ModeRegs(SiS_Private *SiS_Pr,
+             tempbl = 0x7f;
+             if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+                tempbl = 0xff;
+-             if(!(SiS_IsDualEdge(SiS_Pr, HwDeviceExtension, BaseAddr)))
++             if(!(SiS_IsDualEdge(SiS_Pr, HwDeviceExtension, BaseAddr))) {
+                 tempah |= 0x80;
++             }
+             }
+             SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x23,tempbl,tempah);
+        }
+@@ -3174,16 +3287,32 @@ SiS_SetCRT2ModeRegs(SiS_Private *SiS_Pr,
+           tempbl = 0xfb;
+             if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+                tempah = 0x00;
+-             if(SiS_IsDualEdge(SiS_Pr, HwDeviceExtension, BaseAddr))
++             if(SiS_IsDualEdge(SiS_Pr, HwDeviceExtension, BaseAddr)) {
+                 tempbl = 0xff;
++             }
+             }
+           SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,tempbl,tempah);
+-          if(SiS_Pr->SiS_VBInfo & DisableCRT2Display)
++          if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) {
+              SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,0xfb,0x00);
++          }
+           SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2c,0xcf,0x30);
++       } else if(HwDeviceExtension->jChipType == SIS_550) {
++
++#if 0
++          tempah = 0x00;
++          tempbl = 0xfb;
++          if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) {
++             tempah = 0x00;
++             tempbl = 0xfb;
++          }
++          SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,tempbl,tempah);
++#endif
++          SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xfb);
++
++          SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2c,0xcf,0x30);
+        }
+       }
+@@ -3209,10 +3338,9 @@ SiS_GetCRT2Data(SiS_Private *SiS_Pr, UCH
+                             HwDeviceExtension);
+         } else {
+-         if( (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) &&
+-             (SiS_Pr->SiS_VBType & VB_NoLCD) ) {
+-             
+-            /* TW: Need LVDS Data for LCD on 301BDH */
++         if( (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (SiS_Pr->SiS_VBType & VB_NoLCD) ) {
++
++            /* Need LVDS Data for LCD on 301B-DH */
+             SiS_GetCRT2DataLVDS(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+                                 HwDeviceExtension);
+                                 
+@@ -3282,18 +3410,16 @@ SiS_GetCRT2DataLVDS(SiS_Private *SiS_Pr,
+    } else {
+-      /* TW: 301BDH needs LVDS Data */
+-      if( (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) &&
+-          (SiS_Pr->SiS_VBType & VB_NoLCD) ) {
++      /* 301BDH needs LVDS Data */
++      if( (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (SiS_Pr->SiS_VBType & VB_NoLCD) ) {
+             SiS_Pr->SiS_IF_DEF_LVDS = 1;
+       }
+       SiS_GetCRT2Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+                      &CRT2Index,&ResIndex,HwDeviceExtension);
+-      /* TW: 301BDH needs LVDS Data */
+-      if( (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) &&
+-          (SiS_Pr->SiS_VBType & VB_NoLCD) ) {
++      /* 301BDH needs LVDS Data */
++      if( (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (SiS_Pr->SiS_VBType & VB_NoLCD) ) {
+               SiS_Pr->SiS_IF_DEF_LVDS = 0;
+       }
+@@ -3321,11 +3447,18 @@ SiS_GetCRT2DataLVDS(SiS_Private *SiS_Pr,
+       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;
++      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;  /* TW: Super Overscan */
++      case 99:  LVDSData = SiS_Pr->SiS_CHTVSOPALData;        break;  /* Super Overscan */
+       default:  LVDSData = SiS_Pr->SiS_LVDS1024x768Data_1;   break;
+      }
+    }
+@@ -3337,67 +3470,36 @@ SiS_GetCRT2DataLVDS(SiS_Private *SiS_Pr,
+   if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+-    if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)){
+-         if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768){
+-           SiS_Pr->SiS_HDE = 1024;
+-           SiS_Pr->SiS_VDE =  768;
+-         } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024){
+-           SiS_Pr->SiS_HDE = 1280;
+-           SiS_Pr->SiS_VDE = 1024;
+-       } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050){
+-           SiS_Pr->SiS_HDE = 1400;
+-           SiS_Pr->SiS_VDE = 1050;
+-       } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200){
+-           SiS_Pr->SiS_HDE = 1600;
+-           SiS_Pr->SiS_VDE = 1200;
+-         } else {
+-         SiS_Pr->SiS_HDE = 1280;
+-         SiS_Pr->SiS_VDE =  960;
+-       }
+-    }
++     if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) {
++        SiS_Pr->SiS_HDE = SiS_Pr->PanelXRes;
++        SiS_Pr->SiS_VDE = SiS_Pr->PanelYRes;
++     }
+   } else {
+-    if(SiS_Pr->SiS_IF_DEF_TRUMPION == 0) {
+-      if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) {
+-        if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
+-          if((!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) || (SiS_Pr->SiS_SetFlag & SetDOSMode)) {
+-            if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) {
+-              SiS_Pr->SiS_HDE =  800;
+-              SiS_Pr->SiS_VDE =  600;
+-          } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) {
+-            SiS_Pr->SiS_HDE = 1024;
+-              SiS_Pr->SiS_VDE =  600;  
+-            } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+-              SiS_Pr->SiS_HDE = 1024;
+-              SiS_Pr->SiS_VDE =  768;
+-          } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768) {
+-            SiS_Pr->SiS_HDE = 1152;
+-            SiS_Pr->SiS_VDE =  768;   
+-          } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x864) {
+-            SiS_Pr->SiS_HDE = 1152;
+-            SiS_Pr->SiS_VDE =  864;  
+-          } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768) {
+-            SiS_Pr->SiS_HDE = 1280;
+-            SiS_Pr->SiS_VDE =  768;        
+-            } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
+-              SiS_Pr->SiS_HDE = 1280;
+-              SiS_Pr->SiS_VDE = 1024;
+-          } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+-            SiS_Pr->SiS_HDE = 1400;
+-              SiS_Pr->SiS_VDE = 1050;
+-          } else {
+-            SiS_Pr->SiS_HDE = 1600;
+-            SiS_Pr->SiS_VDE = 1200;
+-          }
+-            if(SiS_Pr->SiS_IF_DEF_FSTN) {
+-              SiS_Pr->SiS_HDE = 320;
+-              SiS_Pr->SiS_VDE = 480;
+-            }
+-          }
++     if(SiS_Pr->SiS_IF_DEF_TRUMPION == 0) {
++        if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) {
++           if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
++              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 0
++                 if(SiS_Pr->SiS_IF_DEF_FSTN) {
++                    SiS_Pr->SiS_HDE = 320;
++                    SiS_Pr->SiS_VDE = 480;
++                 }
++#endif
++              }
++           }
+         }
+-      }
+-    }
++     }
+   }
+ }
+@@ -3413,11 +3515,16 @@ SiS_GetCRT2Data301(SiS_Private *SiS_Pr, 
+   const SiS_TVDataStruct  *TVPtr  = NULL;
+   if(ModeNo <= 0x13) {
+-      modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+-      resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
++     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;
++     } else {
+       modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+       resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
++     }
+   }
+   
+   SiS_Pr->SiS_NewFlickerMode = 0;
+@@ -3429,17 +3536,26 @@ SiS_GetCRT2Data301(SiS_Private *SiS_Pr, 
+   SiS_GetCRT2ResInfo(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);
+-  /* TW: For VGA2 ("RAMDAC2") */
+-
+   if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC){
+-     SiS_GetRAMDAC2DATA(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+-                        HwDeviceExtension);
+-     return;
+-  }
+-  /* TW: For TV */
++     if(SiS_Pr->UseCustomMode) {
+-  if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
++        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_HDE       = SiS_Pr->SiS_VGAHDE;
++        SiS_Pr->SiS_VDE       = SiS_Pr->SiS_VGAVDE;
++
++     } else {
++
++        SiS_GetRAMDAC2DATA(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
++                           HwDeviceExtension);
++     }
++
++  } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+     SiS_GetCRT2Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+                    &CRT2Index,&ResIndex,HwDeviceExtension);
+@@ -3452,7 +3568,7 @@ SiS_GetCRT2Data301(SiS_Private *SiS_Pr, 
+       case  4:  TVPtr = SiS_Pr->SiS_ExtNTSCData;   break;
+       case  8:  TVPtr = SiS_Pr->SiS_StPALData;     break;
+       case  9:  TVPtr = SiS_Pr->SiS_StNTSCData;    break;
+-      default:  TVPtr = SiS_Pr->SiS_StPALData;     break;  /* TW: Just to avoid a crash */
++      default:  TVPtr = SiS_Pr->SiS_StPALData;     break;  /* Just to avoid a crash */
+     }
+     SiS_Pr->SiS_RVBHCMAX  = (TVPtr+ResIndex)->RVBHCMAX;
+@@ -3464,18 +3580,16 @@ SiS_GetCRT2Data301(SiS_Private *SiS_Pr, 
+     SiS_Pr->SiS_RVBHRS    = (TVPtr+ResIndex)->RVBHRS;
+     SiS_Pr->SiS_NewFlickerMode = (TVPtr+ResIndex)->FlickerMode;
+     if(modeflag & HalfDCLK) {
+-      SiS_Pr->SiS_RVBHRS    = (TVPtr+ResIndex)->HALFRVBHRS;
++      SiS_Pr->SiS_RVBHRS     = (TVPtr+ResIndex)->HALFRVBHRS;
+     }
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {  
+     
+        if(SiS_Pr->SiS_HiVision != 3) {
+-       
+-                if(resinfo == 0x08) SiS_Pr->SiS_NewFlickerMode = 0x40;
+-                if(resinfo == 0x09) SiS_Pr->SiS_NewFlickerMode = 0x40;
+-        if(resinfo == 0x12) SiS_Pr->SiS_NewFlickerMode = 0x40;
+-        
+-       } 
++                if(resinfo == SIS_RI_1024x768)  SiS_Pr->SiS_NewFlickerMode = 0x40;
++                if(resinfo == SIS_RI_1280x1024) SiS_Pr->SiS_NewFlickerMode = 0x40;
++        if(resinfo == SIS_RI_1280x720)  SiS_Pr->SiS_NewFlickerMode = 0x40;
++       }
+        
+        switch(SiS_Pr->SiS_HiVision) {
+        case 2:
+@@ -3504,119 +3618,136 @@ SiS_GetCRT2Data301(SiS_Private *SiS_Pr, 
+     } 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;
+-
+-      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_VBInfo & SetPALTV)) {
+-        SiS_Pr->SiS_HT = NTSCHT;
+-      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {  
+-         if((ModeNo == 0x4a) || (ModeNo == 0x38)) SiS_Pr->SiS_HT = NTSC2HT;
+-      }  
+-        SiS_Pr->SiS_VT = NTSCVT;
+-      } else {
+-        SiS_Pr->SiS_HT = PALHT;
+-        SiS_Pr->SiS_VT = PALVT;
+-      }
++       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(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
++          SiS_Pr->SiS_HT = NTSCHT;
++        if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
++           if((ModeNo == 0x64) || (ModeNo == 0x4a) || (ModeNo == 0x38)) SiS_Pr->SiS_HT = NTSC2HT;
++        }
++          SiS_Pr->SiS_VT = NTSCVT;
++       } else {
++          SiS_Pr->SiS_HT = PALHT;
++          SiS_Pr->SiS_VT = PALVT;
++       }
+     }
+-    return;
+-  }
++  } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+-  /* TW: For LCD */
++     if(SiS_Pr->UseCustomMode) {
+-  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
++        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_HDE       = SiS_Pr->SiS_VGAHDE;
++        SiS_Pr->SiS_VDE       = SiS_Pr->SiS_VGAVDE;
+-    SiS_GetCRT2Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+-                   &CRT2Index,&ResIndex,HwDeviceExtension);
++     } else {
++
++        SiS_GetCRT2Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
++                      &CRT2Index,&ResIndex,HwDeviceExtension);
++
++        switch(CRT2Index) {
++         case  0: LCDPtr = SiS_Pr->SiS_ExtLCD1024x768Data;        break; /* VESA Timing */
++         case  1: LCDPtr = SiS_Pr->SiS_ExtLCD1280x1024Data;       break; /* VESA Timing */
++         case  5: LCDPtr = SiS_Pr->SiS_StLCD1024x768Data;         break; /* Obviously unused */
++         case  6: LCDPtr = SiS_Pr->SiS_StLCD1280x1024Data;        break; /* Obviously unused */
++         case 10: LCDPtr = SiS_Pr->SiS_St2LCD1024x768Data;        break; /* Non-VESA Timing */
++         case 11: LCDPtr = SiS_Pr->SiS_St2LCD1280x1024Data;       break; /* Non-VESA Timing */
++         case 13: LCDPtr = SiS_Pr->SiS_NoScaleData1024x768;       break; /* Non-expanding */
++         case 14: LCDPtr = SiS_Pr->SiS_NoScaleData1280x1024;      break; /* Non-expanding */
++         case 15: LCDPtr = SiS_Pr->SiS_LCD1280x960Data;           break; /* 1280x960 */
++         case 20: LCDPtr = SiS_Pr->SiS_ExtLCD1400x1050Data;       break; /* VESA Timing */
++         case 21: LCDPtr = SiS_Pr->SiS_NoScaleData1400x1050;      break; /* Non-expanding (let panel scale) */
++         case 22: LCDPtr = SiS_Pr->SiS_StLCD1400x1050Data;        break; /* Non-VESA Timing (let panel scale) */
++         case 23: LCDPtr = SiS_Pr->SiS_ExtLCD1600x1200Data;       break; /* VESA Timing */
++         case 24: LCDPtr = SiS_Pr->SiS_NoScaleData1600x1200;      break; /* Non-expanding */
++         case 25: LCDPtr = SiS_Pr->SiS_StLCD1600x1200Data;        break; /* Non-VESA Timing */
++         case 26: LCDPtr = SiS_Pr->SiS_ExtLCD1280x768Data;        break; /* VESA Timing */
++         case 27: LCDPtr = SiS_Pr->SiS_NoScaleData1280x768;       break; /* Non-expanding */
++         case 28: LCDPtr = SiS_Pr->SiS_StLCD1280x768Data;         break; /* Non-VESA Timing */
++         case 29: LCDPtr = SiS_Pr->SiS_NoScaleData;             break; /* Generic no-scale data */
++#ifdef SIS315H
++       case 50: LCDPtr = (SiS_LCDDataStruct *)SiS310_ExtCompaq1280x1024Data;  break;
++       case 51: LCDPtr = SiS_Pr->SiS_NoScaleData1280x1024;                    break;
++       case 52: LCDPtr = SiS_Pr->SiS_St2LCD1280x1024Data;                     break;
++#endif
++         default: LCDPtr = SiS_Pr->SiS_ExtLCD1024x768Data;      break; /* Just to avoid a crash */
++        }
++
++        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;
+-    switch (CRT2Index) {
+-      case  0: LCDPtr = SiS_Pr->SiS_ExtLCD1024x768Data;        break; /* VESA Timing */
+-      case  1: LCDPtr = SiS_Pr->SiS_ExtLCD1280x1024Data;       break; /* VESA Timing */
+-      case  5: LCDPtr = SiS_Pr->SiS_StLCD1024x768Data;         break; /* Obviously unused */
+-      case  6: LCDPtr = SiS_Pr->SiS_StLCD1280x1024Data;        break; /* Obviously unused */
+-      case 10: LCDPtr = SiS_Pr->SiS_St2LCD1024x768Data;        break; /* Non-VESA Timing */
+-      case 11: LCDPtr = SiS_Pr->SiS_St2LCD1280x1024Data;       break; /* Non-VESA Timing */
+-      case 13: LCDPtr = SiS_Pr->SiS_NoScaleData1024x768;       break; /* Non-expanding */
+-      case 14: LCDPtr = SiS_Pr->SiS_NoScaleData1280x1024;      break; /* Non-expanding */
+-      case 15: LCDPtr = SiS_Pr->SiS_LCD1280x960Data;           break; /* 1280x960 */
+-      case 20: LCDPtr = SiS_Pr->SiS_ExtLCD1400x1050Data;       break; /* VESA Timing */
+-      case 21: LCDPtr = SiS_Pr->SiS_NoScaleData1400x1050;      break; /* Non-expanding (let panel scale) */
+-      case 22: LCDPtr = SiS_Pr->SiS_StLCD1400x1050Data;              break; /* Non-VESA Timing (let panel scale) */
+-      case 23: LCDPtr = SiS_Pr->SiS_ExtLCD1600x1200Data;       break; /* VESA Timing */
+-      case 24: LCDPtr = SiS_Pr->SiS_NoScaleData1600x1200;      break; /* Non-expanding */
+-      case 25: LCDPtr = SiS_Pr->SiS_StLCD1600x1200Data;              break; /* Non-VESA Timing */
+-      default: LCDPtr = SiS_Pr->SiS_ExtLCD1024x768Data;              break; /* Just to avoid a crash */
+-    }
+-
+-    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;
+-    
+ #ifdef TWDEBUG
+-    xf86DrvMsg(0, X_INFO,
+-      "GetCRT2Data: Index %d ResIndex %d\n", CRT2Index, ResIndex);
+-#endif    
++        xf86DrvMsg(0, X_INFO,
++          "GetCRT2Data: Index %d ResIndex %d\n", CRT2Index, ResIndex);
++#endif
+-    tempax = 1024;
+-    if(SiS_Pr->SiS_SetFlag & LCDVESATiming) {
+-      if(HwDeviceExtension->jChipType < SIS_315H) {
+-         if     (SiS_Pr->SiS_VGAVDE == 350) tempbx = 560;
+-         else if(SiS_Pr->SiS_VGAVDE == 400) tempbx = 640;
+-         else                               tempbx = 768;
+-      } else {      
+-         tempbx = 768; 
+-      }
+-    } 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                               tempbx = 768;
+-    }
+-    if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
+-      tempax = 1280;
+-      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                               tempbx = 1024;
+-    }
+-    if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960) {
+-      tempax = 1280;
+-      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                                tempbx = 960;
+-    }
+-    if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+-      tempax = 1400;
+-      tempbx = 1050;
+-    }
+-    if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) {
+-      tempax = 1600;
+-      tempbx = 1200;
+-    }
+-    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;
+-    return;
++      if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
++           tempax = 1024;
++           if(SiS_Pr->SiS_SetFlag & LCDVESATiming) {
++              if(HwDeviceExtension->jChipType < SIS_315H) {
++                 if     (SiS_Pr->SiS_VGAVDE == 350) tempbx = 560;
++                 else if(SiS_Pr->SiS_VGAVDE == 400) tempbx = 640;
++                 else                               tempbx = 768;
++              } else {
++                 tempbx = 768;
++              }
++           } 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                               tempbx = 768;
++           }
++      } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
++           tempax = 1280;
++           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                               tempbx = 1024;
++        } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960) {
++           tempax = 1280;
++           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                                tempbx = 960;
++        } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) {
++           tempax = 1600;
++           if     (SiS_Pr->SiS_VGAVDE == 350)  tempbx = 875;
++           else if(SiS_Pr->SiS_VGAVDE == 400)  tempbx = 1000;
++           else                                tempbx = 1200;
++        } else {
++         tempax = SiS_Pr->PanelXRes;
++           tempbx = SiS_Pr->PanelYRes;
++      }
++        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;
++     }
+   }
+ }
+@@ -3626,9 +3757,9 @@ SiS_GetResInfo(SiS_Private *SiS_Pr, UCHA
+   USHORT resindex;
+   if(ModeNo <= 0x13)
+-      resindex=SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
++     resindex=SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+   else
+-      resindex=SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
++     resindex=SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+   return(resindex);
+ }
+@@ -3639,41 +3770,46 @@ SiS_GetCRT2ResInfo(SiS_Private *SiS_Pr, 
+ {
+   USHORT xres,yres,modeflag=0,resindex;
++  if(SiS_Pr->UseCustomMode) {
++     SiS_Pr->SiS_VGAHDE = SiS_Pr->SiS_HDE = SiS_Pr->CHDisplay;
++     SiS_Pr->SiS_VGAVDE = SiS_Pr->SiS_VDE = SiS_Pr->CVDisplay;
++     return;
++  }
++
+   resindex = SiS_GetResInfo(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex);
+   if(ModeNo <= 0x13) {
+-      xres = SiS_Pr->SiS_StResInfo[resindex].HTotal;
+-      yres = SiS_Pr->SiS_StResInfo[resindex].VTotal;
++     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;
++     xres = SiS_Pr->SiS_ModeResInfo[resindex].HTotal;
++     yres = SiS_Pr->SiS_ModeResInfo[resindex].VTotal;
++     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+   }
+-  if((HwDeviceExtension->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_GetReg1(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((HwDeviceExtension->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_GetReg1(SiS_Pr->SiS_P3d4,0x3a) & 0x01) {
++         if(ModeNo == 0x12) yres = 400;
++        }
++     }
++
++     if(ModeNo > 0x13) {
++      if(modeflag & HalfDCLK)       xres *= 2;
++      if(modeflag & DoubleScanMode) yres *= 2;
++     }
+-  if(ModeNo > 0x13) {
+-      if(SiS_Pr->SiS_IF_DEF_FSTN == 1){
+-            xres *= 2;
+-            yres *= 2;
+-      } else {
+-          if(modeflag & HalfDCLK)       xres *= 2;
+-          if(modeflag & DoubleScanMode) yres *= 2;
+-      }
+   }
+   if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+         if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+            if(xres == 720) xres = 640;
+       } else {
+-         if(SiS_Pr->SiS_VBType & VB_NoLCD) {           /* TW: 301BDH */
++         if(SiS_Pr->SiS_VBType & VB_NoLCD) {           /* 301BDH */
+               if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+                    if(xres == 720) xres = 640;
+               }
+@@ -3694,17 +3830,16 @@ SiS_GetCRT2ResInfo(SiS_Private *SiS_Pr, 
+                if(xres == 720) xres = 640;
+             }
+             if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+-               if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
+-                  if(ModeNo <= 0x13) {
+-                     /* TW: This is wrong for 640x400 *graphics* mode */
++               if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
++                  if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) {
++                     /* BIOS bug - does this regardless of scaling */
+                              if(yres == 400) yres = 405;
+                   }
+                           if(yres == 350) yres = 360;
+                           if(SiS_Pr->SiS_SetFlag & LCDVESATiming) {
+                      if(yres == 360) yres = 375;
+                           }
+-               }
+-               if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768){
++               } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+                           if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {
+                      if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) {
+                         if(yres == 350) yres = 357;
+@@ -3719,12 +3854,15 @@ SiS_GetCRT2ResInfo(SiS_Private *SiS_Pr, 
+   } else {
+       if(xres == 720) xres = 640;
+       if(SiS_Pr->SiS_SetFlag & SetDOSMode) {
+-            yres = 400;
+-            if(HwDeviceExtension->jChipType >= SIS_315H) {
+-                if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x17) & 0x80) yres = 480;
+-            } else {
+-                if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13) & 0x80) yres = 480;
+-            }
++         yres = 400;
++         if(HwDeviceExtension->jChipType >= SIS_315H) {
++            if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x17) & 0x80) yres = 480;
++         } else {
++            if(SiS_GetReg1(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;
+@@ -3739,6 +3877,13 @@ SiS_GetCRT2Ptr(SiS_Private *SiS_Pr, UCHA
+   USHORT tempbx=0,tempal=0;
+   USHORT Flag,resinfo=0;
++  if(ModeNo <= 0x13) {
++     tempal = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
++  } else {
++     tempal = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
++     resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
++  }
++
+   if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+       if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {                            /* LCD */
+@@ -3753,19 +3898,44 @@ SiS_GetCRT2Ptr(SiS_Private *SiS_Pr, UCHA
+                       tempbx = 23;
+                       if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)         tempbx = 24;
+                       else if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx = 25;
++#if 0
++              } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768) {
++                      tempbx = 26;
++                      if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)         tempbx = 27;
++                      else if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx = 28;
++#endif
+               } else if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+-                      tempbx = 13;
+-                      if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) tempbx++;
++                      if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
++                         if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)       tempbx = 13;
++                         else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) tempbx = 14;
++                         else                                                          tempbx = 29;
++                      } else {
++                         tempbx = 29;
++                         if(ModeNo >= 0x13) {
++                            /* 1280x768 and 1280x960 have same CRT2CRTC,
++                             * so we change it here if 1280x960 is chosen
++                             */
++                            if(resinfo == SIS_RI_1280x960) tempal = 10;
++                         }
++                      }
+               } else {
+                          tempbx = SiS_Pr->SiS_LCDResInfo - SiS_Pr->SiS_Panel1024x768;
+                          if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {
+                       tempbx += 5;
+                         /* GetRevisionID();  */
+-                      /* TW: BIOS only adds 5 once */
++                      /* BIOS only adds 5 once */
+                       tempbx += 5;
+                          }
+               }
++#ifdef SIS315H
++              if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
++                 tempbx = 50;
++                 if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)         tempbx = 51;
++                 else if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx = 52;
++              }
++#endif
++
+       } else {                                                        /* TV */
+       
+                       if((SiS_Pr->SiS_VBType & VB_SIS301B302B) &&
+@@ -3773,7 +3943,7 @@ SiS_GetCRT2Ptr(SiS_Private *SiS_Pr, UCHA
+                       if(SiS_Pr->SiS_VGAVDE > 480) SiS_Pr->SiS_SetFlag &= (~TVSimuMode);
+                       tempbx = 2;
+                       if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+-                              if(!(SiS_Pr->SiS_SetFlag & TVSimuMode)) tempbx = 12; 
++                              if(!(SiS_Pr->SiS_SetFlag & TVSimuMode)) tempbx = 12;
+                       }
+                       } else {
+                       if(SiS_Pr->SiS_VBInfo & SetPALTV) tempbx = 3;
+@@ -3783,34 +3953,18 @@ SiS_GetCRT2Ptr(SiS_Private *SiS_Pr, UCHA
+               
+       }
+-      if(ModeNo <= 0x13) {
+-                      tempal = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+-      } else {
+-                      tempal = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+-              resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+-        }
+-
+-      tempal &= 0x3F;
+-
+-              if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) &&
+-           (SiS_Pr->SiS_VBInfo & (SetCRT2ToTV-SetCRT2ToHiVisionTV))) {
+-                      if(tempal == 0x06) tempal = 0x07;
+-        }
+-
+-      /* TW: 300/301LV BIOS */
+-      if((HwDeviceExtension->jChipType == SIS_300) &&
+-         (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) {
+-          if(ModeNo > 0x13) {
+-              if((resinfo == 0x0c) || (resinfo == 0x0d))  /* 720 (index diff. on 310/325!) */
+-                  tempal = 6;
+-          }
+-      }
++        tempal &= 0x3F;
+-      if(HwDeviceExtension->jChipType != SIS_300) {
+-           if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+-              if((ModeNo == 0x31) || (ModeNo == 0x32)) tempal = 6;
++              if(SiS_Pr->SiS_VBInfo & (SetCRT2ToTV - SetCRT2ToHiVisionTV)) {
++         if(ModeNo > 0x13) {
++                    if(tempal == 6) tempal = 7;
++              if((resinfo == SIS_RI_720x480) ||
++               (resinfo == SIS_RI_720x576) ||
++               (resinfo == SIS_RI_768x576)) {
++               tempal = 6;
++            }
+          }
+-      }
++        }
+       *CRT2Index = tempbx;
+       *ResIndex = tempal;
+@@ -3820,25 +3974,22 @@ SiS_GetCRT2Ptr(SiS_Private *SiS_Pr, UCHA
+       Flag = 1;
+       tempbx = 0;
+       if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+-      
+-                      if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) {
+-                      Flag = 0;
+-                      tempbx = 10;
+-                      if(SiS_Pr->SiS_VBInfo & SetCHTVOverScan) tempbx += 1;
+-                      if(SiS_Pr->SiS_VBInfo & SetPALTV) {
+-                              tempbx += 2;
+-                              if(SiS_Pr->SiS_CHSOverScan) tempbx = 99;
+-                              if(SiS_Pr->SiS_CHPALM) {
+-                                      tempbx = 90;
+-                                      if(SiS_Pr->SiS_VBInfo & SetCHTVOverScan) tempbx += 1;
+-                              } else if(SiS_Pr->SiS_CHPALN) {
+-                                      tempbx = 92;
+-                                      if(SiS_Pr->SiS_VBInfo & SetCHTVOverScan) tempbx += 1;
+-                              }
+-                              
+-                      }
+-                      }
+-              
++                 if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) {
++              Flag = 0;
++              tempbx = 10;
++            if(SiS_Pr->SiS_VBInfo & SetCHTVOverScan) tempbx += 1;
++              if(SiS_Pr->SiS_VBInfo & SetPALTV) {
++               tempbx += 2;
++               if(SiS_Pr->SiS_CHSOverScan) tempbx = 99;
++               if(SiS_Pr->SiS_CHPALM) {
++                  tempbx = 90;
++                  if(SiS_Pr->SiS_VBInfo & SetCHTVOverScan) tempbx += 1;
++               } else if(SiS_Pr->SiS_CHPALN) {
++                  tempbx = 92;
++                  if(SiS_Pr->SiS_VBInfo & SetCHTVOverScan) tempbx += 1;
++               }
++              }
++           }
+       }
+       if(Flag) {
+@@ -3846,11 +3997,19 @@ SiS_GetCRT2Ptr(SiS_Private *SiS_Pr, UCHA
+               if(SiS_Pr->SiS_LCDResInfo <= SiS_Pr->SiS_Panel1280x1024) {
+                  tempbx = SiS_Pr->SiS_LCDResInfo - SiS_Pr->SiS_PanelMinLVDS;
+                  if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)  tempbx += 3;
++                 if(SiS_Pr->SiS_CustomT == CUT_BARCO1024) {
++                    tempbx = 82;
++                    if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)  tempbx++;
++                 }
+               } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768) {
+                  tempbx = 18;
+                  if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)  tempbx++; 
+-              } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) { 
++              } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) {
+                  tempbx = 6;
++              } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2) {
++                 tempbx = 30;
++              } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3) {
++                 tempbx = 30;
+               } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) {
+                  tempbx = 15;
+                  if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)  tempbx += 2;
+@@ -3863,27 +4022,30 @@ SiS_GetCRT2Ptr(SiS_Private *SiS_Pr, UCHA
+               } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) {
+                  tempbx = 21;
+                  if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)  tempbx++;
++              } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelBarco1366) {
++                 tempbx = 80;
++                 if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)  tempbx++;
+               }
+-              
++
+               if(SiS_Pr->SiS_LCDInfo & LCDPass11) {
+                  tempbx = 7;
+               }
+-              
+-      }
+-      if(ModeNo <= 0x13)
+-                      tempal = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+-      else {
+-                      tempal = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+-              resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
++              if(SiS_Pr->SiS_CustomT == CUT_PANEL848) {
++                 tempbx = 84;
++                 if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)  tempbx++;
++              }
++
+       }
++#if 0
+       if(SiS_Pr->SiS_IF_DEF_FSTN){
+                       if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel320x480){
+                       tempbx = 14;
+                       tempal = 6;
+               }
+       }
++#endif
+       if(SiS_Pr->SiS_SetFlag & SetDOSMode) {
+               if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) tempal = 7;
+@@ -3895,13 +4057,10 @@ SiS_GetCRT2Ptr(SiS_Private *SiS_Pr, UCHA
+       if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+           if(ModeNo > 0x13) {
+-              if(HwDeviceExtension->jChipType < SIS_315H) {
+-                 if((resinfo == 0x0c) || (resinfo == 0x0d))  /* 720 */
+-                     tempal = 6;
+-              } else {
+-                 if((resinfo == 0x0d) || (resinfo == 0x0e))  /* 720 */
+-                     tempal = 6;
+-              }
++             if((resinfo == SIS_RI_720x480) ||
++                (resinfo == SIS_RI_720x576) ||
++                (resinfo == SIS_RI_768x576))
++                tempal = 6;
+           }
+       }
+@@ -3940,7 +4099,7 @@ SiS_GetCRT2PtrA(SiS_Private *SiS_Pr, UCH
+ void
+ SiS_GetCRT2Part2Ptr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                   USHORT RefreshRateTableIndex,USHORT *CRT2Index,
+-                  USHORT *ResIndex)
++                  USHORT *ResIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
+ {
+   USHORT tempbx,tempal;
+@@ -3954,6 +4113,16 @@ SiS_GetCRT2Part2Ptr(SiS_Private *SiS_Pr,
+   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)      tempbx += 16;
+   else if(SiS_Pr->SiS_SetFlag & LCDVESATiming) tempbx += 32;
++#ifdef SIS315H
++  if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
++     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
++        tempbx = 100;
++        if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)      tempbx = 101;
++      else if(SiS_Pr->SiS_SetFlag & LCDVESATiming) tempbx = 102;
++     }
++  }
++#endif
++
+   *CRT2Index = tempbx;
+   *ResIndex = tempal & 0x3F;
+ }
+@@ -3962,15 +4131,17 @@ USHORT
+ SiS_GetRatePtrCRT2(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT ModeNo, USHORT ModeIdIndex,
+                    PSIS_HW_DEVICE_INFO HwDeviceExtension)
+ {
+-  SHORT  LCDRefreshIndex[] = { 0x00, 0x00, 0x03, 0x01,
++  SHORT  LCDRefreshIndex[] = { 0x00, 0x00, 0x01, 0x01,
+                                0x01, 0x01, 0x01, 0x01,
+                              0x01, 0x01, 0x01, 0x01,
+-                             0x01, 0x01, 0x01, 0x01 };
++                             0x01, 0x01, 0x01, 0x01,
++                             0x00, 0x00, 0x00, 0x00 };
+   USHORT RefreshRateTableIndex,i,backup_i;
+   USHORT modeflag,index,temp,backupindex;
+-  if(SiS_Pr->UseCustomMode) 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
+@@ -3984,7 +4155,7 @@ SiS_GetRatePtrCRT2(SiS_Private *SiS_Pr, 
+   if(ModeNo < 0x14) return(0xFFFF);
+- /* TW: CR33 holds refresh rate index for CRT1 [3:0] and CRT2 [7:4].
++ /* CR33 holds refresh rate index for CRT1 [3:0] and CRT2 [7:4].
+   *     On LVDS machines, CRT2 index is always 0 and will be
+   *     set to 0 by the following code; this causes the function
+   *     to take the first non-interlaced mode in SiS_Ext2Struct
+@@ -3998,40 +4169,38 @@ SiS_GetRatePtrCRT2(SiS_Private *SiS_Pr, 
+   if(index > 0) index--;
+   if(SiS_Pr->SiS_SetFlag & ProgrammingCRT2) {
+-      if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
++     if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+         if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA))  index = 0;
+-      } else {
++     } else {
+         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_VBType & VB_NoLCD)
++            index = 0;
++         else if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)
++            index = backupindex = 0;
+       }
+-      }
+-  }
++     }
+-  if(SiS_Pr->SiS_SetFlag & ProgrammingCRT2) {
+-      if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+-                      if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+-                      index = 0;
+-                      }
+-      }
+-      if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+-                      if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+-                      if(!(SiS_Pr->SiS_VBType & VB_NoLCD)) {
+-                         temp = LCDRefreshIndex[SiS_Pr->SiS_LCDResInfo];
+-                         if(index > temp) index = temp;
+-                      }
+-                      } else {
+-                      index = 0;
+-                      }
+-      }
++     if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
++        if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
++           index = 0;
++        }
++     }
++     if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
++        if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
++         if(!(SiS_Pr->SiS_VBType & VB_NoLCD)) {
++              temp = LCDRefreshIndex[SiS_Pr->SiS_LCDResInfo];
++              if(index > temp) index = temp;
++         }
++              } else {
++           index = 0;
++              }
++     }
+   }
+   RefreshRateTableIndex = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
+   ModeNo = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].ModeID;
+-  /* TW: 650/LVDS 1.10.07, 650/30xLV 1.10.6s */
++  /* 650/LVDS 1.10.07, 650/30xLV 1.10.6s */
+   if(HwDeviceExtension->jChipType >= SIS_315H) {
+      if(!(SiS_Pr->SiS_VBInfo & DriverMode)) {
+         if( (SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_VESAID == 0x105) ||
+@@ -4066,7 +4235,7 @@ SiS_GetRatePtrCRT2(SiS_Private *SiS_Pr, 
+       backup_i = i;
+       if (!(SiS_AdjustCRT2Rate(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
+                                    RefreshRateTableIndex,&i,HwDeviceExtension))) {
+-              /* TW: This is for avoiding random data to be used; i is
++              /* This is for avoiding random data to be used; i is
+                *     in an undefined state if no matching CRT2 mode is
+                *     found.
+                */
+@@ -4085,196 +4254,199 @@ SiS_AdjustCRT2Rate(SiS_Private *SiS_Pr, 
+   USHORT tempax,tempbx,resinfo;
+   USHORT modeflag,infoflag;
+-  if (ModeNo <= 0x13)
++  if(ModeNo <= 0x13) {
+       modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+-  else
++      resinfo = 0;
++  } else {
+       modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
++        resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
++  }
+-  resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+   tempbx = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex + (*i)].ModeID;
+   tempax = 0;
++
+   if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
++
+       if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) {
+                       tempax |= SupportRAMDAC2;
+               if(HwDeviceExtension->jChipType >= SIS_315H) {
+-                  tempax |= SupportTV;
+-                  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+-                      if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+-                          if(resinfo == 0x0a) tempax |= SupportTV1024;
+-                      }
+-                  }
++                 tempax |= SupportTV;
++                 if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
++                    if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
++                       if(resinfo == SIS_RI_1600x1200) tempax |= SupportTV1024;
++                    }
++                 }
+               }
+-      }
+-      if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
++      } else if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+                       tempax |= SupportLCD;
+               if(HwDeviceExtension->jChipType >= SIS_315H) {
+                    if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1600x1200) {
+                     if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1400x1050) {
+-                       if((resinfo == 6) && (SiS_Pr->SiS_LCDInfo & DontExpandLCD)) {
++                       if((resinfo == SIS_RI_640x480) && (SiS_Pr->SiS_LCDInfo & DontExpandLCD)) {
+                           (*i) = 0;
+                             return(1);
+                        } else {
+                                   if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x1024) {
+-                            if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x960) {
+-                              if((resinfo == 6) && (SiS_Pr->SiS_LCDInfo & DontExpandLCD)) {
+-                                  return(0);
+-                              } else {
+-                                  if((resinfo >= 9) && (resinfo != 0x14)) {
++                             if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x960) {
++                                if((resinfo == SIS_RI_640x480) && (SiS_Pr->SiS_LCDInfo & DontExpandLCD)) {
++                                   return(0);
++                                } else {
++                                   if((resinfo >= SIS_RI_1280x1024) && (resinfo != SIS_RI_1280x768)) {
+                                               return(0);
+-                                  }
+-                              }
+-                            }
++                                   }
++                                }
++                             }
+                           }
+                        }
+                     }
+                          }
+               } else {
+                 if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) {
+-                   if((resinfo != 0x0f) && ((resinfo == 4) || (resinfo >= 8))) return(0);
++                   if( (resinfo != SIS_RI_1024x600) &&
++                       ((resinfo == SIS_RI_512x384) || (resinfo >= SIS_RI_1024x768))) return(0);
+                 } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768) {
+-                   if((resinfo != 0x10) && (resinfo > 8)) return(0);
++                   if((resinfo != SIS_RI_1152x768) && (resinfo > SIS_RI_1024x768)) return(0);
+                 } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960) {
+-                   if((resinfo != 0x0e) && (resinfo > 8)) return(0);
++                   if((resinfo != SIS_RI_1280x960) && (resinfo > SIS_RI_1024x768)) return(0);
+                 } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
+-                   if(resinfo > 9) return(0);
++                   if(resinfo > SIS_RI_1280x1024) return(0);
+                 } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+-                   if(resinfo > 8) return(0);
++                   if(resinfo > SIS_RI_1024x768) return(0);
+                 } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) {
+-                   if((resinfo == 4) || (resinfo > 7)) return(0);
++                   if((resinfo == SIS_RI_512x384) || (resinfo > SIS_RI_800x600)) return(0);
+                 } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) {
+-                   if((resinfo == 4) || (resinfo == 3) || (resinfo > 6)) return(0);
++                   if((resinfo == SIS_RI_512x384) ||
++                      (resinfo == SIS_RI_400x300) ||
++                      (resinfo > SIS_RI_640x480)) return(0);
+                 }
+               }
+-      }
+-      if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) { 
++      } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {
+               if(SiS_Pr->SiS_HiVision == 3) {
+                       tempax |= SupportHiVisionTV2;
+                               if(SiS_Pr->SiS_VBInfo & SetInSlaveMode){
+-                              if(resinfo == 4) return(0);
+-                              if(resinfo == 3) return(0);
+-                              if(resinfo == 7) {
++                              if(resinfo == SIS_RI_512x384) return(0);
++                              if(resinfo == SIS_RI_400x300) return(0);
++                              if(resinfo == SIS_RI_800x600) {
+                                       if(SiS_Pr->SiS_SetFlag & TVSimuMode) return(0);
+                               }
+-                              if(resinfo > 7) return(0);
++                              if(resinfo > SIS_RI_800x600) return(0);
+                       }
+               } else {  
+                               tempax |= SupportHiVisionTV;
+                               if(SiS_Pr->SiS_VBInfo & SetInSlaveMode){
+-                              if(resinfo == 4) return(0);
+-                              if((resinfo == 3) || (resinfo == 7)) {
++                              if(resinfo == SIS_RI_512x384) return(0);
++                              if((resinfo == SIS_RI_400x300) || (resinfo == SIS_RI_800x600)) {
+                                       if(SiS_Pr->SiS_SetFlag & TVSimuMode) return(0);
+                               }
+-                              if(resinfo > 7) return(0);
++                              if(resinfo > SIS_RI_800x600) return(0);
+                       }
+               }
+-      } else {
+-                 if(SiS_Pr->SiS_VBInfo & (SetCRT2ToAVIDEO|SetCRT2ToSVIDEO|SetCRT2ToSCART)) {
++      } else if(SiS_Pr->SiS_VBInfo & (SetCRT2ToAVIDEO|SetCRT2ToSVIDEO|SetCRT2ToSCART)) {
+               tempax |= SupportTV;
+               tempax |= SupportTV1024;
+               if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+-                  if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+-                      if((SiS_Pr->SiS_VBInfo & SetNotSimuMode) && (SiS_Pr->SiS_VBInfo & SetPALTV)) {
+-                           if(resinfo != 8) {
+-                               if( (!(SiS_Pr->SiS_VBInfo & SetPALTV)) ||
+-                                   ((SiS_Pr->SiS_VBInfo & SetPALTV) && (resinfo != 4)) ) {
+-                                   tempax &= ~(SupportTV1024);
+-                                   if(HwDeviceExtension->jChipType >= SIS_315H) {
+-                                         if((modeflag & NoSupportSimuTV) && (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+-                                           if( (!(SiS_Pr->SiS_VBInfo & SetPALTV)) ||
+-                                               ((SiS_Pr->SiS_VBInfo & SetPALTV) && (resinfo != 7)) ) {
+-                                               if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) return(0);
+-                                           }
+-                                       }
+-                                   } else {
+-                                       if( (resinfo != 3) ||
+-                                           (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
+-                                           (SiS_Pr->SiS_VBInfo & SetNotSimuMode) ) {
+-                                           if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+-                                               if((modeflag & NoSupportSimuTV) && (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+-                                                   if(resinfo == 3) return(0);
+-                                                   if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) return (0);
+-                                               }
+-                                           }
+-                                         } else return(0);
+-                                   }
+-                               }
+-                           }
+-                      } else {
+-                          tempax &= ~(SupportTV1024);
+-                          if(HwDeviceExtension->jChipType >= SIS_315H) {
+-                              if((modeflag & NoSupportSimuTV) && (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+-                                  if( (!(SiS_Pr->SiS_VBInfo & SetPALTV)) ||
+-                                      ((SiS_Pr->SiS_VBInfo & SetPALTV) && (resinfo != 7)) ) {
++                 if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
++                    if((SiS_Pr->SiS_VBInfo & SetNotSimuMode) && (SiS_Pr->SiS_VBInfo & SetPALTV)) {
++                       if(resinfo != SIS_RI_1024x768) {
++                          if( (!(SiS_Pr->SiS_VBInfo & SetPALTV)) ||
++                              ((SiS_Pr->SiS_VBInfo & SetPALTV) && (resinfo != SIS_RI_512x384)) ) {
++                             tempax &= ~(SupportTV1024);
++                             if(HwDeviceExtension->jChipType >= SIS_315H) {
++                                  if((modeflag & NoSupportSimuTV) && (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
++                                   if( (!(SiS_Pr->SiS_VBInfo & SetPALTV)) ||
++                                       ((SiS_Pr->SiS_VBInfo & SetPALTV) && (resinfo != SIS_RI_800x600)) ) {
+                                       if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) return(0);
+-                                  }
+-                              }
+-                          } else {
+-                              if( (resinfo != 3) ||
+-                                  (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
+-                                  (SiS_Pr->SiS_VBInfo & SetNotSimuMode) ) {
+-                                   if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+-                                       if((modeflag & NoSupportSimuTV) && (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+-                                           if(resinfo == 3) return(0);
+-                                           if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) return (0);
+-                                       }
+                                    }
+-                                } else return(0);
+-                            }
+-                      }
+-                  } else {  /* slavemode */
+-                      if(resinfo != 8) {
+-                          if( (!(SiS_Pr->SiS_VBInfo & SetPALTV)) ||
+-                              ((SiS_Pr->SiS_VBInfo & SetPALTV) && (resinfo != 4) ) ) {
+-                               tempax &= ~(SupportTV1024);
+-                               if(HwDeviceExtension->jChipType >= SIS_315H) {
+-                                   if((modeflag & NoSupportSimuTV) && (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+-                                       if( (!(SiS_Pr->SiS_VBInfo & SetPALTV)) ||
+-                                           ((SiS_Pr->SiS_VBInfo & SetPALTV) && (resinfo != 7)) ) {
+-                                           if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode))  return(0);
+-                                       }
++                                }
++                             } else {
++                                if( (resinfo != SIS_RI_400x300) ||
++                                    (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
++                                    (SiS_Pr->SiS_VBInfo & SetNotSimuMode) ) {
++                                   if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
++                                      if((modeflag & NoSupportSimuTV) && (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
++                                         if(resinfo == SIS_RI_400x300) return(0);
++                                         if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) return (0);
++                                      }
+                                    }
+-                              } else {
+-                                  if( (resinfo != 3) ||
+-                                      (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
+-                                      (SiS_Pr->SiS_VBInfo & SetNotSimuMode) ) {
+-                                       if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+-                                           if((modeflag & NoSupportSimuTV) && (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+-                                               if(resinfo == 3) return(0);
+-                                               if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) return (0);
+-                                           }
+-                                       }
+-                                    } else return(0);
+-                              }
++                                  } else return(0);
++                             }
+                           }
+-                      }
+-                  }
+-              } else {   /* 301 */
+-                  tempax &= ~(SupportTV1024);
+-                  if(HwDeviceExtension->jChipType >= SIS_315H) {
+-                      if((modeflag & NoSupportSimuTV) && (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+-                          if( (!(SiS_Pr->SiS_VBInfo & SetPALTV)) ||
+-                              ((SiS_Pr->SiS_VBInfo & SetPALTV) && (resinfo != 7)) ) {
+-                              if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) return(0);
+-                          }
+-                      }
+-                  } else {
+-                      if( (resinfo != 3) ||
+-                          (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
+-                          (SiS_Pr->SiS_VBInfo & SetNotSimuMode) ) {
+-                          if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+-                              if((modeflag & NoSupportSimuTV) && (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+-                                  if(resinfo == 3) return(0);
+-                                  if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) return (0);
+-                              }
++                       }
++                    } else {
++                       tempax &= ~(SupportTV1024);
++                       if(HwDeviceExtension->jChipType >= SIS_315H) {
++                          if((modeflag & NoSupportSimuTV) && (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
++                             if( (!(SiS_Pr->SiS_VBInfo & SetPALTV)) ||
++                                 ((SiS_Pr->SiS_VBInfo & SetPALTV) && (resinfo != SIS_RI_800x600)) ) {
++                                if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) return(0);
++                             }
+                           }
+-                        } else return(0);
+-                  }
+-              }
+-           }
+-      }
+-      
+-  } else {    /* TW: for LVDS  */
++                       } else {
++                          if( (resinfo != SIS_RI_400x300) ||
++                              (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
++                              (SiS_Pr->SiS_VBInfo & SetNotSimuMode) ) {
++                             if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
++                                if((modeflag & NoSupportSimuTV) && (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
++                                   if(resinfo == SIS_RI_400x300) return(0);
++                                   if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) return(0);
++                                }
++                             }
++                            } else return(0);
++                         }
++                    }
++                 } else {  /* slavemode */
++                    if(resinfo != SIS_RI_1024x768) {
++                       if( (!(SiS_Pr->SiS_VBInfo & SetPALTV)) ||
++                           ((SiS_Pr->SiS_VBInfo & SetPALTV) && (resinfo != SIS_RI_512x384) ) ) {
++                          tempax &= ~(SupportTV1024);
++                          if(HwDeviceExtension->jChipType >= SIS_315H) {
++                             if((modeflag & NoSupportSimuTV) && (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
++                                if( (!(SiS_Pr->SiS_VBInfo & SetPALTV)) ||
++                                    ((SiS_Pr->SiS_VBInfo & SetPALTV) && (resinfo != SIS_RI_800x600)) ) {
++                                   if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode))  return(0);
++                                }
++                             }
++                          } else {
++                             if( (resinfo != SIS_RI_400x300) ||
++                                 (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
++                                 (SiS_Pr->SiS_VBInfo & SetNotSimuMode) ) {
++                                if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
++                                   if((modeflag & NoSupportSimuTV) && (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
++                                      if(resinfo == SIS_RI_400x300) return(0);
++                                      if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) return(0);
++                                   }
++                                }
++                               } else return(0);
++                          }
++                       }
++                    }
++                 }
++              } else {   /* 301 */
++                 tempax &= ~(SupportTV1024);
++                 if(HwDeviceExtension->jChipType >= SIS_315H) {
++                    if((modeflag & NoSupportSimuTV) && (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
++                       if( (!(SiS_Pr->SiS_VBInfo & SetPALTV)) ||
++                           ((SiS_Pr->SiS_VBInfo & SetPALTV) && (resinfo != SIS_RI_800x600)) ) {
++                          if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) return(0);
++                       }
++                    }
++                 } else {
++                    if( (resinfo != SIS_RI_400x300) ||
++                        (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
++                        (SiS_Pr->SiS_VBInfo & SetNotSimuMode) ) {
++                       if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
++                          if((modeflag & NoSupportSimuTV) && (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
++                             if(resinfo == SIS_RI_400x300) return(0);
++                             if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) return (0);
++                          }
++                       }
++                      } else return(0);
++                 }
++              }
++        }
++
++  } else {    /* for LVDS  */
+       if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+                       if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+@@ -4284,24 +4456,33 @@ SiS_AdjustCRT2Rate(SiS_Private *SiS_Pr, 
+       if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+                       tempax |= SupportLCD;
+               if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768) {
+-                   if((resinfo != 0x14) && (resinfo > 0x09)) return(0);
++                   if((resinfo != SIS_RI_1280x768) && (resinfo >= SIS_RI_1280x1024)) return(0);
+               } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) {
+-                   if((resinfo != 0x0f) && (resinfo > 0x08)) return(0);
++                   if((resinfo != SIS_RI_1024x600) && (resinfo >= SIS_RI_1024x768))  return(0);
+               } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768) {
+-                   if((resinfo != 0x10) && (resinfo > 0x08)) return(0);
++                   if((resinfo != SIS_RI_1152x768) && (resinfo > SIS_RI_1024x768))   return(0);
+               } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+-                   if((resinfo != 0x15) && (resinfo > 0x09)) return(0);
++                   if((resinfo != SIS_RI_1400x1050) && (resinfo > SIS_RI_1280x1024)) return(0);
++              } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) {
++                     if(resinfo > SIS_RI_1600x1200) return(0);
+               } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
+-                     if(resinfo > 0x09) return(0);
++                     if(resinfo > SIS_RI_1280x1024) return(0);
+                 } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+-                   if(resinfo > 0x08) return(0);
++                   if(resinfo > SIS_RI_1024x768)  return(0);
+               } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600){
+-                   if(resinfo > 0x07) return(0);
+-                   if(resinfo == 0x04) return(0);
++                   if(resinfo > SIS_RI_800x600)   return(0);
++                   if(resinfo == SIS_RI_512x384)  return(0);
++              } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelBarco1366) {
++                     if((resinfo != SIS_RI_1360x1024) && (resinfo > SIS_RI_1280x1024)) return(0);
++              }  else if(SiS_Pr->SiS_LCDResInfo == Panel_848x480) {
++                     if((resinfo != SIS_RI_1360x768) &&
++                      (resinfo != SIS_RI_848x480)  &&
++                      (resinfo > SIS_RI_1024x768)) return(0);
+               }
+       }
+   }
+-  /* TW: Look backwards in table for matching CRT2 mode */
++
++  /* Look backwards in table for matching CRT2 mode */
+   for(; SiS_Pr->SiS_RefIndex[RefreshRateTableIndex+(*i)].ModeID == tempbx; (*i)--) {
+       infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex + (*i)].Ext_InfoFlag;
+       if(infoflag & tempax) {
+@@ -4309,7 +4490,7 @@ SiS_AdjustCRT2Rate(SiS_Private *SiS_Pr, 
+       }
+       if ((*i) == 0) break;
+   }
+-  /* TW: Look through the whole mode-section of the table from the beginning
++  /* 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)++) {
+@@ -4329,7 +4510,7 @@ SiS_SaveCRT2Info(SiS_Private *SiS_Pr, US
+ {
+   USHORT temp1,temp2;
+-  /* TW: We store CRT1 ModeNo in CR34 */
++  /* We store CRT1 ModeNo in CR34 */
+   SiS_SetReg1(SiS_Pr->SiS_P3d4,0x34,ModeNo);
+   temp1 = (SiS_Pr->SiS_VBInfo & SetInSlaveMode) >> 8;
+   temp2 = ~(SetInSlaveMode >> 8);
+@@ -4345,16 +4526,16 @@ SiS_GetVBInfo(SiS_Private *SiS_Pr, USHOR
+   USHORT modeflag, resinfo=0;
+   UCHAR  OutputSelect = *SiS_Pr->pSiS_OutputSelect;
+-  if(SiS_Pr->UseCustomMode) {
+-        modeflag = SiS_Pr->CModeFlag;
++  if(ModeNo <= 0x13) {
++     modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+   } else {
+-    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;
+@@ -4364,22 +4545,24 @@ SiS_GetVBInfo(SiS_Private *SiS_Pr, USHOR
+   if(SiS_BridgeIsOn(SiS_Pr,BaseAddr,HwDeviceExtension) == 0) {  
+       temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30);
+ #if 0 
+-      /* SiS_HiVision is only used on 310/325/330+30xLV */
++      /* SiS_HiVision is only used on 315/330+30xLV */
+       if(SiS_Pr->SiS_VBType & (VB_SIS301LV302LV)) {
+-         if(SiS_Pr->SiS_HiVision & 0x03) {    /* TW: New from 650/30xLV 1.10.6s */
++         if(SiS_Pr->SiS_HiVision & 0x03) {    /* New from 650/30xLV 1.10.6s */
+             temp &= (SetCRT2ToHiVisionTV | SwitchToCRT2 | SetSimuScanMode);   /* 0x83 */
+             temp |= SetCRT2ToHiVisionTV;                                      /* 0x80 */
+          }
+-         if(SiS_Pr->SiS_HiVision & 0x04) {    /* TW: New from 650/30xLV 1.10.6s */
++         if(SiS_Pr->SiS_HiVision & 0x04) {    /* New from 650/30xLV 1.10.6s */
+             temp &= (SetCRT2ToHiVisionTV | SwitchToCRT2 | SetSimuScanMode);   /* 0x83 */
+             temp |= SetCRT2ToSVIDEO;                                          /* 0x08 */
+          }
+       }
+-#endif        
++#endif
++#if 0
+       if(SiS_Pr->SiS_IF_DEF_FSTN) {   /* fstn must set CR30=0x21 */
+                       temp = (SetCRT2ToLCD | SetSimuScanMode);
+                       SiS_SetReg1(SiS_Pr->SiS_P3d4,0x30,temp);
+       }
++#endif
+       tempbx |= temp;
+       tempax = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x31) << 8;
+         tempax &= (LoadDACFlag | DriverMode | SetDispDevSwitch | SetNotSimuMode | SetPALTV);
+@@ -4519,7 +4702,7 @@ SiS_GetVBInfo(SiS_Private *SiS_Pr, USHOR
+                       tempbx |= SetSimuScanMode;
+       }
+-      /* TW: LVDS (LCD/TV) and 301BDH (LCD) can only be slave in 8bpp modes */
++      /* LVDS (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) ||
+              ((tempbx & SetCRT2ToLCD) && (SiS_Pr->SiS_VBType & VB_NoLCD)) ) {
+@@ -4527,12 +4710,12 @@ SiS_GetVBInfo(SiS_Private *SiS_Pr, USHOR
+          }
+       }
+       
+-      if(!(tempbx & SetSimuScanMode)){
++      if(!(tempbx & SetSimuScanMode)) {
+                   if(tempbx & SwitchToCRT2) {
+               if((!(modeflag & CRT2Mode)) && (checkcrt2mode)) {
+                    if( (HwDeviceExtension->jChipType >= SIS_315H) &&
+                        (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) ) {
+-                       if(resinfo != 0x0a)
++                       if(resinfo != SIS_RI_1600x1200)
+                               tempbx |= SetSimuScanMode;
+                    } else {
+                             tempbx |= SetSimuScanMode;
+@@ -4555,7 +4738,7 @@ SiS_GetVBInfo(SiS_Private *SiS_Pr, USHOR
+                   if((!(modeflag & CRT2Mode)) && (checkcrt2mode)) {
+                       if( (HwDeviceExtension->jChipType >= SIS_315H) &&
+                           (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) ) {
+-                           if(resinfo != 0x0a) {  /* TW: 650/301 BIOS */
++                           if(resinfo != SIS_RI_1600x1200) {  /* 650/301 BIOS */
+                                 tempbx |= SetInSlaveMode;
+                                 if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+                                            if(tempbx & SetCRT2ToTV) {
+@@ -4563,7 +4746,7 @@ SiS_GetVBInfo(SiS_Private *SiS_Pr, USHOR
+                                            SiS_Pr->SiS_SetFlag |= TVSimuMode;
+                                            }
+                                   }
+-                           }                      /* TW: 650/301 BIOS */
++                           }                      /* 650/301 BIOS */
+                       } else {
+                           tempbx |= SetInSlaveMode;
+                           if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+@@ -4621,7 +4804,7 @@ SiS_GetVBInfo(SiS_Private *SiS_Pr, USHOR
+       if(HwDeviceExtension->jChipType >= SIS_315H) {
+               if(ROMAddr && SiS_Pr->SiS_UseROM) {
+                   OutputSelect = ROMAddr[0xf3];
+-                  if(HwDeviceExtension->jChipType == SIS_330) {
++                  if(HwDeviceExtension->jChipType >= SIS_330) {
+                       OutputSelect = ROMAddr[0x11b];
+                   }
+                 }
+@@ -4652,7 +4835,7 @@ SiS_GetVBInfo(SiS_Private *SiS_Pr, USHOR
+   SiS_Pr->SiS_VBInfo = tempbx;
+   if(HwDeviceExtension->jChipType == SIS_630) {
+-       SiS_WhatIsThis(SiS_Pr, SiS_Pr->SiS_VBInfo);
++       SiS_SetChrontelGPIO(SiS_Pr, SiS_Pr->SiS_VBInfo);
+   }
+ #ifdef TWDEBUG
+@@ -4666,61 +4849,35 @@ SiS_GetVBInfo(SiS_Private *SiS_Pr, USHOR
+ #endif
+ #endif
+-#if 0  /* TW: Incomplete! (But does not seem to be required) */
+-  if(HwDeviceExtension->jChipType < SIS_315H) {
+-     /* TW: From A901/630+301B BIOS */
+-     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+-         if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13) & 0x80)
+-     }
+-     if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) {
+-         if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13) & 0x80)
+-           if( [si] == 3) ModeIdIndex = 0x3f2b;
+-       }
+-     }
+-     SiS_SetRegAND(SiS_Pr->SiS_P3d4, 0x31, 0xF7);
+-     if(ModeNo == 0x13) bp+4 = 0x03;
+-  } else {
+-     /* From 650/30xLV BIOS: */
+-     SiS_SetRegAND(SiS_Pr->SiS_P3d4, 0x31, 0xF7);
+-     if(ModeNo == 0x13) bp+4 = 0x03;
+-     else bp+4 = ModeNo;
+-  }
+-#endif
+-
+-  /* TW: 630/301B and 650/301 (not 301LV!) BIOSes do more here, but this seems for DOS mode */
+-
+ }
++/* Setup general purpose IO for Chrontel communication */
+ void
+-SiS_WhatIsThis(SiS_Private *SiS_Pr, USHORT myvbinfo)
++SiS_SetChrontelGPIO(SiS_Private *SiS_Pr, USHORT myvbinfo)
+ {
+-   unsigned long eax, temp;
+-   unsigned short temp1;
++   unsigned long  acpibase;
++   unsigned short temp;
+    if(!(SiS_Pr->SiS_ChSW)) return;
+ #ifndef LINUX_XF86
+-   SiS_SetReg4(0xcf8,0x80000874);
+-   eax = SiS_GetReg3(0xcfc);
++   SiS_SetReg4(0xcf8,0x80000874);                /* get ACPI base */
++   acpibase = SiS_GetReg3(0xcfc);
+ #else
+-   eax = pciReadLong(0x00000800, 0x74);
++   acpibase = pciReadLong(0x00000800, 0x74);
+ #endif
+-   eax &= 0xFFFF;
+-   temp = eax;
+-   eax += 0x3c;
+-   temp1 = SiS_GetReg4((USHORT)eax);
+-   temp1 &= 0xFEFF;
+-   SiS_SetReg5((USHORT)eax, temp1);
+-   temp1 = SiS_GetReg4((USHORT)eax);
+-   eax = temp;
+-   eax += 0x3a;
+-   temp1 = SiS_GetReg4((USHORT)eax);
+-   temp1 &= 0xFEFF;
++   acpibase &= 0xFFFF;
++   temp = SiS_GetReg4((USHORT)(acpibase + 0x3c));  /* ACPI register 0x3c: GP Event 1 I/O mode select */
++   temp &= 0xFEFF;
++   SiS_SetReg5((USHORT)(acpibase + 0x3c), temp);
++   temp = SiS_GetReg4((USHORT)(acpibase + 0x3c));
++   temp = SiS_GetReg4((USHORT)(acpibase + 0x3a));  /* ACPI register 0x3a: GP Pin Level (low/high) */
++   temp &= 0xFEFF;
+    if(!(myvbinfo & SetCRT2ToTV)) {
+-      temp1 |= 0x0100;
++      temp |= 0x0100;
+    }
+-   SiS_SetReg5((USHORT)eax, temp1);
+-   temp1 = SiS_GetReg4((USHORT)eax);
++   SiS_SetReg5((USHORT)(acpibase + 0x3a), temp);
++   temp = SiS_GetReg4((USHORT)(acpibase + 0x3a));
+ }
+ void
+@@ -4731,14 +4888,14 @@ SiS_GetRAMDAC2DATA(SiS_Private *SiS_Pr, 
+   USHORT temp1=0,modeflag=0,tempcx=0;
+   USHORT StandTableIndex,CRT1Index;
+ #ifdef SIS315H   
+-  USHORT ResInfo,DisplayType,temp=0;
++  USHORT ResIndex,DisplayType,temp=0;
+   const  SiS_LVDSCRT1DataStruct *LVDSCRT1Ptr = NULL;
+ #endif
+   SiS_Pr->SiS_RVBHCMAX  = 1;
+   SiS_Pr->SiS_RVBHCFACT = 1;
+-  if(ModeNo <= 0x13){
++  if(ModeNo <= 0x13) {
+       modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+       StandTableIndex = SiS_GetModePtr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex);
+@@ -4752,7 +4909,7 @@ SiS_GetRAMDAC2DATA(SiS_Private *SiS_Pr, 
+ #ifdef SIS315H     
+       temp = SiS_GetLVDSCRT1Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
+-                      RefreshRateTableIndex,&ResInfo,&DisplayType);
++                      RefreshRateTableIndex,&ResIndex,&DisplayType);
+       if(temp == 0)  return;
+@@ -4795,16 +4952,16 @@ SiS_GetRAMDAC2DATA(SiS_Private *SiS_Pr, 
+               case 99: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1OPAL;                break;
+               default: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_1;          break;
+       }
+-      tempax = (LVDSCRT1Ptr+ResInfo)->CR[0];
+-      tempax |= (LVDSCRT1Ptr+ResInfo)->CR[14] << 8;
++      tempax = (LVDSCRT1Ptr+ResIndex)->CR[0];
++      tempax |= (LVDSCRT1Ptr+ResIndex)->CR[14] << 8;
+       tempax &= 0x03FF;
+-      tempbx = (LVDSCRT1Ptr+ResInfo)->CR[6];
+-      tempcx = (LVDSCRT1Ptr+ResInfo)->CR[13] << 8;
++      tempbx = (LVDSCRT1Ptr+ResIndex)->CR[6];
++      tempcx = (LVDSCRT1Ptr+ResIndex)->CR[13] << 8;
+       tempcx &= 0x0100;
+       tempcx <<= 2;
+       tempbx |= tempcx;
+-      temp1  = (LVDSCRT1Ptr+ResInfo)->CR[7];
+-#endif        
++      temp1  = (LVDSCRT1Ptr+ResIndex)->CR[7];
++#endif
+     } else {
+@@ -4840,11 +4997,12 @@ SiS_GetRAMDAC2DATA(SiS_Private *SiS_Pr, 
+   if(modeflag & Charx8Dot) tempax *= 8;
+   else                     tempax *= 9;
+-  /* TW: From 650/30xLV 1.10.6s */
++  /* From 650/30xLV 1.10.6s */
+   if(modeflag & HalfDCLK)  tempax <<= 1;
+-  SiS_Pr->SiS_VGAHT = SiS_Pr->SiS_HT = tempax;
+   tempbx++;
++
++  SiS_Pr->SiS_VGAHT = SiS_Pr->SiS_HT = tempax;
+   SiS_Pr->SiS_VGAVT = SiS_Pr->SiS_VT = tempbx;
+ }
+@@ -4852,18 +5010,18 @@ void
+ SiS_UnLockCRT2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr)
+ {
+   if(HwDeviceExtension->jChipType >= SIS_315H)
+-      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);
+ }
+ void
+ SiS_LockCRT2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr)
+ {
+   if(HwDeviceExtension->jChipType >= SIS_315H)
+-      SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2F,0xFE);
++     SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2F,0xFE);
+   else
+-      SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x24,0xFE);
++     SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x24,0xFE);
+ }
+ void
+@@ -4872,7 +5030,6 @@ SiS_EnableCRT2(SiS_Private *SiS_Pr)
+   SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);
+ }
+-/* Checked against all BIOSes */
+ void
+ SiS_DisableBridge(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr)
+ {
+@@ -4882,9 +5039,9 @@ SiS_DisableBridge(SiS_Private *SiS_Pr, P
+   USHORT temp=0;
+   UCHAR *ROMAddr = HwDeviceExtension->pjVirtualRomBase;
+-  if (SiS_Pr->SiS_IF_DEF_LVDS == 0) {
++  if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+-      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {   /* ===== TW: For 30xB/LV ===== */
++      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {   /* ===== For 30xB/LV ===== */
+         if(HwDeviceExtension->jChipType < SIS_315H) {
+@@ -4940,9 +5097,9 @@ SiS_DisableBridge(SiS_Private *SiS_Pr, P
+         } else {
+-#ifdef SIS315H           /* 310/325 series */
++#ifdef SIS315H           /* 315 series */
+-           if(IS_SIS650740) {         /* 650, 740 */
++           if(IS_SIS550650740660) {           /* 550, 650, 740, 660 */
+ #if 0
+             if(SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x00) != 1) return;  /* From 1.10.7w */
+@@ -4950,40 +5107,67 @@ SiS_DisableBridge(SiS_Private *SiS_Pr, P
+             modenum = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x34);
+-              if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
++              if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {                     /* LV */
+             
+                SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x30,0x00);
+                
+                if( (modenum <= 0x13) ||
+                    (!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) ||
+                    (SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) ) {
+-                    SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFE,0x00);
++                    SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFE);
++                    if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
++                       SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
++                    }
+                }
+-               SiS_DDC2Delay(SiS_Pr,0xff00);
+-               SiS_DDC2Delay(SiS_Pr,0x6000);
+-               SiS_DDC2Delay(SiS_Pr,0x8000);
+-               SiS_SetReg3(SiS_Pr->SiS_P3c6,0x00);
++               if(SiS_Pr->SiS_CustomT != CUT_COMPAQ1280) {
++                  SiS_DDC2Delay(SiS_Pr,0xff00);
++                  SiS_DDC2Delay(SiS_Pr,0x6000);
++                  SiS_DDC2Delay(SiS_Pr,0x8000);
+-                 pushax = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x06);
+-               
+-               if(IS_SIS740) {
+-                  SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x06,0xE3);
++                  SiS_SetReg3(SiS_Pr->SiS_P3c6,0x00);
++
++                    pushax = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x06);
++
++                  if(IS_SIS740) {
++                     SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x06,0xE3);
++                  }
++
++                  SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
++
++                  if(!(IS_SIS740)) {
++                     if(!(SiS_IsNotM650or651(SiS_Pr,HwDeviceExtension, BaseAddr))) {
++                        tempah = 0xef;
++                        if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
++                           tempah = 0xf7;
++                          }
++                        SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x4c,tempah);
++                     }
++                  }
+                }
+-               SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+-               
+-               if(!(SiS_IsNotM650or651(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+-                  tempah = 0xef;
+-                  if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+-                     tempah = 0xf7;
+-                    }
+-                  SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x4c,tempah);
+-               }
++              } else if(SiS_Pr->SiS_VBType & VB_NoLCD) {                      /* B-DH */
++               /* This is actually bullshit. The B-DH bridge has cetainly no
++                * Part4 Index 26, since it has no ability to drive LCD panels
++                * at all. But as the BIOS does it, we do it, too...
++                */
++               if(HwDeviceExtension->jChipType == SIS_650) {
++                  if(!(SiS_IsNotM650or651(SiS_Pr,HwDeviceExtension, BaseAddr))) {
++                     SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x4c,0xef);
++                  }
++                  if((!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) ||
++                     (SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) ) {
++                     SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFE,0x00);
++                  }
++                  SiS_SetPanelDelay(SiS_Pr, ROMAddr, HwDeviceExtension, 3);
++               }
++            }
+-              }
++            if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
++               SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1F,0xef);
++            }
+-              if(SiS_Pr->SiS_VBType & VB_SIS301B302B) {
++              if((SiS_Pr->SiS_VBType & VB_SIS301B302B) || (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280)) {
+                tempah = 0x3f;
+                if(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+                   tempah = 0x7f;
+@@ -4997,7 +5181,7 @@ SiS_DisableBridge(SiS_Private *SiS_Pr, P
+               if((SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) ||
+                ((SiS_Pr->SiS_VBType & VB_SIS301LV302LV) && (modenum <= 0x13))) {
+-               if(SiS_Pr->SiS_VBType & VB_SIS301B302B) {
++               if((SiS_Pr->SiS_VBType & VB_SIS301B302B) || (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280)) {
+                   SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1E,0xDF);
+                   SiS_DisplayOff(SiS_Pr);
+                   SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);
+@@ -5020,7 +5204,7 @@ SiS_DisableBridge(SiS_Private *SiS_Pr, P
+             } else {
+-               if(SiS_Pr->SiS_VBType & VB_SIS301B302B) {
++               if((SiS_Pr->SiS_VBType & VB_SIS301B302B) || (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280)) {
+                   if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+                      SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xdf);
+                      SiS_DisplayOff(SiS_Pr);
+@@ -5044,10 +5228,10 @@ SiS_DisableBridge(SiS_Private *SiS_Pr, P
+             }
+-            if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
++            if((SiS_Pr->SiS_VBType & VB_SIS301LV302LV) && (SiS_Pr->SiS_CustomT != CUT_COMPAQ1280)) {
++
++               SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1f,~0x10);               /* 1.10.8r, 8m */
+-               SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1f,~0x10);    /* 1.10.8r */
+-               
+                tempah = 0x3f;
+                if(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+                   tempah = 0x7f;
+@@ -5057,9 +5241,9 @@ SiS_DisableBridge(SiS_Private *SiS_Pr, P
+                }
+                SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1F,tempah);
+-               if(SiS_IsNotM650or651(SiS_Pr,HwDeviceExtension, BaseAddr)) {   /* 1.10.8r */
++               if(SiS_IsNotM650or651(SiS_Pr,HwDeviceExtension, BaseAddr)) {   /* 1.10.8r, 8m */
+                   SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0x7f);
+-               }                                                              /* 1.10.8r */
++               }                                                              /* 1.10.8r, 8m */
+                if(!(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+                   SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xdf);
+@@ -5075,80 +5259,47 @@ SiS_DisableBridge(SiS_Private *SiS_Pr, P
+                SiS_SetReg1(SiS_Pr->SiS_P3c4,0x06,pushax);
+-            }
++            } else if(SiS_Pr->SiS_VBType & VB_NoLCD) {
+-#if 0
+-          } else if(IS_SIS740) {      /* 740 */
+-        
+-           if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {   /* 30xLV */
+-           
+-              if( (!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) ||
+-                  (SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) ) {
+-                    SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFE,0x00);
+-              }
+-              
+-              SiS_SetReg3(SiS_Pr->SiS_P3c6,0x00);
++               if(HwDeviceExtension->jChipType == SIS_650) {
++                  if((SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) ||
++                     (!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr)))) {
++                     if((!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) ||
++                        (!(SiS_CRT2IsLCD(SiS_Pr,BaseAddr,HwDeviceExtension)))) {
++                        SiS_SetPanelDelay(SiS_Pr, ROMAddr, HwDeviceExtension, 2);
++                        SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFD);
++                        SiS_SetPanelDelay(SiS_Pr, ROMAddr, HwDeviceExtension, 4);
++                     }
++                  }
++               }
+-                pushax = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x06);
+-              
+-              SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x06,0xE3);
++            } else if((SiS_Pr->SiS_VBType & VB_SIS301B302B) || (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280)) {
+-              SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+-              
+-              if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+-                 SiS_DisplayOff(SiS_Pr);
+-                 SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 2);
+-                 SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);
+-                 SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1E,0xDF);
+-              } else {
+-                 SiS_DisplayOff(SiS_Pr);
+-                 SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x80);
+-                 SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 2);
+-                 SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);
+-                 temp = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00);
+-                   SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x10);
+-                 SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF);
+-                 SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x00,temp);
+-              }
+-              
+-              SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1F,0x3F);
+-              SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1F,0xEF);  /* (from 650) */
+-              
+-              SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0x7f);
+-              
+-              if(!(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+-                 SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xdf);
+-              }
+-              
+-              if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+-                 if(!(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+-                    if(!(SiS_CRT2IsLCD(SiS_Pr,BaseAddr,HwDeviceExtension))) {
+-                       if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+-                          SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFD,0x00);
+-                         }
+-                      }
+-                 }
+-              }
+-              SiS_SetReg1(SiS_Pr->SiS_P3c4,0x06,pushax);
+-           
+-           } else {   /* (301,) 301B */
+-        
+-              if(SiS_Is301B(SiS_Pr,BaseAddr)) {
+-                 SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1F,0x3F);
+-              }
+-           
+-              SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xDF);
+-              SiS_DisplayOff(SiS_Pr);
+-              SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x80);
+-              SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);
++               if(HwDeviceExtension->jChipType == SIS_650) {
++                  if(!(SiS_IsNotM650or651(SiS_Pr,HwDeviceExtension, BaseAddr))) {
++                     tempah = 0xef;
++                     if(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr)) {
++                        if(modenum > 0x13) {
++                           tempah = 0xf7;
++                        }
++                       }
++                     SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x4c,tempah);
++                  }
++                  if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
++                     if((SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) ||
++                        (!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr)))) {
++                        if((!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) ||
++                           (!(SiS_CRT2IsLCD(SiS_Pr,BaseAddr,HwDeviceExtension)))) {
++                           SiS_SetPanelDelay(SiS_Pr, ROMAddr, HwDeviceExtension, 2);
++                           SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFD);
++                           SiS_SetPanelDelay(SiS_Pr, ROMAddr, HwDeviceExtension, 4);
++                        }
++                     }
++                  }
++               }
++
++            }
+-              temp = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00);
+-                SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x10);
+-              SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF);
+-              SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x00,temp);
+-              
+-           }
+-#endif          
+         } else {                      /* 315, 330 - all bridge types */
+            if(SiS_Is301B(SiS_Pr,BaseAddr)) {
+@@ -5193,13 +5344,13 @@ SiS_DisableBridge(SiS_Private *SiS_Pr, P
+       }
+-      } else {     /* ============ TW: For 301 ================ */
++      } else {     /* ============ For 301 ================ */
+         if(HwDeviceExtension->jChipType < SIS_315H) {
+-            if(SiS_CRT2IsLCD(SiS_Pr,BaseAddr,HwDeviceExtension)) {
+-                SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,0xF0,0x0B);
+-              SiS_SetPanelDelay(SiS_Pr, ROMAddr, HwDeviceExtension, 1);
+-          }
++            if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwDeviceExtension))) {
++            SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,0xF7,0x08);
++            SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
++         }
+       }
+         SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xDF);           /* disable VB */
+@@ -5218,18 +5369,23 @@ SiS_DisableBridge(SiS_Private *SiS_Pr, P
+           SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x00,temp);
+       } else {
+             SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF);            /* disable CRT2 */
++          if( (!(SiS_CRT2IsLCD(SiS_Pr,BaseAddr,HwDeviceExtension))) ||
++              (!(SiS_CR36BIOSWord23d(SiS_Pr,HwDeviceExtension))) ) {
++              SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 2);
++              SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,0xFB,0x04);
++          }
+       }
+       }
+-  } else {     /* ============ TW: For LVDS =============*/
++  } else {     /* ============ For LVDS =============*/
+     if(HwDeviceExtension->jChipType < SIS_315H) {
+ #ifdef SIS300 /* 300 series */
+       if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) {
+-          SiS_SetCH700x(SiS_Pr,0x090E);
++         SiS_SetCH700x(SiS_Pr,0x090E);
+       }
+       if(HwDeviceExtension->jChipType == SIS_730) {
+@@ -5245,17 +5401,17 @@ SiS_DisableBridge(SiS_Private *SiS_Pr, P
+             if(!(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13) & 0x40)) {
+   
+-                if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwDeviceExtension))) {
++               if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwDeviceExtension))) {
+-                     SiS_WaitVBRetrace(SiS_Pr,HwDeviceExtension);
++                    SiS_WaitVBRetrace(SiS_Pr,HwDeviceExtension);
+-                   if(!(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x06) & 0x1c)) {
+-                       SiS_DisplayOff(SiS_Pr);
+-                   }
++                  if(!(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x06) & 0x1c)) {
++                      SiS_DisplayOff(SiS_Pr);
++                  }
+-                   SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,0xF7,0x08);
+-                   SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+-                  }
++                  SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,0xF7,0x08);
++                  SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
++                 }
+               }
+          }
+       }
+@@ -5279,29 +5435,40 @@ SiS_DisableBridge(SiS_Private *SiS_Pr, P
+     } else {
+-#ifdef SIS315H        /* 310/325 series */
++#ifdef SIS315H        /* 315 series */
+       if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+-              temp = SiS_GetCH701x(SiS_Pr,0x61);
+-              if(temp < 1) {
+-                 SiS_SetCH701x(SiS_Pr,0xac76);
+-                 SiS_SetCH701x(SiS_Pr,0x0066);
+-              }
+-              
+-              if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
++
++              if(HwDeviceExtension->jChipType == SIS_740) {
++                 temp = SiS_GetCH701x(SiS_Pr,0x61);
++                 if(temp < 1) {
++                    SiS_SetCH701x(SiS_Pr,0xac76);
++                    SiS_SetCH701x(SiS_Pr,0x0066);
++                 }
++
++                 if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+                       SiS_SetCH701x(SiS_Pr,0x3e49);
+-              } else if(SiS_IsTVOrYPbPrOrScart(SiS_Pr,HwDeviceExtension, BaseAddr))  {
++                 } else if(SiS_IsTVOrYPbPrOrScart(SiS_Pr,HwDeviceExtension, BaseAddr))  {
+                       SiS_SetCH701x(SiS_Pr,0x3e49);
++                 }
+               }
+-              
++
+               if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+                       SiS_Chrontel701xBLOff(SiS_Pr);
+-                      SiS_Chrontel701xOff(SiS_Pr);
++                      SiS_Chrontel701xOff(SiS_Pr,HwDeviceExtension);
+               } else if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+                       SiS_Chrontel701xBLOff(SiS_Pr);
+-                      SiS_Chrontel701xOff(SiS_Pr);
++                      SiS_Chrontel701xOff(SiS_Pr,HwDeviceExtension);
+               }
+-              
++
++              if(HwDeviceExtension->jChipType != SIS_740) {
++                 if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
++                      SiS_SetCH701x(SiS_Pr,0x0149);
++                 } else if(SiS_IsTVOrYPbPrOrScart(SiS_Pr,HwDeviceExtension, BaseAddr))  {
++                      SiS_SetCH701x(SiS_Pr,0x0149);
++                 }
++              }
++
+       }
+       if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) {
+@@ -5325,6 +5492,10 @@ SiS_DisableBridge(SiS_Private *SiS_Pr, P
+               SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x80);
+       }
++      if(HwDeviceExtension->jChipType == 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) {
+@@ -5337,15 +5508,27 @@ SiS_DisableBridge(SiS_Private *SiS_Pr, P
+       if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) {
+               if(SiS_CRT2IsLCD(SiS_Pr, BaseAddr,HwDeviceExtension)) {
+-                      SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1e,0xdf);
++                 SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1e,0xdf);
++                 if(HwDeviceExtension->jChipType == SIS_550) {
++                    SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1e,0xbf);
++                    SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1e,0xef);
++                 }
++              }
++      } else {
++         if(HwDeviceExtension->jChipType == SIS_740) {
++              if(SiS_IsLCDOrLCDA(SiS_Pr,HwDeviceExtension, BaseAddr)) {
++                 SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1e,0xdf);
+               }
+-      } else if(SiS_IsLCDOrLCDA(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+-              SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1e,0xdf);
++         } else {
++              if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
++                 SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1e,0xdf);
++              }
++         }
+       }
+       if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+               if(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+-                      SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xff);
++                      /* SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xff); */
+               } else {
+                       SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xfb);
+               }
+@@ -5353,7 +5536,10 @@ SiS_DisableBridge(SiS_Private *SiS_Pr, P
+       SiS_UnLockCRT2(SiS_Pr,HwDeviceExtension, BaseAddr);
+-      if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) {
++      if(HwDeviceExtension->jChipType == SIS_550) {
++              SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x01,0x80);
++              SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x02,0x40);
++      } else if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) {
+               SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0xf7);
+       } else if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+               SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0xf7);
+@@ -5361,7 +5547,7 @@ SiS_DisableBridge(SiS_Private *SiS_Pr, P
+               SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0xf7);
+       }
+-#if 0  /* TW: BIOS code makes no sense */
++#if 0  /* BIOS code makes no sense */
+        if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+            if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+               if(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+@@ -5387,7 +5573,6 @@ SiS_DisableBridge(SiS_Private *SiS_Pr, P
+ }
+-/* TW: Checked against all BIOSes */
+ void
+ SiS_EnableBridge(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr)
+ {
+@@ -5400,7 +5585,7 @@ SiS_EnableBridge(SiS_Private *SiS_Pr, PS
+   if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+-    if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {   /* TW: ====== For 301B et al  ====== */
++    if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {   /* ====== For 301B et al  ====== */
+       if(HwDeviceExtension->jChipType < SIS_315H) {
+@@ -5497,48 +5682,95 @@ SiS_EnableBridge(SiS_Private *SiS_Pr, PS
+       } else {
+-#ifdef SIS315H    /* 310/325 series */
++#ifdef SIS315H    /* 315 series */
+-       if(IS_SIS650740) {             /* 650 */
++       if(IS_SIS550650740660) {               /* 550, 650, 740, 660 */
+ #if 0
+           if(SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x00) != 1) return;    /* From 1.10.7w */
+ #endif
+           if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+-          
+-             SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1f,0xef);  /* 1.10.7u */
+-             SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x30,0x00);    /* 1.10.7u */
++
++             if(SiS_Pr->SiS_CustomT != CUT_COMPAQ1280) {
++                SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1f,0xef);  /* 1.10.7u */
++                SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x30,0x00);    /* 1.10.7u */
++             }
+              if(!(IS_SIS740)) {
+                   if(!(SiS_IsNotM650or651(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+                    tempah = 0x10;
+-                   if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+-                      tempah = 0x08;
+-                     }
+-                   SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x4c,tempah);
++                   if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
++                      if(SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x13) & 0x04) {
++                         if((SiS_GetReg1(SiS_Pr->SiS_Part2Port,0x00) & 0x0f) == 0x0c) {
++                            tempah = 0x08;
++                         } else {
++                            tempah = 0x18;
++                         }
++                      }
++                      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x4c,tempah);
++                   } else {
++                      if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
++                         tempah = 0x08;
++                        }
++                      SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x4c,tempah);
++                   }
+                 }
+              }
+-             SiS_SetReg3(SiS_Pr->SiS_P3c6,0x00);
+-             SiS_DisplayOff(SiS_Pr);
+-             pushax = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x06);
+-             if(IS_SIS740) {
+-                SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x06,0xE3);
++             if(SiS_Pr->SiS_CustomT != CUT_COMPAQ1280) {
++                SiS_SetReg3(SiS_Pr->SiS_P3c6,0x00);
++                SiS_DisplayOff(SiS_Pr);
++                pushax = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x06);
++                if(IS_SIS740) {
++                   SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x06,0xE3);
++                }
+              }
+              if( (SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) ||
+                  (SiS_CRT2IsLCD(SiS_Pr,BaseAddr,HwDeviceExtension)) ) {
+-                   if(!(SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x26) & 0x02)) {
+-                    SiS_SetPanelDelayLoop(SiS_Pr,ROMAddr, HwDeviceExtension, 3, 2);
+-                    SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x02);
+-                    SiS_SetPanelDelayLoop(SiS_Pr,ROMAddr, HwDeviceExtension, 3, 2);
+-                 }
++                  if(!(SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x26) & 0x02)) {
++                   if(SiS_Pr->SiS_CustomT != CUT_COMPAQ1280) {
++                      SiS_SetPanelDelayLoop(SiS_Pr,ROMAddr, HwDeviceExtension, 3, 2);
++                   }
++                   SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x02);
++                   SiS_SetPanelDelayLoop(SiS_Pr,ROMAddr, HwDeviceExtension, 3, 2);
++                }
++             }
++
++               if(SiS_Pr->SiS_CustomT != CUT_COMPAQ1280) {
++                if(!(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x31) & 0x40)) {
++                     SiS_SetPanelDelayLoop(SiS_Pr,ROMAddr, HwDeviceExtension, 3, 10);
++                   delaylong = TRUE;
++                }
++             }
++
++          } else if(SiS_Pr->SiS_VBType & VB_NoLCD) {
++
++             if(HwDeviceExtension->jChipType == SIS_650) {
++                if(!(SiS_IsNotM650or651(SiS_Pr,HwDeviceExtension, BaseAddr))) {
++                   SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x4c,0x10);
++                }
++                if( (SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) ||
++                    (SiS_CRT2IsLCD(SiS_Pr,BaseAddr,HwDeviceExtension)) ) {
++                   SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x02);
++                   SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 0);
++                }
+              }
+-             if(!(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x31) & 0x40)) {
+-                  SiS_SetPanelDelayLoop(SiS_Pr,ROMAddr, HwDeviceExtension, 3, 10);
+-                delaylong = TRUE;
++          } else if(SiS_Pr->SiS_VBType & VB_SIS301B302B) {
++
++             if(HwDeviceExtension->jChipType == SIS_650) {
++                if(!(SiS_IsNotM650or651(SiS_Pr,HwDeviceExtension, BaseAddr))) {
++                   tempah = 0x10;
++                   if(SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x13) & 0x04) {
++                      tempah = 0x18;
++                      if((SiS_GetReg1(SiS_Pr->SiS_Part2Port,0x00) & 0x0f) == 0x0c) {
++                         tempah = 0x08;
++                      }
++                   }
++                   SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x4c,tempah);
++                }
+              }
+           }
+@@ -5547,13 +5779,17 @@ SiS_EnableBridge(SiS_Private *SiS_Pr, PS
+                temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x32) & 0xDF;
+              if(SiS_BridgeInSlave(SiS_Pr)) {
+                   tempah = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30);
+-                  if(!(tempah & SetCRT2ToRAMDAC))  temp |= 0x20;
++                  if(!(tempah & SetCRT2ToRAMDAC)) {
++                   if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
++                      if(!(SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x13) & 0x04)) temp |= 0x20;
++                   } else temp |= 0x20;
++                }
+                }
+                SiS_SetReg1(SiS_Pr->SiS_P3c4,0x32,temp);
+              SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);                   /* enable CRT2 */
+              
+-             if(SiS_Pr->SiS_VBType & VB_SIS301B302B) {
++             if((SiS_Pr->SiS_VBType & VB_SIS301B302B) || (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280)) {
+                 SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0x7f);
+                 temp = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x2e);
+                 if(!(temp & 0x80)) {
+@@ -5565,12 +5801,12 @@ SiS_EnableBridge(SiS_Private *SiS_Pr, PS
+           }
+           if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+-                SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1e,0x20);
++             SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1e,0x20);
+           }
+           SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x00,0x1f,0x20);
+-          if(SiS_Pr->SiS_VBType & VB_SIS301B302B) {
++          if((SiS_Pr->SiS_VBType & VB_SIS301B302B) || (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280)) {
+              temp = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x2e);
+              if(!(temp & 0x80)) {
+                 SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2e,0x80);
+@@ -5586,7 +5822,9 @@ SiS_EnableBridge(SiS_Private *SiS_Pr, PS
+           }
+             SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1F,tempah);
+-          if(SiS_Pr->SiS_VBType & VB_SIS301B302B) {
++          if((SiS_Pr->SiS_VBType & VB_SIS301B302B) ||
++             ((SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) &&
++              (!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))))) {
+                SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f);
+           }
+@@ -5595,186 +5833,144 @@ SiS_EnableBridge(SiS_Private *SiS_Pr, PS
+              SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x30,0x00);    /* All this from 1.10.7u */
+              SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x27,0x0c);
+              SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x20);
+-             SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x31,0x05);  
+-             SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x32,0x60);  
+-             SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x33,0x00);  
+-             SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x34,0x10); 
+-             SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x40); 
+-             
+-             SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 2);
+-          
++
++             if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
++
++                SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x31,0x08);
++                SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x32,0x10);
++                SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x33,0x4d);
++                if((SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36) & 0x0f) != 0x02) {
++                   SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x31,0x0d);
++                   SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x32,0x70);
++                   SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x33,0x6b);
++                }
++                SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x34,0x10);
++
++             } else {
++
++                SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x31,0x12);
++                SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x32,0xd0);
++                SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x33,0x6b);
++                if((SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36) & 0x0f) == 0x02) {   /* @@@@ really == ? */
++                   SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x31,0x0d);
++                   SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x32,0x70);
++                   SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x33,0x40);
++                   if(((SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36) & 0xf0) != 0x03)) {
++                      SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x31,0x05);
++                      SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x32,0x60);
++                      SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x33,0x33);  /* 00 */
++                   }
++                }
++                SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x34,0x10);
++                if((SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36) & 0x0f) != 0x03) {
++                   SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x40);
++                }
++             }
++
++             if(SiS_Pr->SiS_CustomT != CUT_COMPAQ1280) {
++                SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 2);
++             }
++
+              SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1f,0x10);  /* 1.10.8r */
+-             SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2e,0x80);
++             if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
+-             if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+                 if( (SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) ||
+                     ((SiS_CRT2IsLCD(SiS_Pr,BaseAddr,HwDeviceExtension))) ) {
+-                  SiS_SetPanelDelayLoop(SiS_Pr,ROMAddr, HwDeviceExtension, 3, 10);
+-                  if(delaylong) {
+-                      SiS_SetPanelDelayLoop(SiS_Pr,ROMAddr, HwDeviceExtension, 3, 10);
+-                  }
+-                    SiS_WaitVBRetrace(SiS_Pr,HwDeviceExtension);
+-                  SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xfe,0x01);
+-               }
+-            }
++                   SiS_DisplayOn(SiS_Pr);
++                   SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 1);
++                   SiS_WaitVBRetrace(SiS_Pr,HwDeviceExtension);
++                   SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
++                   SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x40);
++                   if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) {
++                      SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xfe,0x01);
++                   }
++                }
+-            SiS_SetReg1(SiS_Pr->SiS_P3c4,0x06,pushax);
+-            SiS_DisplayOn(SiS_Pr);
+-            SiS_SetReg3(SiS_Pr->SiS_P3c6,0xff);
++             } else {
+-            if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+-                SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f);
+-            }
+-#if 0
+-              SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x30,0x00);
+-            SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x27,0x0c);
+-            SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x20);
+-            SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x31,0x05);   /* 1.10.8r: 0x0d */
+-            SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x32,0x60);   /* 1.10.8r: 0x70 */
+-            SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x33,0x00);   /* 1.10.8r: 0x40 */
+-            SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x34,0x10); 
+-            SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x40); 
+-#endif              
++                SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2e,0x80);
+-        }
++                if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) {
++                   if( (SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) ||
++                       ((SiS_CRT2IsLCD(SiS_Pr,BaseAddr,HwDeviceExtension))) ) {
++                      SiS_SetPanelDelayLoop(SiS_Pr,ROMAddr, HwDeviceExtension, 3, 10);
++                      if(delaylong) {
++                         SiS_SetPanelDelayLoop(SiS_Pr,ROMAddr, HwDeviceExtension, 3, 10);
++                      }
++                        SiS_WaitVBRetrace(SiS_Pr,HwDeviceExtension);
++                      SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xfe,0x01);
++                   }
++                }
+-#if 0
+-         } else if(IS_SIS740) {               /* 740 */
+-       
+-         if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {  /* 30xLV */
+-         
+-            SiS_SetReg3(SiS_Pr->SiS_P3c6,0x00);
+-            SiS_DisplayOff(SiS_Pr);
+-            pushax = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x06);
+-            SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x06,0xE3);
+-            
+-            if( (SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) ||
+-                (SiS_CRT2IsLCD(SiS_Pr,BaseAddr,HwDeviceExtension)) ) {
+-                   if(!(SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x26) & 0x02)) {
+-                    SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x02);
+-                    SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+-                 }
+-            }
+-            
+-            if(!(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+-               temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x32) & 0xDF;
+-               if(SiS_BridgeInSlave(SiS_Pr)) {
+-                    tempah = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30);
+-                    if(!(tempah & SetCRT2ToRAMDAC))  temp |= 0x20;
+-                 }
+-                 SiS_SetReg1(SiS_Pr->SiS_P3c4,0x32,temp);
++                SiS_SetReg1(SiS_Pr->SiS_P3c4,0x06,pushax);
++                SiS_DisplayOn(SiS_Pr);
++                SiS_SetReg3(SiS_Pr->SiS_P3c6,0xff);
+-               SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);      
+-               SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 2);
+-            }
+-            
+-            if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+-               SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x20);
+-            }
+-            
+-            SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x00,0x1f,0x20);
+-            SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1F,0xC0);
+-            SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1F,0x10);  /* (taken from 650 1.10.8r) */
+-            SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2E,0x80);
+-            
+-            if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+-               if( (SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) ||
+-                   (SiS_CRT2IsLCD(SiS_Pr,BaseAddr,HwDeviceExtension)) ) {
+-                  SiS_SetPanelDelayLoop(SiS_Pr,ROMAddr, HwDeviceExtension, 3, 10);
+-                  if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x31) & 0x40) {
+-                     SiS_WaitVBRetrace(SiS_Pr,HwDeviceExtension);
+-                  }
+-                  SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xfe,0x01);
+-                  SiS_SetPanelDelayLoop(SiS_Pr,ROMAddr, HwDeviceExtension, 3, 10);
+-                  SiS_WaitVBRetrace(SiS_Pr,HwDeviceExtension);
+-               }
+-              }
+-            
+-            SiS_SetReg1(SiS_Pr->SiS_P3c4,0x06,pushax);
+-            SiS_DisplayOn(SiS_Pr);
+-            SiS_SetReg3(SiS_Pr->SiS_P3c6,0xff);
+-            
+-            if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+-               SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f);
+-            }
+-         
+-         } else {     /* (301), 301B */
+-       
+-            if(!(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+-               temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x32) & 0xDF;
+-               if(SiS_BridgeInSlave(SiS_Pr)) {
+-                    tempah = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30);
+-                    if(!(tempah & SetCRT2ToRAMDAC))  temp |= 0x20;
+-                 }
+-                 SiS_SetReg1(SiS_Pr->SiS_P3c4,0x32,temp);
++                if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) {
++                   SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f);
++                }
+-               SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);                   /* enable CRT2 */
++             }
+-               temp = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x2E);
+-                 if(!(temp & 0x80))
+-                    SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2E,0x80);
+-              }
++          } if(SiS_Pr->SiS_VBType & VB_NoLCD) {
++
++             if(HwDeviceExtension->jChipType == SIS_650) {
++                if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) {
++                   if( (SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) ||
++                       (SiS_CRT2IsLCD(SiS_Pr,BaseAddr,HwDeviceExtension)) ) {
++                      SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 1);
++                      SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x01);
++                   }
++                }
++             }
+-            SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x00,0x1f,0x20);
++          }
+-            if(SiS_Is301B(SiS_Pr,BaseAddr)) { 
+-               SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1F,0xC0);
+-               SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f);
+-            } else {
+-               SiS_VBLongWait(SiS_Pr);
+-                 SiS_DisplayOn(SiS_Pr);
+-               SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7F);
+-                 SiS_VBLongWait(SiS_Pr);
+-            }
+-            
+-         }
+-#endif
+-        
+        } else {                       /* 315, 330 */
+-         if(!(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+-            temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x32) & 0xDF;
+-            if(SiS_BridgeInSlave(SiS_Pr)) {
+-                 tempah = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30);
+-                 if(!(tempah & SetCRT2ToRAMDAC))  temp |= 0x20;
+-              }
+-              SiS_SetReg1(SiS_Pr->SiS_P3c4,0x32,temp);
++          if(!(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr))) {
++             temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x32) & 0xDF;
++             if(SiS_BridgeInSlave(SiS_Pr)) {
++                  tempah = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30);
++                  if(!(tempah & SetCRT2ToRAMDAC))  temp |= 0x20;
++               }
++               SiS_SetReg1(SiS_Pr->SiS_P3c4,0x32,temp);
+-            SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);                   /* enable CRT2 */
++             SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);                   /* enable CRT2 */
+-            temp = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x2E);
+-              if(!(temp & 0x80))
+-                 SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2E,0x80);
+-           }
++             temp = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x2E);
++               if(!(temp & 0x80))
++                  SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2E,0x80);
++            }
+-         SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x00,0x1f,0x20);
++          SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x00,0x1f,0x20);
+-         if(SiS_Is301B(SiS_Pr,BaseAddr)) {
++          if(SiS_Is301B(SiS_Pr,BaseAddr)) {
+-            temp=SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x2E);
+-              if (!(temp & 0x80))
+-                 SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2E,0x80);
++             temp=SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x2E);
++               if(!(temp & 0x80))
++                  SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2E,0x80);
++
++             tempah = 0xc0;
++             if(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr)) {
++                tempah = 0x80;
++                if(!(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr))) {
++                   tempah = 0x40;
++                  }
++             }
++               SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1F,tempah);
+-            tempah = 0xc0;
+-            if(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+-               tempah = 0x80;
+-               if(!(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+-                  tempah = 0x40;
+-                 }
+-            }
+-              SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1F,tempah);
++             SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f);
+-            SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f);
++          } else {
+-         } else {
+-         
+-            SiS_VBLongWait(SiS_Pr);
+-              SiS_DisplayOn(SiS_Pr);
+-            SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7F);
+-              SiS_VBLongWait(SiS_Pr);
++             SiS_VBLongWait(SiS_Pr);
++               SiS_DisplayOn(SiS_Pr);
++             SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7F);
++               SiS_VBLongWait(SiS_Pr);
+-         }
++          }
+        }   /* 315, 330 */
+@@ -5782,11 +5978,11 @@ SiS_EnableBridge(SiS_Private *SiS_Pr, PS
+       }
+-    } else {  /* ============  TW: For 301 ================ */
++    } else {  /* ============  For 301 ================ */
+        if(HwDeviceExtension->jChipType < SIS_315H) {
+             if(SiS_CRT2IsLCD(SiS_Pr,BaseAddr,HwDeviceExtension)) {
+-                SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,0xF0,0x0B);
++                SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x11,0xFB);
+               SiS_SetPanelDelay(SiS_Pr, ROMAddr, HwDeviceExtension, 0);
+           }
+        }
+@@ -5818,13 +6014,13 @@ SiS_EnableBridge(SiS_Private *SiS_Pr, PS
+        if(HwDeviceExtension->jChipType < SIS_315H) {
+             if(SiS_CRT2IsLCD(SiS_Pr,BaseAddr,HwDeviceExtension)) {
+               SiS_SetPanelDelay(SiS_Pr, ROMAddr, HwDeviceExtension, 1);
+-                SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,0xF0,0x03);
++                SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x11,0xF7);
+           }
+        }
+     }
+-  } else {   /* =================== TW: For LVDS ================== */
++  } else {   /* =================== For LVDS ================== */
+     if(HwDeviceExtension->jChipType < SIS_315H) {
+@@ -5847,35 +6043,35 @@ SiS_EnableBridge(SiS_Private *SiS_Pr, PS
+       SiS_UnLockCRT2(SiS_Pr,HwDeviceExtension, BaseAddr);
+       SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x02,0xBF);
+       if(SiS_BridgeInSlave(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,BaseAddr,HwDeviceExtension))) {
+-              SiS_SetCH700x(SiS_Pr,0x0B0E);
+-        }
++         if(!(SiS_CRT2IsLCD(SiS_Pr,BaseAddr,HwDeviceExtension))) {
++          SiS_SetCH700x(SiS_Pr,0x0B0E);
++         }
+       }
+       if(SiS_CRT2IsLCD(SiS_Pr,BaseAddr,HwDeviceExtension)) {
+-          if(!(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13) & 0x40)) {
+-              if(!(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x16) & 0x10)) {
+-                if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwDeviceExtension))) {
+-                      SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 1);
+-                      SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 1);
+-                }
+-                SiS_WaitVBRetrace(SiS_Pr,HwDeviceExtension);
+-                  SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x11,0xF7);
+-              }
+-        }
++         if(!(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13) & 0x40)) {
++            if(!(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x16) & 0x10)) {
++             if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwDeviceExtension))) {
++                SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 1);
++                SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 1);
++             }
++             SiS_WaitVBRetrace(SiS_Pr,HwDeviceExtension);
++               SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x11,0xF7);
++            }
++       }
+       }
+ #endif  /* SIS300 */
+     } else {
+-#ifdef SIS315H    /* 310/325 series */
++#ifdef SIS315H    /* 315 series */
+ #if 0  /* BIOS code makes no sense */
+        if(SiS_IsVAMode()) {
+@@ -5902,36 +6098,41 @@ SiS_EnableBridge(SiS_Private *SiS_Pr, PS
+         SiS_Chrontel701xBLOff(SiS_Pr);
+        }
+-       SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0x7f);
+-       
+-#ifdef NEWCH701x
+-       if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+-           if(SiS_IsLCDOrLCDA(SiS_Pr,HwDeviceExtension,BaseAddr)) {
++       if(HwDeviceExtension->jChipType != SIS_550) {
++          SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0x7f);
++       }
++
++       if(HwDeviceExtension->jChipType == SIS_740) {
++          if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
++             if(SiS_IsLCDOrLCDA(SiS_Pr,HwDeviceExtension,BaseAddr)) {
+               SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x20);
+-         }
++           }
++        }
+        }
+-#endif       
+        temp1 = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x2E);
+-       if (!(temp1 & 0x80))
++       if(!(temp1 & 0x80))
+            SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2E,0x80);
+        if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+            if(temp) {
+-             SiS_Chrontel701xBLOn(SiS_Pr);
++             SiS_Chrontel701xBLOn(SiS_Pr, HwDeviceExtension);
+          }
+        }
+        if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) {
+            if(SiS_CRT2IsLCD(SiS_Pr,BaseAddr,HwDeviceExtension)) {
+               SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x20);
++              if(HwDeviceExtension->jChipType == SIS_550) {
++                 SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x40);
++                 SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x10);
++              }
++         }
++       } else if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
++           if(HwDeviceExtension->jChipType != SIS_740) {
++              SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x20);
+          }
+-       } 
+-#ifndef NEWCH701x       
+-         else if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+-           SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x20);
+        }
+-#endif       
+        if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+            SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f);
+@@ -5954,10 +6155,10 @@ SiS_EnableBridge(SiS_Private *SiS_Pr, PS
+        if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+                       if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+                       if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+-                              SiS_Chrontel701xBLOn(SiS_Pr);
++                              SiS_Chrontel701xBLOn(SiS_Pr, HwDeviceExtension);
+                               SiS_ChrontelDoSomething4(SiS_Pr,HwDeviceExtension, BaseAddr);
+                       } else if(SiS_IsLCDOrLCDA(SiS_Pr,HwDeviceExtension, BaseAddr))  {
+-                                      SiS_Chrontel701xBLOn(SiS_Pr);
++                                      SiS_Chrontel701xBLOn(SiS_Pr, HwDeviceExtension);
+                                       SiS_ChrontelDoSomething4(SiS_Pr,HwDeviceExtension, BaseAddr);
+                       }
+                       }
+@@ -5983,7 +6184,7 @@ SiS_SiS30xBLOn(SiS_Private *SiS_Pr, PSIS
+ {
+   USHORT  BaseAddr = (USHORT)HwDeviceExtension->ulIOAddress;
+-  /* TW: Switch on LCD backlight on SiS30xLV */
++  /* Switch on LCD backlight on SiS30xLV */
+   if( (SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) ||
+       (SiS_CRT2IsLCD(SiS_Pr,BaseAddr,HwDeviceExtension)) ) {
+     if(!(SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x26) & 0x02)) {
+@@ -6001,7 +6202,7 @@ SiS_SiS30xBLOff(SiS_Private *SiS_Pr, PSI
+ {
+   USHORT  BaseAddr = (USHORT)HwDeviceExtension->ulIOAddress;
+-  /* TW: Switch off LCD backlight on SiS30xLV */
++  /* Switch off LCD backlight on SiS30xLV */
+   if( (!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) ||
+       (SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) ) {
+        SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFE,0x00);
+@@ -6023,12 +6224,14 @@ SiS_CR36BIOSWord23b(SiS_Private *SiS_Pr,
+   UCHAR *ROMAddr;
+   if((ROMAddr = (UCHAR *)HwDeviceExtension->pjVirtualRomBase) && SiS_Pr->SiS_UseROM) {
+-     temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36) & 0xff;
+-     temp >>= 4;
+-     temp = 1 << temp;
+-     temp1 = (ROMAddr[0x23c] << 8) | ROMAddr[0x23b];
+-     if(temp1 & temp) return(1);
+-     else return(0);
++     if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) {
++        temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36) & 0xff;
++        temp >>= 4;
++        temp = 1 << temp;
++        temp1 = (ROMAddr[0x23c] << 8) | ROMAddr[0x23b];
++        if(temp1 & temp) return(1);
++        else return(0);
++     } else return(0);
+   } else {
+      return(0);
+   }
+@@ -6041,12 +6244,14 @@ SiS_CR36BIOSWord23d(SiS_Private *SiS_Pr,
+   UCHAR *ROMAddr;
+   if((ROMAddr = (UCHAR *)HwDeviceExtension->pjVirtualRomBase) && SiS_Pr->SiS_UseROM) {
+-     temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36) & 0xff;
+-     temp >>= 4;
+-     temp = 1 << temp;
+-     temp1 = (ROMAddr[0x23e] << 8) | ROMAddr[0x23d];
+-     if(temp1 & temp) return(1);
+-     else return(0);
++     if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) {
++        temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36) & 0xff;
++        temp >>= 4;
++        temp = 1 << temp;
++        temp1 = (ROMAddr[0x23e] << 8) | ROMAddr[0x23d];
++        if(temp1 & temp) return(1);
++        else return(0);
++     } else return(0);
+   } else {
+      return(0);
+   }
+@@ -6143,7 +6348,7 @@ SiS_SetPanelDelay(SiS_Private *SiS_Pr, U
+ #ifdef SIS315H
+-      if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {                      /* 310/325 series, LVDS */
++      if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {                      /* 315 series, LVDS */
+           if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) {
+               PanelID = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36);
+@@ -6171,7 +6376,7 @@ SiS_SetPanelDelay(SiS_Private *SiS_Pr, U
+             SiS_ShortDelay(SiS_Pr,Delay);
+         }
+-      } else {                                                        /* 310/325 series, 301(B) */
++      } else {                                                        /* 315 series, 301(B) */
+           PanelID = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36);
+         DelayIndex = PanelID >> 4;
+@@ -6271,14 +6476,7 @@ SiS_IsVAMode(SiS_Private *SiS_Pr, PSIS_H
+   if(HwDeviceExtension->jChipType >= SIS_315H) {
+      flag = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x38);
+      if((flag & EnableDualEdge) && (flag & SetToLCDA))   return(1);
+-#if 0 /* Not done in 650/30xLV 1.10.6s, but in 650/301LV */
+-     else if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+-       if(flag) return(1);
+-       else     return(0);                             
+-     }
+-#endif
+-     else
+-       return(0);
++     else return(0);
+   } else
+ #endif
+      return(0);
+@@ -6325,7 +6523,9 @@ SiS_IsNotM650or651(SiS_Private *SiS_Pr, 
+   if(HwDeviceExtension->jChipType == SIS_650) {
+      flag = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x5f);
+      flag &= 0xF0;
+-     if((flag == 0xb0) || (flag == 0x90)) return 0;
++     /* Check for revision != A0 only */
++     if((flag == 0xe0) || (flag == 0xc0) ||
++        (flag == 0xb0) || (flag == 0x90)) return 0;
+      else return 1;
+   } else
+ #endif
+@@ -6443,7 +6643,7 @@ SiS_BridgeIsEnable(SiS_Private *SiS_Pr, 
+       if((flag == 0x80) || (flag == 0x20)) return 0;
+       else                               return 1;
+     } else {
+-      /* 310/325 series (650/30xLV 1.10.6s) */
++      /* 315 series (650/30xLV 1.10.6s) */
+       flag &= 0x50;
+       if((flag == 0x40) || (flag == 0x10)) return 0;
+       else                                 return 1;
+@@ -6487,14 +6687,14 @@ SiS_SetHiVision(SiS_Private *SiS_Pr, USH
+   }
+ }
+-BOOLEAN
++void
+ SiS_GetLCDResInfo(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,
+                   USHORT ModeIdIndex, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+ {
+   USHORT temp,modeflag,resinfo=0;
+   const unsigned char SiS300SeriesLCDRes[] =
+-         { 0, 1, 2, 3, 7, 4, 5, 8,
+-         0, 0, 0, 0, 0, 0, 0, 0 };
++         { 0,  1,  2,  3,  7,  4,  5,  8,
++         0,  0, 10,  0,  0,  0,  0, 15 };
+   SiS_Pr->SiS_LCDResInfo = 0;
+   SiS_Pr->SiS_LCDTypeInfo = 0;
+@@ -6511,17 +6711,19 @@ SiS_GetLCDResInfo(SiS_Private *SiS_Pr, U
+      }
+   }
+-  if(!(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)))   return 0;
++  if(!(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)))   return;
+-  if(!(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchToCRT2))) return 0;
++  if(!(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchToCRT2))) return;
+   temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36);
++#if 0
+   /* FSTN: Fake CR36 (TypeInfo 2, ResInfo SiS_Panel320x480) */
+   if(SiS_Pr->SiS_IF_DEF_FSTN) {
+       temp = 0x20 | SiS_Pr->SiS_Panel320x480;
+       SiS_SetReg1(SiS_Pr->SiS_P3d4,0x36,temp);
+   }
++#endif
+   if(HwDeviceExtension->jChipType < SIS_315H) {
+       SiS_Pr->SiS_LCDTypeInfo = temp >> 4;
+@@ -6530,14 +6732,16 @@ SiS_GetLCDResInfo(SiS_Private *SiS_Pr, U
+   }
+   temp &= 0x0f;
+   if(HwDeviceExtension->jChipType < SIS_315H) {
+-      /* TW: Translate 300 series LCDRes to 310/325 series for unified usage */
++      /* Translate 300 series LCDRes to 315 series for unified usage */
+       temp = SiS300SeriesLCDRes[temp];
+   }
+   SiS_Pr->SiS_LCDResInfo = temp;
++#if 0
+   if(SiS_Pr->SiS_IF_DEF_FSTN){
+               SiS_Pr->SiS_LCDResInfo = SiS_Pr->SiS_Panel320x480;
+   }
++#endif
+   if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+       if(SiS_Pr->SiS_LCDResInfo < SiS_Pr->SiS_PanelMin301)
+@@ -6547,75 +6751,115 @@ SiS_GetLCDResInfo(SiS_Private *SiS_Pr, U
+               SiS_Pr->SiS_LCDResInfo = SiS_Pr->SiS_PanelMinLVDS;
+   }
+-  if(SiS_Pr->SiS_LCDResInfo > SiS_Pr->SiS_PanelMax)
++  if((!SiS_Pr->CP_HaveCustomData) || (SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_PanelCustom)) {
++     if(SiS_Pr->SiS_LCDResInfo > SiS_Pr->SiS_PanelMax)
+       SiS_Pr->SiS_LCDResInfo = SiS_Pr->SiS_Panel1024x768;
++  }
++
++  if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
++     if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) {
++        SiS_Pr->SiS_LCDResInfo = Panel_Barco1366;
++     } else if(SiS_Pr->SiS_CustomT == CUT_PANEL848) {
++        SiS_Pr->SiS_LCDResInfo = Panel_848x480;
++     }
++  }
++
++  switch(SiS_Pr->SiS_LCDResInfo) {
++     case Panel_800x600:   SiS_Pr->PanelXRes =  800; SiS_Pr->PanelYRes =  600; break;
++     case Panel_1024x768:  SiS_Pr->PanelXRes = 1024; SiS_Pr->PanelYRes =  768; break;
++     case Panel_1280x1024: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 1024; break;
++     case Panel_640x480_3:
++     case Panel_640x480_2:
++     case Panel_640x480:   SiS_Pr->PanelXRes =  640; SiS_Pr->PanelYRes =  480; break;
++     case Panel_1024x600:  SiS_Pr->PanelXRes = 1024; SiS_Pr->PanelYRes =  600; break;
++     case Panel_1152x864:  SiS_Pr->PanelXRes = 1152; SiS_Pr->PanelYRes =  864; break;
++     case Panel_1280x960:  SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes =  960; break;
++     case Panel_1152x768:  SiS_Pr->PanelXRes = 1152; SiS_Pr->PanelYRes =  768; break;
++     case Panel_1400x1050: SiS_Pr->PanelXRes = 1400; SiS_Pr->PanelYRes = 1050; break;
++     case Panel_1280x768:  SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes =  768; break;
++     case Panel_1600x1200: SiS_Pr->PanelXRes = 1600; SiS_Pr->PanelYRes = 1200; break;
++     case Panel_320x480:   SiS_Pr->PanelXRes =  320; SiS_Pr->PanelYRes =  480; break;
++     case Panel_Custom:    SiS_Pr->PanelXRes = SiS_Pr->CP_MaxX;
++                         SiS_Pr->PanelYRes = SiS_Pr->CP_MaxY;
++                         break;
++     case Panel_Barco1366: SiS_Pr->PanelXRes = 1360; SiS_Pr->PanelYRes = 1024; break;
++     case Panel_848x480:   SiS_Pr->PanelXRes =  848; SiS_Pr->PanelYRes =  480; break;
++     default:            SiS_Pr->PanelXRes = 1024; SiS_Pr->PanelYRes =  768; break;
++  }
+   temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x37);
++#if 0
+   if(SiS_Pr->SiS_IF_DEF_FSTN){
+-        /* TW: Fake LVDS bridge for FSTN */
++        /* Fake LVDS bridge for FSTN */
+               temp = 0x04;
+               SiS_SetReg1(SiS_Pr->SiS_P3d4,0x37,temp);
+   }
++#endif
+   SiS_Pr->SiS_LCDInfo = temp;
+-  
++
++  if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
++     if(SiS_Pr->SiS_CustomT == CUT_PANEL848) {
++        SiS_Pr->SiS_LCDInfo = 0x80 | 0x40 | 0x20;   /* neg sync, RGB24 */
++     }
++  }
++
+   if(!(SiS_Pr->UsePanelScaler))        SiS_Pr->SiS_LCDInfo &= ~DontExpandLCD;
+   else if(SiS_Pr->UsePanelScaler == 1) SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
+-  /* TW: Inserted entire 315-block from 650/LVDS/30xLV BIOSes */
++  if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
++     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
++        if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom) {
++         /* For non-standard LCD resolution, we let the panel scale */
++           SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
++        } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
++         if(ModeNo == 0x7c || ModeNo == 0x7d || ModeNo == 0x7e) {
++            /* Bridge does not scale to 1280x960 */
++              SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
++         }
++        } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768) {
++           /* TEMP - no idea about the timing and zoom factors */
++           SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
++        } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
++         if(ModeNo == 0x3a || ModeNo == 0x4d || ModeNo == 0x65) {
++            /* Bridge does not scale to 1280x1024 */
++            SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
++         }
++      } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) {
++         /* TEMP - no idea about the timing and zoom factors */
++         SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
++      }
++     }
++  }
++
++
+   if(HwDeviceExtension->jChipType >= SIS_315H) {
+ #ifdef SIS315H
+-     if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+-         if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+-           if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+-               if(ModeNo == 0x3a || ModeNo == 0x4d || ModeNo == 0x65) {
+-                   /* Bridge does not scale to 1280x1024 */
+-                   SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
+-               }
+-           }
+-           if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
+-               if(ModeNo == 0x7c || ModeNo == 0x7d || ModeNo == 0x7e) {
+-                   /* TW: Bridge does not scale to 1280x960 */
+-                   SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
+-               }
+-               if(ModeNo == 0x2f || ModeNo == 0x5d || ModeNo == 0x5e) {
+-                   /* TW: Bridge does not scale to 640x400 */
+-                   SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
+-               }
+-           }
+-           if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+-               if(ModeNo == 0x2f || ModeNo == 0x5d || ModeNo == 0x5e) {
+-                   /* TW: Most panels can't scale to 640x400 */
+-                   SiS_Pr->SiS_LCDInfo &= ~DontExpandLCD;
+-               }
+-           }
+-       }
+-     }
+      if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x01) {
+-         SiS_Pr->SiS_LCDInfo &= 0xFFEF;    
+-       SiS_Pr->SiS_LCDInfo |= LCDPass11;
++        SiS_Pr->SiS_LCDInfo &= 0xFFEF;
++      SiS_Pr->SiS_LCDInfo |= LCDPass11;
+      }
+ #endif
+   } else {
+ #ifdef SIS300
+      if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+         if((ROMAddr) && SiS_Pr->SiS_UseROM) {
+-           if(!(ROMAddr[0x235] & 0x02)) {
+-            SiS_Pr->SiS_LCDInfo &= 0xEF;
++         if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) {
++              if(!(ROMAddr[0x235] & 0x02)) {
++               SiS_Pr->SiS_LCDInfo &= 0xEF;
++            }
+          }
+         }
+-     } else {
+-        if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+-         if((SiS_Pr->SiS_SetFlag & SetDOSMode) && ((ModeNo == 0x03) || (ModeNo == 0x10))) {
+-               SiS_Pr->SiS_LCDInfo &= 0xEF;
+-         }
++     } else if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
++      if((SiS_Pr->SiS_SetFlag & SetDOSMode) && ((ModeNo == 0x03) || (ModeNo == 0x10))) {
++           SiS_Pr->SiS_LCDInfo &= 0xEF;
+       }
+      }
+ #endif
+   }
+-  
+-  /* TW: With Trumpion, always Expanding */
+-  if(SiS_Pr->SiS_IF_DEF_TRUMPION != 0){
+-       SiS_Pr->SiS_LCDInfo &= (~DontExpandLCD);
++
++  /* Trumpion: Assume non-expanding */
++  if(SiS_Pr->SiS_IF_DEF_TRUMPION != 0) {
++     SiS_Pr->SiS_LCDInfo &= (~DontExpandLCD);
+   }
+   if(!((HwDeviceExtension->jChipType < SIS_315H) && (SiS_Pr->SiS_SetFlag & SetDOSMode))) {
+@@ -6624,7 +6868,7 @@ SiS_GetLCDResInfo(SiS_Private *SiS_Pr, U
+         if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) {
+          if(ModeNo > 0x13) {
+             if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) {
+-                 if((resinfo == 7) || (resinfo == 3)) {
++                 if((resinfo == SIS_RI_800x600) || (resinfo == SIS_RI_400x300)) {
+                     SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
+                }
+               }
+@@ -6644,9 +6888,9 @@ SiS_GetLCDResInfo(SiS_Private *SiS_Pr, U
+                                             (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480))) {
+                  if(ModeNo > 0x13) {
+                     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+-                       if(resinfo == 4) SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;     /* 512x384  */
++                       if(resinfo == SIS_RI_512x384) SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
+                     } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) {
+-                       if(resinfo == 3) SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;     /* 400x300  */
++                       if(resinfo == SIS_RI_400x300) SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
+                     }
+                  }
+             } else SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
+@@ -6665,19 +6909,21 @@ SiS_GetLCDResInfo(SiS_Private *SiS_Pr, U
+   }
+ #ifdef SIS315H
+-  /* TW: 650/30xLV 1.10.6s */
++  /* 650/30xLV 1.10.6s */
+   if(HwDeviceExtension->jChipType >= SIS_315H) {
+-    if(SiS_Pr->SiS_VBType & (VB_SIS302B | VB_SIS302LV)) {
+-      /* Enable 302B/302LV dual link mode */
+-      /* (302B is a theory - not in any BIOS */
+-      temp = 0x00;
+-      if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) temp = 0x04;
+-      if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) temp = 0x04;
+-      if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) temp = 0x04;
+-      SiS_SetReg1(SiS_Pr->SiS_P3d4,0x39,temp);
+-    } else if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+-      SiS_SetReg1(SiS_Pr->SiS_P3d4,0x39,0x00);
+-    }
++     if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
++        SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x39,~0x04);
++        if(SiS_Pr->SiS_VBType & (VB_SIS302B | VB_SIS302LV)) {
++           /* Enable 302B/302LV dual link mode.
++            * (302B is a theory - not in any BIOS)
++          */
++           if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) ||
++              (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) ||
++              (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200)) {
++            SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x39,0x04);
++         }
++      }
++     }
+   }
+ #endif
+@@ -6693,20 +6939,6 @@ SiS_GetLCDResInfo(SiS_Private *SiS_Pr, U
+       SiS_Pr->SiS_LCDInfo, SiS_Pr->SiS_LCDResInfo, SiS_Pr->SiS_LCDTypeInfo, SiS_Pr->SiS_SetFlag);
+ #endif
+-  return 1;
+-}
+-
+-void
+-SiS_PresetScratchregister(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+-{
+-  return;
+-  /*SiS_SetReg1(SiS_Pr->SiS_P3d4,0x30,0x21);  */
+-  /*SiS_SetReg1(SiS_Pr->SiS_P3d4,0x31,0x41);  */
+-  /*SiS_SetReg1(SiS_Pr->SiS_P3d4,0x32,0x28);  */
+-  /*SiS_SetReg1(SiS_Pr->SiS_P3d4,0x33,0x22);  */
+-  /*SiS_SetReg1(SiS_Pr->SiS_P3d4,0x35,0x43);  */
+-  /*SiS_SetReg1(SiS_Pr->SiS_P3d4,0x36,0x01);  */
+-  /*SiS_SetReg1(SiS_Pr->SiS_P3d4,0x37,0x00);  */
+ }
+ void
+@@ -6736,7 +6968,6 @@ SiS_VBLongWait(SiS_Private *SiS_Pr)
+   } else {
+     SiS_LongWait(SiS_Pr);
+   }
+-  return;
+ }
+ void
+@@ -6803,7 +7034,7 @@ SiS_WaitRetrace1(SiS_Private *SiS_Pr, PS
+ #endif
+   } else {
+ #ifdef SIS300
+-#if 0  /* TW: Not done in A901 BIOS */
++#if 0  /* Not done in A901 BIOS */
+      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+         if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1f) & 0xc0) return;
+      }
+@@ -6898,7 +7129,51 @@ void SiS_SetRegOR(USHORT Port,USHORT Ind
+ /* ========================================================= */
+-/* TW: Set 301 TV Encoder (and some LCD relevant) registers */
++static void
++SiS_SetTVSpecial(SiS_Private *SiS_Pr, USHORT ModeNo)
++{
++  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
++     if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
++        if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
++           if((ModeNo == 0x64) || (ModeNo == 0x4a) || (ModeNo == 0x38)) {
++              SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1c,0xa7);
++              SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1d,0x07);
++            SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1e,0xf2);
++            SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1f,0x6e);
++            SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x20,0x17);
++            SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x21,0x8b);
++            SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x22,0x73);
++            SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x23,0x53);
++            SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x24,0x13);
++            SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x25,0x40);
++            SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x26,0x34);
++            SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x27,0xf4);
++            SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x28,0x63);
++            SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x29,0xbb);
++            SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2a,0xcc);
++            SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2b,0x7a);
++            SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2c,0x58);   /* 48 */
++            SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2d,0xe4);
++            SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2e,0x73);
++            SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2f,0xda);   /* de */
++            SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x30,0x13);
++            if((SiS_GetReg1(SiS_Pr->SiS_P3d4,0x38)) & 0x40) {
++               SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x01,0x14);
++            } else {
++               SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x01,0x15);
++            }
++            SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x02,0x1b);
++            SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x43,0x72);
++           }
++        } else {
++         SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x01,0x21);
++         SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x02,0x5a);
++      }
++     }
++  }
++}
++
++/* Set 301 TV Encoder (and some LCD relevant) registers */
+ void
+ SiS_SetGroup2(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr, USHORT ModeNo,
+               USHORT ModeIdIndex,USHORT RefreshRateTableIndex,
+@@ -6911,67 +7186,46 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHOR
+ #ifdef SIS315H   
+   const       SiS_Part2PortTblStruct *CRT2Part2Ptr = NULL;
+   USHORT      resindex, CRT2Index;
+-#endif  
++#endif
+   USHORT      modeflag, resinfo, crt2crtc;
+-  ULONG       longtemp, tempeax, tempebx, temp2, tempecx;
++  ULONG       longtemp, tempeax;
++#ifdef SIS300
+   const UCHAR atable[] = {
+                  0xc3,0x9e,0xc3,0x9e,0x02,0x02,0x02,
+                0xab,0x87,0xab,0x9e,0xe7,0x02,0x02
+   };
++#endif
+ #ifdef SIS315H   
+   if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+-     /* TW: 650/30xLV 1.10.6s: (Is at end of SetGroup2!) */
++     /* 650/30xLV 1.10.6s: (Is at end of SetGroup2!) */
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+         if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+          SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1a,0xfc,0x03);
+-         temp = 1;
+-         if(ModeNo <= 0x13) temp = 3;
++         temp = 0x01;
++         if(ModeNo <= 0x13) temp = 0x03;
+          SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x0b,temp);
+       }
+      }
+-     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+-       if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+-         if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+-           if((ModeNo == 0x4a) || (ModeNo == 0x38)) {
+-               SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1c,0xa7);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1d,0x07);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1e,0xf2);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1f,0x6e);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x20,0x17);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x21,0x8b);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x22,0x73);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x23,0x53);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x24,0x13);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x25,0x40);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x26,0x34);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x27,0xf4);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x28,0x63);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x29,0xbb);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2a,0xcc);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2b,0x7a);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2c,0x58);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2d,0xe4);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2e,0x73);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2f,0xda);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x30,0x13);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x43,0x72);
+-           }
+-         }
+-       }
+-     }
++     SiS_SetTVSpecial(SiS_Pr, ModeNo);
+      return;
+   }
+-#endif  
++#endif
+-  if(ModeNo<=0x13) {
+-      modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;      /* si+St_ResInfo */
+-      resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+-      crt2crtc = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
++  if(ModeNo <= 0x13) {
++     modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
++     resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
++     crt2crtc = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+   } else {
+-      modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;     /* si+Ext_ResInfo */
++     if(SiS_Pr->UseCustomMode) {
++        modeflag = SiS_Pr->CModeFlag;
++      resinfo = 0;
++      crt2crtc = 0;
++     } else {
++        modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+       resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+       crt2crtc = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
++     }
+   }
+   tempcx = SiS_Pr->SiS_VBInfo;
+@@ -6984,9 +7238,9 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHOR
+   temp |= ((tempbx & 0x00FF) >> 3);
+   temp ^= 0x0C;
+-  /* TW: From 1.10.7w (no vb check there; don't care - this only disables SVIDEO and CVBS signal) */
++  /* From 1.10.7w (no vb check there; don't care - this only disables SVIDEO and CVBS signal) */
+   if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+-      temp |= 0x0c;
++     temp |= 0x0c;
+   }
+   PhasePoint  = SiS_Pr->SiS_PALPhase;
+@@ -6994,44 +7248,44 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHOR
+   
+   if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {          
+   
+-    temp ^= 0x01;
+-    if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+-      TimingPoint = SiS_Pr->SiS_HiTVSt2Timing;
+-      if(SiS_Pr->SiS_SetFlag & TVSimuMode) {
+-        if(modeflag & Charx8Dot) TimingPoint = SiS_Pr->SiS_HiTVSt1Timing;
+-        else TimingPoint = SiS_Pr->SiS_HiTVTextTiming;
+-      }
+-    } else TimingPoint = SiS_Pr->SiS_HiTVExtTiming;
+-    
+-    if(SiS_Pr->SiS_HiVision & 0x03) temp &= 0xfe;
+-    
++     temp ^= 0x01;
++     if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
++        TimingPoint = SiS_Pr->SiS_HiTVSt2Timing;
++        if(SiS_Pr->SiS_SetFlag & TVSimuMode) {
++           if(modeflag & Charx8Dot) TimingPoint = SiS_Pr->SiS_HiTVSt1Timing;
++           else TimingPoint = SiS_Pr->SiS_HiTVTextTiming;
++        }
++     } else TimingPoint = SiS_Pr->SiS_HiTVExtTiming;
++
++     if(SiS_Pr->SiS_HiVision & 0x03) temp &= 0xfe;
++
+   } else {
+-  
+-    if(SiS_Pr->SiS_VBInfo & SetPALTV){
+-      TimingPoint = SiS_Pr->SiS_PALTiming;
+-      PhasePoint  = SiS_Pr->SiS_PALPhase;
++     if(SiS_Pr->SiS_VBInfo & SetPALTV){
+-      if( (SiS_Pr->SiS_VBType & VB_SIS301B302B) &&
+-          ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
+-          (SiS_Pr->SiS_SetFlag & TVSimuMode) ) ) {
+-         PhasePoint = SiS_Pr->SiS_PALPhase2;
+-      }
++        TimingPoint = SiS_Pr->SiS_PALTiming;
++        PhasePoint  = SiS_Pr->SiS_PALPhase;
+-    } else {
++        if( (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) &&
++            ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
++            (SiS_Pr->SiS_SetFlag & TVSimuMode) ) ) {
++           PhasePoint = SiS_Pr->SiS_PALPhase2;
++        }
++
++     } else {
+         temp |= 0x10;
+-      TimingPoint = SiS_Pr->SiS_NTSCTiming;
+-      PhasePoint  = SiS_Pr->SiS_NTSCPhase;
++        TimingPoint = SiS_Pr->SiS_NTSCTiming;
++        PhasePoint  = SiS_Pr->SiS_NTSCPhase;
+-        if( (SiS_Pr->SiS_VBType & VB_SIS301B302B) &&
++        if( (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) &&
+           ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
+             (SiS_Pr->SiS_SetFlag & TVSimuMode) ) ) {
+-              PhasePoint = SiS_Pr->SiS_NTSCPhase2;
++           PhasePoint = SiS_Pr->SiS_NTSCPhase2;
+         }
+-    }
+-    
++     }
++
+   }
+   SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x00,temp);
+@@ -7044,36 +7298,35 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHOR
+      temp = 0x38;
+   }
+   if(temp) {
+-    if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+-      if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x31) & 0x01) {
+-          temp1 = SiS_GetReg1(SiS_Pr->SiS_P3d4,temp);
+-          if(temp1 & EnablePALM) {    /* 0x40 */
+-                      PhasePoint = SiS_Pr->SiS_PALMPhase;
+-              if( (SiS_Pr->SiS_VBType & VB_SIS301B302B) &&
+-                  ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
+-                    (SiS_Pr->SiS_SetFlag & TVSimuMode) ) ) {
+-                 PhasePoint = SiS_Pr->SiS_PALMPhase2;
+-              }
+-        }
+-          if(temp1 & EnablePALN) {    /* 0x80 */
+-                      PhasePoint = SiS_Pr->SiS_PALNPhase;
+-              if( (SiS_Pr->SiS_VBType & VB_SIS301B302B) &&
+-                  ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
+-                    (SiS_Pr->SiS_SetFlag & TVSimuMode) ) ) {
+-                 PhasePoint = SiS_Pr->SiS_PALNPhase2;
+-              }
+-        }
+-      }
+-    }
++     if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
++        if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x31) & 0x01) {
++           temp1 = SiS_GetReg1(SiS_Pr->SiS_P3d4,temp);
++           if(temp1 & EnablePALM) {   /* 0x40 */
++              PhasePoint = SiS_Pr->SiS_PALMPhase;
++            if( (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) &&
++                ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
++                  (SiS_Pr->SiS_SetFlag & TVSimuMode) ) ) {
++               PhasePoint = SiS_Pr->SiS_PALMPhase2;
++            }
++         }
++           if(temp1 & EnablePALN) {   /* 0x80 */
++              PhasePoint = SiS_Pr->SiS_PALNPhase;
++            if( (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) &&
++                ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
++                  (SiS_Pr->SiS_SetFlag & TVSimuMode) ) ) {
++               PhasePoint = SiS_Pr->SiS_PALNPhase2;
++            }
++         }
++        }
++     }
+   }
+ #ifdef SIS315H
+-  /* TW: 650/301LV BIOS */
+   if(HwDeviceExtension->jChipType >= SIS_315H) {
+      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {  
+         if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+            if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+-              if((ModeNo == 0x4a) || (ModeNo == 0x38)) {
++              if((ModeNo == 0x64) || (ModeNo == 0x4a) || (ModeNo == 0x38)) {
+                PhasePoint = SiS_Pr->SiS_SpecialPhase;
+             }
+            }
+@@ -7094,12 +7347,12 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHOR
+   }
+   if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+-    if(HwDeviceExtension->jChipType >= SIS_315H) {
+-      if(!(SiS_Pr->SiS_ModeType & 0x07))
++     if(HwDeviceExtension->jChipType >= SIS_315H) {
++        if(!(SiS_Pr->SiS_ModeType & 0x07))
++           SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x3A,0x1F);
++     } else {
+         SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x3A,0x1F);
+-    } else {
+-      SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x3A,0x1F);
+-    }
++     }
+   }
+   SiS_SetRegOR(SiS_Pr->SiS_Part2Port,0x0A,SiS_Pr->SiS_NewFlickerMode);
+@@ -7110,11 +7363,11 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHOR
+   SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x38,SiS_Pr->SiS_RY4COE);
+   if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {
+-      if(SiS_Pr->SiS_HiVision == 3) tempax = 950;
+-      else tempax = 440;
++     if(SiS_Pr->SiS_HiVision == 3) tempax = 950;
++     else tempax = 440;
+   } else {
+-    if(SiS_Pr->SiS_VBInfo & SetPALTV) tempax = 520;
+-    else tempax = 440;
++     if(SiS_Pr->SiS_VBInfo & SetPALTV) tempax = 520;
++     else tempax = 440;
+   }
+   if( ( ( (!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) || (SiS_Pr->SiS_HiVision == 3) ) && (SiS_Pr->SiS_VDE <= tempax) ) ||
+@@ -7134,18 +7387,18 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHOR
+      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x02,temp);
+      if( (SiS_Pr->SiS_VBInfo & (SetCRT2ToTV - SetCRT2ToHiVisionTV)) &&
+-        (SiS_Pr->SiS_HiVision != 3) &&
+-        (SiS_Pr->SiS_VGAHDE >= 1024) ) {
++         (SiS_Pr->SiS_HiVision != 3) &&
++         (SiS_Pr->SiS_VGAHDE >= 1024) ) {
+         if(SiS_Pr->SiS_VBInfo & SetPALTV) {
+            SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x01,0x19);
+            SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x02,0x52);
+         } else {
+            if(HwDeviceExtension->jChipType >= SIS_315H) {
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x01,0x17);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x02,0x1d);
++              SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x01,0x17);
++              SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x02,0x1d);
+          } else {
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x01,0x0b);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x02,0x11);
++              SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x01,0x0b);
++              SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x02,0x11);
+          }
+         }
+      }
+@@ -7154,7 +7407,7 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHOR
+   tempcx = SiS_Pr->SiS_HT;
+-  /* TW: 650/30xLV 1.10.6s */
++  /* 650/30xLV 1.10.6s */
+   if(HwDeviceExtension->jChipType >= SIS_315H) {
+       if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04) {
+                  tempcx >>= 1;
+@@ -7181,7 +7434,7 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHOR
+   tempcx += 7;
+   if((SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) &&
+      (SiS_Pr->SiS_HiVision == 3)) {
+-       tempcx -= 4;
++     tempcx -= 4;
+   }
+   temp = (tempcx & 0x00FF) << 4;
+   SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x22,0x0F,temp);
+@@ -7201,8 +7454,8 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHOR
+   tempbx += 8;
+   if((SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) &&
+      (SiS_Pr->SiS_HiVision == 3)) {
+-    tempbx -= 4;
+-    tempcx = tempbx;
++     tempbx -= 4;
++     tempcx = tempbx;
+   }
+   temp = (tempbx & 0x00FF) << 4;
+   SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x29,0x0F,temp);
+@@ -7231,8 +7484,8 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHOR
+   tempcx -= 11;
+   if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) {
+-    tempax = SiS_GetVGAHT2(SiS_Pr) - 1;
+-    tempcx = tempax;
++     tempax = SiS_GetVGAHT2(SiS_Pr) - 1;
++     tempcx = tempax;
+   }
+   temp = tempcx & 0x00FF;
+   SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2E,temp);
+@@ -7242,38 +7495,38 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHOR
+   if(SiS_Pr->SiS_VGAVDE == 375) tempbx = 746;
+   if(SiS_Pr->SiS_VGAVDE == 405) tempbx = 853;
+   if(HwDeviceExtension->jChipType < SIS_315H) {
+-      if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) tempbx >>= 1;
++     if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) tempbx >>= 1;
+   } else {
+-      if((SiS_Pr->SiS_VBInfo & SetCRT2ToTV) && (!(SiS_Pr->SiS_HiVision & 0x03))) {
+-         tempbx >>= 1;
+-         if(SiS_Pr->SiS_SetFlag & TVSimuMode) {
+-            if(ModeNo <= 0x13) {
+-               if(crt2crtc == 1) {
+-                  tempbx++;
+-                 }
+-            }
+-         } else {
+-              if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+-               if(crt2crtc == 4)   /* TW: BIOS calls GetRatePtrCRT2 here - does not make sense */
+-                    if(SiS_Pr->SiS_ModeType <= 3) tempbx++;
+-            }
++     if((SiS_Pr->SiS_VBInfo & SetCRT2ToTV) && (!(SiS_Pr->SiS_HiVision & 0x03))) {
++      tempbx >>= 1;
++      if(SiS_Pr->SiS_SetFlag & TVSimuMode) {
++         if(ModeNo <= 0x13) {
++            if(crt2crtc == 1) {
++               tempbx++;
++              }
+          }
+-        }
++      } else {
++           if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
++            if(crt2crtc == 4)   /* BIOS calls GetRatePtrCRT2 here - does not make sense */
++                 if(SiS_Pr->SiS_ModeType <= 3) tempbx++;
++         }
++      }
++     }
+   }
+   tempbx -= 2;
+   temp = tempbx & 0x00FF;
+   if((SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) &&
+      (SiS_Pr->SiS_HiVision == 3)) {
+-    if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+-      if(ModeNo == 0x2f) temp++;
+-    }
++     if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
++        if((ModeNo == 0x2f) || (ModeNo == 0x5d) || (ModeNo == 0x5e)) temp++;
++     }
+   }
+-  /* TW: From 1.10.7w - doesn't make sense */
++  /* From 1.10.7w - doesn't make sense */
+   if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+      if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+         if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+          if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {   /* SetFlag?? */
+-             if(ModeNo == 0x03) temp++;
++            if(ModeNo == 0x03) temp++;
+          }
+       }
+      }
+@@ -7285,15 +7538,15 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHOR
+   tempax |= (tempbx & 0xFF00);
+   if(HwDeviceExtension->jChipType < SIS_315H) {
+      if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV)) {
+-        if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToSCART)) {          /* TW: New from 630/301B (II) BIOS */
++        if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToSCART)) {          /* New from 630/301B (II) BIOS */
+            tempax |= 0x1000;
+            if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToSVIDEO))  tempax |= 0x2000;
+         }
+      }
+   } else {
+      /* TODO Check this with other BIOSes */
+-     if((!(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV)) && 
+-        (SiS_Pr->SiS_HiVision == 3)) {
++     if((!(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV))
++         /* && (SiS_Pr->SiS_HiVision == 3) */ ) {
+       tempax |= 0x1000;
+         if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToSVIDEO))  tempax |= 0x2000;
+      }
+@@ -7301,12 +7554,12 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHOR
+   temp = (tempax & 0xFF00) >> 8;
+   SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x30,temp);
+-  /* TW: 650/30xLV 1.10.6s */
++  /* 650/30xLV 1.10.6s */
+   if(HwDeviceExtension->jChipType > SIS_315H) {
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+         if( (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) ||
+             (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) ) {
+-            SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x10,0x60);
++           SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x10,0x60);
+         }
+      }
+   }
+@@ -7322,79 +7575,70 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHOR
+      }
+   }
+-  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {     
+-    tempbx = SiS_Pr->SiS_VDE;
+-    if((SiS_Pr->SiS_VBInfo & SetCRT2ToTV) && (!(SiS_Pr->SiS_HiVision & 0x03))) {
+-         tempbx >>= 1;
+-    }
+-    tempbx -= 3;
+-    tempbx &= 0x03ff;
+-    temp = ((tempbx & 0xFF00) >> 8) << 5;
+-    temp |= 0x18;
+-    SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x46,temp);
+-    temp = tempbx & 0x00FF;
+-    SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x47,temp);     /* tv gatingno */
+-    if(HwDeviceExtension->jChipType >= SIS_315H) {    /* TW: 650/30xLV 1.10.6s */
+-       if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+-          tempax = 0;
+-          if(SiS_Pr->SiS_HiVision & 0x03) {
+-           tempax = 0x3000;
+-           if(SiS_Pr->SiS_HiVision & 0x01) tempax = 0x5000;
+-        }
+-        temp = (tempax & 0xFF00) >> 8;
+-          SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x4d,temp);
+-       }
+-    }
++  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
++     tempbx = SiS_Pr->SiS_VDE;
++     if((SiS_Pr->SiS_VBInfo & SetCRT2ToTV) && (!(SiS_Pr->SiS_HiVision & 0x03))) {
++        tempbx >>= 1;
++     }
++     tempbx -= 3;
++     tempbx &= 0x03ff;
++     temp = ((tempbx & 0xFF00) >> 8) << 5;
++     temp |= 0x18;
++     SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x46,temp);
++     temp = tempbx & 0x00FF;
++     SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x47,temp);    /* tv gatingno */
++     if(HwDeviceExtension->jChipType >= SIS_315H) {
++        if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
++           tempax = 0;
++           if(SiS_Pr->SiS_HiVision & 0x03) {
++            tempax = 0x3000;
++            if(SiS_Pr->SiS_HiVision & 0x01) tempax = 0x5000;
++         }
++         temp = (tempax & 0xFF00) >> 8;
++           SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x4d,temp);
++        }
++     }
+   }
+   tempbx &= 0x00FF;
+   if(!(modeflag & HalfDCLK)) {
+-    tempcx = SiS_Pr->SiS_VGAHDE;
+-    if(tempcx >= SiS_Pr->SiS_HDE) {
+-      tempbx |= 0x2000;
+-      tempax &= 0x00FF;
+-    }
++     if(SiS_Pr->SiS_VGAHDE >= SiS_Pr->SiS_HDE) {
++        tempbx |= 0x2000;
++        tempax &= 0x00FF;
++     }
+   }
+   tempcx = 0x0101;
+-/*if(SiS_Pr->SiS_VBInfo & (SetPALTV | SetCRT2ToTV)) {  */ /*301b- TW: BIOS BUG? */
++/*if(SiS_Pr->SiS_VBInfo & (SetPALTV | SetCRT2ToTV)) {  */ /* BIOS BUG? */
+   if(SiS_Pr->SiS_VBInfo & (SetCRT2ToTV - SetCRT2ToHiVisionTV)) {
+-    if(!(SiS_Pr->SiS_HiVision & 0x03)) {
+-      if(SiS_Pr->SiS_VGAHDE >= 1024) {
+-        if((!(modeflag & HalfDCLK)) || (HwDeviceExtension->jChipType < SIS_315H)) {   /* TW: This check not in 630/301B */
+-          tempcx = 0x1920;
+-          if(SiS_Pr->SiS_VGAHDE >= 1280) {
+-            tempcx = 0x1420;
+-            tempbx &= 0xDFFF;
+-          }
++     if(!(SiS_Pr->SiS_HiVision & 0x03)) {
++        if(SiS_Pr->SiS_VGAHDE >= 1024) {
++           if((!(modeflag & HalfDCLK)) || (HwDeviceExtension->jChipType < SIS_315H)) {
++              tempcx = 0x1920;
++              if(SiS_Pr->SiS_VGAHDE >= 1280) {
++                 tempcx = 0x1420;
++                 tempbx &= 0xDFFF;
++              }
++           }
+         }
+-      }
+-    }
++     }
+   }
+   if(!(tempbx & 0x2000)) {
+-    if(modeflag & HalfDCLK) {
+-         tempcx = (tempcx & 0xFF00) | (((tempcx & 0x00FF) << 1) & 0xff);
+-    }
+-    push1 = tempbx;
+-    tempeax = SiS_Pr->SiS_VGAHDE;
+-    tempebx = (tempcx & 0xFF00) >> 8;
+-    longtemp = tempeax * tempebx;
+-    tempecx = tempcx & 0x00FF;
+-    longtemp /= tempecx;
+-    longtemp <<= 0x0d;
+-    if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
++     if(modeflag & HalfDCLK) {
++        tempcx = (tempcx & 0xFF00) | ((tempcx << 1) & 0x00FF);
++     }
++     longtemp = (SiS_Pr->SiS_VGAHDE * ((tempcx & 0xFF00) >> 8)) / (tempcx & 0x00FF);
++     longtemp <<= 13;
++     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+       longtemp <<= 3;
+-    }
+-    tempecx = SiS_Pr->SiS_HDE;
+-    temp2 = longtemp % tempecx;
+-    tempeax = longtemp / tempecx;
+-    if(temp2 != 0) tempeax++;
+-    tempax = (USHORT)tempeax;
+-    tempbx = push1;
+-    tempcx = (tempcx & 0xff00) | (((tempax & 0xFF00) >> 8) >> 5);
+-    tempbx |= (tempax & 0x1F00);
+-    tempax = ((tempax & 0x00FF) << 8) | (tempax & 0x00FF);
++     }
++     tempeax = longtemp / SiS_Pr->SiS_HDE;
++     if(longtemp % SiS_Pr->SiS_HDE) tempeax++;
++     tempax = (USHORT)tempeax;
++     tempcx = (tempcx & 0xFF00) | ((tempax & 0xFF00) >> (8 + 5));
++     tempbx |= (tempax & 0x1F00);
++     tempax = ((tempax & 0x00FF) << 8) | (tempax & 0x00FF);
+   }
+   temp = (tempax & 0xFF00) >> 8;
+@@ -7403,33 +7647,32 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHOR
+   SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x45,0xC0,temp);
+   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+-       temp = tempcx & 0x00FF;
+-       if(tempbx & 0x2000) temp = 0;
+-       temp |= 0x18;
+-       SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x46,0xE0,temp);
+-       if(SiS_Pr->SiS_VBInfo & SetPALTV) {
+-             tempbx = 0x0382;  
+-             tempcx = 0x007e;  
+-       } else {
+-             tempbx = 0x0369;  
+-             tempcx = 0x0061;  
+-       }
+-       temp = (tempbx & 0x00FF) ;
+-       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x4B,temp);
+-       temp = (tempcx & 0x00FF) ;
+-       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x4C,temp);
+-       tempbx &= 0x03FF;
+-       temp = (tempcx & 0xFF00) >> 8;
+-       temp = (temp & 0x0003) << 2;
+-       temp |= (tempbx >> 8);
+-       if(HwDeviceExtension->jChipType < SIS_315H) {
+-          SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x4D,temp);
+-       } else {
+-          SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x4D,0xF0,temp);
+-       }
++     temp = tempcx & 0x00FF;
++     if(tempbx & 0x2000) temp = 0;
++     temp |= 0x18;
++     SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x46,0xE0,temp);
+-       temp = SiS_GetReg1(SiS_Pr->SiS_Part2Port,0x43);
+-       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x43,(USHORT)(temp - 3));
++     if(SiS_Pr->SiS_VBInfo & SetPALTV) {
++        tempbx = 0x0382;
++        tempcx = 0x007e;
++     } else {
++        tempbx = 0x0369;
++        tempcx = 0x0061;
++     }
++     temp = (tempbx & 0x00FF) ;
++     SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x4B,temp);
++     temp = (tempcx & 0x00FF) ;
++     SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x4C,temp);
++     temp = (tempcx & 0x0300) >> (8 - 2);
++     temp |= ((tempbx >> 8) & 0x03);
++     if(HwDeviceExtension->jChipType < SIS_315H) {
++        SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x4D,temp);
++     } else {
++        SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x4D,0xF0,temp);
++     }
++
++     temp = SiS_GetReg1(SiS_Pr->SiS_Part2Port,0x43);
++     SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x43,(USHORT)(temp - 3));
+   }
+   temp = 0;
+@@ -7440,23 +7683,33 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHOR
+      temp = 0x38;
+   }
+   if(temp) {
+-      if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+-          if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x31) & 0x01) {
+-               if(SiS_GetReg1(SiS_Pr->SiS_P3d4,temp) & EnablePALM) {  /* 0x40 */
+-                     SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xEF);
+-                     temp = SiS_GetReg1(SiS_Pr->SiS_Part2Port,0x01);
+-                     SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x01,temp - 1);
+-               }
+-          }
+-      }
++     if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
++        if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x31) & 0x01) {
++           if(SiS_GetReg1(SiS_Pr->SiS_P3d4,temp) & EnablePALM) {  /* 0x40 */
++              SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xEF);
++              temp = SiS_GetReg1(SiS_Pr->SiS_Part2Port,0x01);
++              SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x01,temp - 1);
++           }
++        }
++     }
+   }
++  if(HwDeviceExtension->jChipType >= SIS_315H) {
++     if((SiS_Pr->SiS_VBType & VB_SIS301B302B) && (!(SiS_Pr->SiS_VBType & VB_NoLCD))) {
++        if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
++           SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x0B,0x00);
++        }
++     }
++  }
++
++#if 0  /* Old: Why HiVision? */
+   if( (SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) &&
+       (!(SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) ) {
+-    if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+-      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x0B,0x00);
+-    }
++     if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
++        SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x0B,0x00);
++     }
+   }
++#endif
+   if(HwDeviceExtension->jChipType < SIS_315H) {
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+@@ -7465,74 +7718,43 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHOR
+       return;
+      }
+   } else {
+-     /* TW: !!! The following is a duplicate, done for LCDA as well (see above) */
++     /* !!! The following is a duplicate, done for LCDA as well (see above) */
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+-       if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {    
+-         if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+-           if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+-             if((ModeNo == 0x4a) || (ModeNo == 0x38)) {
+-               SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1c,0xa7);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1d,0x07);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1e,0xf2);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1f,0x6e);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x20,0x17);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x21,0x8b);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x22,0x73);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x23,0x53);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x24,0x13);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x25,0x40);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x26,0x34);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x27,0xf4);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x28,0x63);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x29,0xbb);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2a,0xcc);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2b,0x7a);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2c,0x58);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2d,0xe4);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2e,0x73);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2f,0xda);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x30,0x13);
+-             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x43,0x72);
+-           }
+-           }
+-         }
+-       }
+-       return;
++        SiS_SetTVSpecial(SiS_Pr, ModeNo);
++        return;
+      }
+   }
+-  /* TW: From here: Part2 LCD setup */
++  /* From here: Part2 LCD setup */
+   tempbx = SiS_Pr->SiS_HDE;
+   if(HwDeviceExtension->jChipType >= SIS_315H) {
+-      /* TW: 650/30xLV 1.10.6s */
+-      if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04) tempbx >>= 1;
++     /* 650/30xLV 1.10.6s */
++     if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04) tempbx >>= 1;
+   }
+   tempbx--;                                   /* RHACTE=HDE-1 */
+   temp = tempbx & 0x00FF;
+   SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2C,temp);
+-  temp = (tempbx & 0xFF00) >> 8;
+-  temp <<= 4;
++  temp = (tempbx & 0xFF00) >> 4;
+   SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2B,0x0F,temp);
+   temp = 0x01;
+   if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
+-    if(SiS_Pr->SiS_ModeType == ModeEGA) {
+-      if(SiS_Pr->SiS_VGAHDE >= 1024) {
+-        temp = 0x02;
+-      if(HwDeviceExtension->jChipType >= SIS_315H) {
+-           if(SiS_Pr->SiS_SetFlag & LCDVESATiming) {
+-             temp = 0x01;
++     if(SiS_Pr->SiS_ModeType == ModeEGA) {
++        if(SiS_Pr->SiS_VGAHDE >= 1024) {
++           temp = 0x02;
++         if(HwDeviceExtension->jChipType >= SIS_315H) {
++              if(SiS_Pr->SiS_SetFlag & LCDVESATiming) {
++                 temp = 0x01;
++            }
+          }
+-      }
+-      }
+-    }
++        }
++     }
+   }
+   SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x0B,temp);
+-  tempbx = SiS_Pr->SiS_VDE;                   /* RTVACTEO=(VDE-1)&0xFF */
+-  push1 = tempbx;
+-
++  tempbx = SiS_Pr->SiS_VDE;                   /* RTVACTEO = VDE - 1 */
++  /* push1 = tempbx; */
+   tempbx--;
+   temp = tempbx & 0x00FF;
+   SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x03,temp);
+@@ -7540,10 +7762,9 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHOR
+   SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x0C,0xF8,temp);
+   tempcx = SiS_Pr->SiS_VT;
+-  push2 = tempcx;
+-
++  /* push2 = tempcx; */
+   tempcx--;
+-  temp = tempcx & 0x00FF;                      /* RVTVT=VT-1 */
++  temp = tempcx & 0x00FF;                      /* RVTVT = VT - 1 */
+   SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x19,temp);
+   temp = (tempcx & 0xFF00) >> 8;
+@@ -7551,40 +7772,42 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHOR
+   
+   /* Enable dithering; newer versions only do this for 32bpp mode */
+   if((HwDeviceExtension->jChipType == SIS_300) && (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) {
+-    if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) temp |= 0x10;
++     if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) temp |= 0x10;
+   } else if(HwDeviceExtension->jChipType < SIS_315H) {
+-    if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) temp |= 0x10;
+-    else {
+-      if(SiS_Pr->SiS_LCDInfo & LCDSync)       /* TW: 630/301 BIOS checks this */
+-         temp |= 0x10;
+-    }
++     temp |= 0x10;
+   } else {
+-      if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+-         /* TW: 650/30xLV 1.10.6s */
+-         if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) {
+-            if(SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00) & 0x01) {  /* 32bpp mode? */
+-                     temp |= 0x10;
+-          }
+-         }
+-      } else {
+-         temp |= 0x10;
+-      }
++     if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
++        /* 650/30xLV 1.10.6s */
++        if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) {
++           if(SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00) & 0x01) {  /* 32bpp mode? */
++              temp |= 0x10;
++         }
++        }
++     } else {
++        temp |= 0x10;
++     }
+   }
+   /* 630/301 does not do all this */
+   if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) {
+      if((HwDeviceExtension->jChipType >= SIS_315H) && (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) {
+-        /* TW: 650/30xLV 1.10.6s */
+-        temp |= (SiS_GetReg1(SiS_Pr->SiS_P3d4,0x37) >> 6);
+-      temp |= 0x08;                                           /* From 1.10.7w */
+-      if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) temp |= 0x04;  /* From 1.10.7w */
+-     } else {
+-        tempbx = (tempbx & 0xFF00) | (SiS_Pr->SiS_LCDInfo & 0x0FF);
+-        if(tempbx & LCDSync) {
+-           tempbx &= 0xFFE0;
+-           tempbx = (tempbx & 0xFF00) | ((tempbx & 0x00FF) >> 6);
+-           temp |= (tempbx & 0x00FF);
+-        }
++      if((SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) &&
++         (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024)) {
++#ifdef SIS315H
++         if(SiS_Pr->SiS_LCDInfo & LCDSync) {
++            temp |= (SiS_Pr->SiS_LCDInfo >> 6);
++         }
++#endif
++      } else {
++         /* 650/30xLV 1.10.6s */
++           temp |= (SiS_GetReg1(SiS_Pr->SiS_P3d4,0x37) >> 6);
++         temp |= 0x08;                                                /* From 1.10.7w */
++         if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) temp |= 0x04;       /* From 1.10.7w */
++      }
++     } else {
++        if(SiS_Pr->SiS_LCDInfo & LCDSync) {
++         temp |= (SiS_Pr->SiS_LCDInfo >> 6);
++      }
+      }
+   }
+   SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1A,temp);
+@@ -7595,24 +7818,22 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHOR
+   SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x17,0xFB);
+   SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x18,0xDF);
+-  /* 1280x960, 1280x1024 and 1600x1200 data invalid/missing in tables, use old calculation */
+-  if((HwDeviceExtension->jChipType >= SIS_315H)             && 
+-     (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)                &&  
+-     (SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x1024) &&
+-     (SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1600x1200) &&
+-     (SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x960)) {
++  if((HwDeviceExtension->jChipType >= SIS_315H)         &&
++     (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)            &&
++     ((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)  ||
++      (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) ||
++      (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) ||
++      (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200)) ) {
+      
+-#ifdef SIS315H                                                        /* ------------- 310/325/330 series ------------ */
++#ifdef SIS315H                                                        /* ------------- 315/330 series ------------ */
+-      /* TW: Inserted this entire section from 650/301LV(x) BIOS */
+-      
+       /* Using this on the 301B with an auto-expanding 1024 panel (CR37=1) results
+        * in a black bar in modes < 1024; if the panel is non-expanding, the bridge
+        * scales all modes to 1024. All modes in both variants (exp/non-exp) work.
+        */
+       SiS_GetCRT2Part2Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+-                         &CRT2Index,&resindex);
++                         &CRT2Index,&resindex,HwDeviceExtension);
+       switch(CRT2Index) {
+         case Panel_1024x768      : CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_1;  break;  /* "Normal" */
+@@ -7627,6 +7848,9 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHOR
+         case Panel_1280x1024 + 32: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1280x1024_3; break;
+       case Panel_1400x1050 + 32: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1400x1050_3; break;
+       case Panel_1600x1200 + 32: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1600x1200_3; break;
++      case 100:                  CRT2Part2Ptr = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_Compaq1280x1024_1; break;  /* Custom */
++      case 101:                  CRT2Part2Ptr = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_Compaq1280x1024_2; break;
++      case 102:                  CRT2Part2Ptr = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_Compaq1280x1024_3; break;
+       default:                   CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_3;  break;
+       }
+@@ -7653,8 +7877,7 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHOR
+         }
+         SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2f,temp);
+         SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x30,0xb3);
+-      }
+-      if(SiS_Pr->SiS_VGAVDE == 420) {
++      } else if(SiS_Pr->SiS_VGAVDE == 420) {
+         temp = 0x4d;
+         if(SiS_Pr->SiS_ModeType <= ModeVGA) {
+            temp++;
+@@ -7664,7 +7887,6 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHOR
+       }
+      }
+-     /* TW: 650/30xLV 1.10.6s: */
+      /* !!! This is a duplicate, done for LCDA as well - see above */
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+         if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+@@ -7683,59 +7905,46 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHOR
+        * the bridge scales all modes to 1024.
+        * !!! Malfunction at 640x480 and 640x400 when panel is auto-expanding - black screen !!!
+        */
+-  
++
++    /* cx = VT - 1 */
++
+     tempcx++;
+-    
+-    if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)       tempbx =  768;
+-    else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) tempbx = 1024;
+-    else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) tempbx = 1200;
+-    else if(SiS_Pr->SiS_VDE != 1024)                            tempbx =  960;
+-    else                                                        tempbx = 1024;
+-    
+-#if 0  /* old */
+-    tempbx = 768;
+-    if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1024x768) {
+-      tempbx = 1024;
+-      if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x1024) {
+-         tempbx = 1200;
+-         if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1600x1200) {
+-            if(tempbx != SiS_Pr->SiS_VDE) {
+-               tempbx = 960;
+-            }
+-         }
+-      }
+-    }
+-#endif
+-    
++
++    tempbx = SiS_Pr->PanelYRes;
++
+     if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+-      tempbx = SiS_Pr->SiS_VDE - 1;
+-      tempcx--;
++       tempbx = SiS_Pr->SiS_VDE - 1;
++       tempcx--;
+     }
+-    
++
+     tempax = 1;
+     if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) {
+-      if(tempbx != SiS_Pr->SiS_VDE) {
+-        tempax = tempbx;
+-/*    if(SiS_Pr->SiS_VGAVDE == 525) tempax += 60;   in 650/301B BIOS */
+-        if(tempax < SiS_Pr->SiS_VDE) {
+-          tempax = 0;
+-          tempcx = 0;
+-        } else {
+-          tempax -= SiS_Pr->SiS_VDE;
+-        }
+-        tempax >>= 1;
+-      }
+-      tempcx -= tempax; /* lcdvdes */
+-      tempbx -= tempax; /* lcdvdee */
+-    } else {
+-      tempax >>= 1;
+-      tempcx -= tempax; /* lcdvdes */
+-      tempbx -= tempax; /* lcdvdee */
++       if(tempbx != SiS_Pr->SiS_VDE) {
++          tempax = tempbx;
++          if(tempax < SiS_Pr->SiS_VDE) {
++             tempax = 0;
++             tempcx = 0;
++          } else {
++             tempax -= SiS_Pr->SiS_VDE;
++          }
++          tempax >>= 1;
++       }
++       tempcx -= tempax; /* lcdvdes */
++       tempbx -= tempax; /* lcdvdee */
+     }
+-    
++#if 0  /* meaningless: 1 / 2 = 0... */
++    else {
++       tempax >>= 1;
++       tempcx -= tempax; /* lcdvdes */
++       tempbx -= tempax; /* lcdvdee */
++    }
++#endif
++
++    /* Non-expanding: lcdvdees = tempcx = VT-1; lcdvdee = tempbx = VDE-1 */
++
+ #ifdef TWDEBUG
+-    xf86DrvMsg(0, X_INFO, "lcdvds 0x%x lcdvde 0x%x\n", tempcx, tempbx);
+-#endif    
++    xf86DrvMsg(0, X_INFO, "lcdvdes 0x%x lcdvdee 0x%x\n", tempcx, tempbx);
++#endif
+     temp = tempcx & 0x00FF;                                   /* RVEQ1EQ=lcdvdes */
+     SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x05,temp);
+@@ -7746,140 +7955,178 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHOR
+     temp |= ((tempcx & 0xFF00) >> 8);
+     SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x02,temp);
+-    tempbx = push2;
+-    tempax = push1;
+-    tempcx = tempbx;
+-    tempcx -= tempax;
+-    tempcx >>= 4;
++    tempbx = SiS_Pr->SiS_VT;    /* push2; */
++    tempax = SiS_Pr->SiS_VDE;   /* push1; */
++    tempcx = (tempbx - tempax) >> 4;
+     tempbx += tempax;
+     tempbx >>= 1;
+     if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)  tempbx -= 10;
+-    
++
++    /* non-expanding: lcdvrs = tempbx = ((VT + VDE) / 2) - 10 */
++
++    if(SiS_Pr->UseCustomMode) {
++       tempbx = SiS_Pr->CVSyncStart;
++    }
++
+ #ifdef TWDEBUG
+     xf86DrvMsg(0, X_INFO, "lcdvrs 0x%x\n", tempbx);
+ #endif
+-    temp = tempbx & 0x00FF;                                   /* RTVACTEE=lcdvrs */
++    temp = tempbx & 0x00FF;                                   /* RTVACTEE = lcdvrs */
+     SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x04,temp);
+     temp = ((tempbx & 0xFF00) >> 8) << 4;
+     tempbx += (tempcx + 1);
+     temp |= (tempbx & 0x000F);
++
++    if(SiS_Pr->UseCustomMode) {
++       temp &= 0xf0;
++       temp |= (SiS_Pr->CVSyncEnd & 0x0f);
++    }
++
++#ifdef TWDEBUG
++    xf86DrvMsg(0, X_INFO, "lcdvre[3:0] 0x%x\n", (temp & 0x0f));
++#endif
++
+     SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x01,temp);
+-    /* TW: Code from 630/301B (I+II) BIOS */
++    /* Code from 630/301B (I+II) BIOS */
+-    if( ( ( (HwDeviceExtension->jChipType == SIS_630) ||
+-            (HwDeviceExtension->jChipType == SIS_730) ) &&
+-          (HwDeviceExtension->jChipRevision > 2) )  &&
+-        (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) &&
+-        (!(SiS_Pr->SiS_SetFlag & LCDVESATiming))  &&
+-        (!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) ) {
+-            if(ModeNo == 0x13) {
+-              SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x04,0xB9);
+-              SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x05,0xCC);
+-              SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x06,0xA6);
+-            } else {
+-              if((crt2crtc & 0x3F) == 4) {
++    if(!SiS_Pr->UseCustomMode) {
++       if( ( ( (HwDeviceExtension->jChipType == SIS_630) ||
++               (HwDeviceExtension->jChipType == SIS_730) ) &&
++             (HwDeviceExtension->jChipRevision > 2) )  &&
++           (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) &&
++           (!(SiS_Pr->SiS_SetFlag & LCDVESATiming))  &&
++           (!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) ) {
++          if(ModeNo == 0x13) {
++             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x04,0xB9);
++             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x05,0xCC);
++             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x06,0xA6);
++          } else {
++             if((crt2crtc & 0x3F) == 4) {
+                 SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x01,0x2B);
+                 SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x02,0x13);
+                 SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x04,0xE5);
+                 SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x05,0x08);
+                 SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x06,0xE2);
+-              }
+-            }
++             }
++          }
++       }
+     }
+-    /* TW: Inserted missing code from 630/301B BIOS;
+-     *     Strangely, this is done in all 650 BIOSes as
+-     *     well (although LCDTypeInfo is not used there
+-     *     in the same way as on 300 series)
+-     */
+-
+-    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_SetReg1(SiS_Pr->SiS_Part2Port,0x06,0xff);
+-         }
++#ifdef SIS300
++    if(HwDeviceExtension->jChipType < SIS_315H) {
++       if(!SiS_Pr->UseCustomMode) {
++          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_SetReg1(SiS_Pr->SiS_Part2Port,0x06,0xff);
++             }
+-         if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) {
+-           if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+-             if(crt2crtc == 4) {
+-                SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x01,0x28);
++             if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) {
++                if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
++                   if(crt2crtc == 4) {
++                      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x01,0x28);
++                   }
++                }
+              }
+-           }
+-         }
+-         SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x02,0x18);
+-         SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x04,atable[tempcx]);
++             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x02,0x18);
++             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x04,atable[tempcx]);
++          }
++       }
+     }
++#endif
+-    tempcx = (SiS_Pr->SiS_HT - SiS_Pr->SiS_HDE) >> 2;     /* (HT-HDE)>>2     */
++    tempcx = (SiS_Pr->SiS_HT - SiS_Pr->SiS_HDE) >> 2;     /* (HT - HDE) >> 2 */
+     tempbx = SiS_Pr->SiS_HDE + 7;                       /* lcdhdee         */
+     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+-         tempbx += 2;
++       tempbx += 2;
+     }
+     push1 = tempbx;
++
+ #ifdef TWDEBUG
+-    xf86DrvMsg(0, X_INFO, "lcdhde 0x%x\n", tempbx);
+-#endif    
+-    temp = tempbx & 0x00FF;                                     /* RHEQPLE=lcdhdee */
++    xf86DrvMsg(0, X_INFO, "lcdhdee 0x%x\n", tempbx);
++#endif
++
++    temp = tempbx & 0x00FF;                                     /* RHEQPLE = lcdhdee */
+     SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x23,temp);
+     temp = (tempbx & 0xFF00) >> 8;
+     SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x25,0xF0,temp);
+     temp = 7;
+     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+-         temp += 2;
++       temp += 2;
+     }
+-    SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1F,temp);       /* RHBLKE=lcdhdes[7:0] */
++    SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1F,temp);       /* RHBLKE = lcdhdes[7:0] */
+     SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x20,0x0F);     /* lcdhdes [11:8] */
+     tempbx += tempcx;
+     push2 = tempbx;
++
++    if(SiS_Pr->UseCustomMode) {
++       tempbx = SiS_Pr->CHSyncStart + 7;
++       if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
++          tempbx += 2;
++       }
++    }
++
+ #ifdef TWDEBUG
+     xf86DrvMsg(0, X_INFO, "lcdhrs 0x%x\n", tempbx);
+ #endif
+-    temp = tempbx & 0x00FF;                                     /* RHBURSTS=lcdhrs */
+-    if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
+-       if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { 
+-          if(SiS_Pr->SiS_HDE == 1280) temp = 0x47;
++
++    temp = tempbx & 0x00FF;                                     /* RHBURSTS = lcdhrs */
++    if(!SiS_Pr->UseCustomMode) {
++       if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
++          if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
++             if(SiS_Pr->SiS_HDE == 1280) temp = 0x47;
++          }
+        }
+     }
+     SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1C,temp);
+-    temp = ((tempbx & 0xFF00) >> 8) << 4;
++    temp = (tempbx & 0x0F00) >> 4;
+     SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1D,0x0F,temp);
+     tempbx = push2;
+     tempcx <<= 1;
+     tempbx += tempcx;
++
++    if(SiS_Pr->UseCustomMode) {
++       tempbx = SiS_Pr->CHSyncEnd + 7;
++       if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
++          tempbx += 2;
++       }
++    }
++
+ #ifdef TWDEBUG
+     xf86DrvMsg(0, X_INFO, "lcdhre 0x%x\n", tempbx);
+-#endif    
+-    temp = tempbx & 0x00FF;                                     /* RHSYEXP2S=lcdhre */
++#endif
++
++    temp = tempbx & 0x00FF;                                     /* RHSYEXP2S = lcdhre */
+     SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x21,temp);
+     if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {
+-      if(SiS_Pr->SiS_VGAVDE == 525) {
+-        if(SiS_Pr->SiS_ModeType <= ModeVGA)
+-         temp=0xC6;
+-        else
+-                 temp=0xC3;
+-        SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2f,temp);
+-        SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x30,0xB3);
+-      } else if(SiS_Pr->SiS_VGAVDE == 420) {
+-        if(SiS_Pr->SiS_ModeType <= ModeVGA)
+-         temp=0x4F;
+-        else
+-                 temp=0x4D;   
+-        SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2f,temp);
+-      }
++       if(SiS_Pr->SiS_VGAVDE == 525) {
++          if(SiS_Pr->SiS_ModeType <= ModeVGA)
++           temp=0xC6;
++          else
++                   temp=0xC3;
++          SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2f,temp);
++          SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x30,0xB3);
++       } else if(SiS_Pr->SiS_VGAVDE == 420) {
++          if(SiS_Pr->SiS_ModeType <= ModeVGA)
++           temp=0x4F;
++          else
++                   temp=0x4D;
++          SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2f,temp);
++       }
+     }
+     SiS_Set300Part2Regs(SiS_Pr, HwDeviceExtension, ModeIdIndex,
+                         RefreshRateTableIndex, BaseAddr, ModeNo);
+@@ -7898,7 +8145,7 @@ SiS_GetVGAHT2(SiS_Private *SiS_Pr)
+   return((USHORT) tempax);
+ }
+-/* TW: New from 300/301LV BIOS 1.16.51 for ECS A907. Seems highly preliminary. */
++/* New from 300/301LV BIOS 1.16.51 for ECS A907. Seems highly preliminary. */
+ void
+ SiS_Set300Part2Regs(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                       USHORT ModeIdIndex, USHORT RefreshRateTableIndex,
+@@ -7910,18 +8157,19 @@ SiS_Set300Part2Regs(SiS_Private *SiS_Pr,
+   if(HwDeviceExtension->jChipType != SIS_300) return;
+   if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) return;
++  if(SiS_Pr->UseCustomMode) return;
+-  if(ModeNo<=0x13) {
+-      crt2crtc = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
++  if(ModeNo <= 0x13) {
++     crt2crtc = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+   } else {
+-      crt2crtc = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
++     crt2crtc = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+   }
+   resindex = crt2crtc & 0x3F;
+   if(SiS_Pr->SiS_SetFlag & LCDVESATiming) CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_1;
+   else                                    CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_2;
+-  /* TW: The BIOS code (1.16.51) is obviously a fragment! */
++  /* The BIOS code (1.16.51) is obviously a fragment! */
+   if(ModeNo > 0x13) {
+      CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_1;
+      resindex = 4;
+@@ -7942,7 +8190,6 @@ SiS_Set300Part2Regs(SiS_Private *SiS_Pr,
+   SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x25,0x0f,(CRT2Part2Ptr+resindex)->CR[11]);
+ }
+-/* TW: Set 301 Macrovision(tm) registers */
+ void
+ SiS_SetGroup3(SiS_Private *SiS_Pr, USHORT  BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
+               USHORT ModeIdIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
+@@ -7954,24 +8201,35 @@ SiS_SetGroup3(SiS_Private *SiS_Pr, USHOR
+   if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) return;
+-  if(ModeNo<=0x13)
+-      modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+-  else
++  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;
++     }
++  }
++#ifndef SIS_CP
+   SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x00,0x00);
++#endif
++
++#ifdef SIS_CP
++  SIS_CP_INIT301_CP
++#endif
+   if(SiS_Pr->SiS_VBInfo & SetPALTV) {
+-    SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x13,0xFA);
+-    SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x14,0xC8);
++     SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x13,0xFA);
++     SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x14,0xC8);
+   } else {
+-    if(HwDeviceExtension->jChipType >= SIS_315H) {
+-      SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x13,0xF5);
+-      SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x14,0xB7);
+-    } else {
+-      SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x13,0xF6);
+-      SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x14,0xBf);
+-    }
++     if(HwDeviceExtension->jChipType >= SIS_315H) {
++        SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x13,0xF5);
++        SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x14,0xB7);
++     } else {
++        SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x13,0xF6);
++        SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x14,0xBf);
++     }
+   }
+   temp = 0;
+@@ -7982,38 +8240,41 @@ SiS_SetGroup3(SiS_Private *SiS_Pr, USHOR
+      temp = 0x38;
+   }
+   if(temp) {
+-      if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+-          if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x31) & 0x01) {
+-              if(SiS_GetReg1(SiS_Pr->SiS_P3d4,temp) & EnablePALM){  /* 0x40 */
+-                  SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x13,0xFA);
+-                  SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x14,0xC8);
+-                  SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x3D,0xA8);
+-              }
+-          }
+-      }
++     if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
++        if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x31) & 0x01) {
++           if(SiS_GetReg1(SiS_Pr->SiS_P3d4,temp) & EnablePALM){  /* 0x40 */
++              SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x13,0xFA);
++              SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x14,0xC8);
++              SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x3D,0xA8);
++           }
++        }
++     }
+   }
+   if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {
+-    tempdi = SiS_Pr->SiS_HiTVGroup3Data;
+-    if(SiS_Pr->SiS_SetFlag & TVSimuMode) {
+-      tempdi = SiS_Pr->SiS_HiTVGroup3Simu;
+-      if(!(modeflag & Charx8Dot)) {
+-        tempdi = SiS_Pr->SiS_HiTVGroup3Text;
+-      }
+-    }
+-    if(SiS_Pr->SiS_HiVision & 0x03) {
+-       tempdi = SiS_HiTVGroup3_1;
+-       if(SiS_Pr->SiS_HiVision & 0x02) tempdi = SiS_HiTVGroup3_2;
+-    }
+-    for(i=0; i<=0x3E; i++){
+-       SiS_SetReg1(SiS_Pr->SiS_Part3Port,i,tempdi[i]);
+-    }
++     tempdi = SiS_Pr->SiS_HiTVGroup3Data;
++     if(SiS_Pr->SiS_SetFlag & TVSimuMode) {
++        tempdi = SiS_Pr->SiS_HiTVGroup3Simu;
++        if(!(modeflag & Charx8Dot)) {
++           tempdi = SiS_Pr->SiS_HiTVGroup3Text;
++        }
++     }
++     if(SiS_Pr->SiS_HiVision & 0x03) {
++        tempdi = SiS_HiTVGroup3_1;
++        if(SiS_Pr->SiS_HiVision & 0x02) tempdi = SiS_HiTVGroup3_2;
++     }
++     for(i=0; i<=0x3E; i++){
++        SiS_SetReg1(SiS_Pr->SiS_Part3Port,i,tempdi[i]);
++     }
+   }
+-  return;
++#ifdef SIS_CP
++  SIS_CP_INIT301_CP2
++#endif
++
+ }
+-/* TW: Set 301 VGA2 registers */
++/* Set 301 VGA2 registers */
+ void
+ SiS_SetGroup4(SiS_Private *SiS_Pr, USHORT  BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
+               USHORT ModeIdIndex,USHORT RefreshRateTableIndex,
+@@ -8022,17 +8283,20 @@ SiS_SetGroup4(SiS_Private *SiS_Pr, USHOR
+   USHORT tempax,tempcx,tempbx,modeflag,temp,temp2,resinfo;
+   ULONG tempebx,tempeax,templong;
+-
+-  if(ModeNo<=0x13) {
+-      modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+-      resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
++  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;
++     } else {
+       modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+       resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
++     }
+   }
+   if(HwDeviceExtension->jChipType >= SIS_315H) {
+-      /* TW: From 650/302LV 1.10.6s (not for 300/301LV - no LCDA on this combination) */
+      if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+         if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+            SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x24,0x0e);
+@@ -8049,10 +8313,10 @@ SiS_SetGroup4(SiS_Private *SiS_Pr, USHOR
+   if(HwDeviceExtension->jChipType >= SIS_315H) {
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+         if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+-         /* TW: From 650/301LV (any, incl. 1.10.6s, 1.10.7w) */
+-         /* TW: This is a duplicate; done at the end, too */
++         /* From 650/301LV (any, incl. 1.10.6s, 1.10.7w) */
++         /* This is a duplicate; done at the end, too */
+          if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04) {
+-              SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x27,0x2c);
++            SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x27,0x2c);
+          }
+          SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x2a,0x00);
+          SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x30,0x00);
+@@ -8090,39 +8354,33 @@ SiS_SetGroup4(SiS_Private *SiS_Pr, USHOR
+   tempbx = SiS_Pr->SiS_VGAHDE;
+   if(modeflag & HalfDCLK)  tempbx >>= 1;
+-  /* TW: New for 650/301LV and 630/301B */
+   temp = 0xA0;
+   if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {
+-       temp = 0;
+-       if(tempbx > 800) {
+-          temp = 0xA0;
+-          if(tempbx != 1024) {
+-             temp = 0xC0;
+-             if(tempbx != 1280) temp = 0;
+-        }
+-       }
+-  } else
+-    if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+-      if(tempbx <= 800) {
+-         temp = 0x80;
+-       if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+-            temp = 0;
+-            if(tempbx > 800) temp = 0x60;
+-         }
+-      }
++     temp = 0;
++     if(tempbx > 800) {
++        temp = 0xA0;
++        if(tempbx != 1024) {
++           temp = 0xC0;
++           if(tempbx != 1280) temp = 0;
++      }
++     }
++  } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
++     if(tempbx <= 800) {
++        temp = 0x80;
++     }
+   } else {
+-      temp = 0x80;
+-      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+-            temp = 0;
+-            if(tempbx > 800) temp = 0x60;
+-      }
++     temp = 0x80;
++     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
++        temp = 0;
++        if(tempbx > 800) temp = 0x60;
++     }
+   }
+   if(SiS_Pr->SiS_HiVision & 0x03) {
+         temp = 0;
+       if(SiS_Pr->SiS_VGAHDE == 1024) temp = 0x20;
+   }
+   if(HwDeviceExtension->jChipType >= SIS_315H) {
+-      if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04) temp = 0;
++     if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04) temp = 0;
+   }
+   if(SiS_Pr->SiS_VBType & VB_SIS301) {
+@@ -8144,10 +8402,10 @@ SiS_SetGroup4(SiS_Private *SiS_Pr, USHOR
+   tempeax = SiS_Pr->SiS_VGAVDE;
+   tempcx |= 0x4000;
+-  if(tempeax <= tempebx){
+-    tempcx ^= 0x4000;
++  if(tempeax <= tempebx) {
++     tempcx ^= 0x4000;
+   } else {
+-    tempeax -= tempebx;
++     tempeax -= tempebx;
+   }
+   templong = (tempeax * 256 * 1024) % tempebx;
+@@ -8173,64 +8431,64 @@ SiS_SetGroup4(SiS_Private *SiS_Pr, USHOR
+          tempax = SiS_Pr->SiS_VGAHDE;
+          if(modeflag & HalfDCLK) tempax >>= 1;
+          if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) || (SiS_Pr->SiS_HiVision & 0x03)) {
+-           if(HwDeviceExtension->jChipType >= SIS_315H) {
+-               if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04) tempax >>= 1;
+-               else if(tempax > 800) tempax -= 800;
+-           } else {
+-                 if(tempax > 800) tempax -= 800;
+-             }
++          if(HwDeviceExtension->jChipType >= SIS_315H) {
++             if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04) tempax >>= 1;
++             else if(tempax > 800) tempax -= 800;
++          } else {
++               if(tempax > 800) tempax -= 800;
++            }
+          }
+ /*       if((SiS_Pr->SiS_VBInfo & (SetCRT2ToTV | SetPALTV)) && (!(SiS_Pr->SiS_HiVision & 0x03))) {  */
+        if((SiS_Pr->SiS_VBInfo & (SetCRT2ToTV - SetCRT2ToHiVisionTV)) && (!(SiS_Pr->SiS_HiVision & 0x03))) {
+-           if(tempax > 800) {
+-            tempbx = 8;
+-              if(tempax == 1024)
+-              tempax *= 25;
+-              else
+-              tempax *= 20;
+-
+-            temp = tempax % 32;
+-            tempax /= 32;
+-            tempax--;
+-            if (temp!=0) tempax++;
+-           }
++            if(tempax > 800) {
++             tempbx = 8;
++               if(tempax == 1024)
++                tempax *= 25;
++               else
++                tempax *= 20;
++
++             temp = tempax % 32;
++             tempax /= 32;
++             tempax--;
++             if (temp!=0) tempax++;
++            }
+          }
+        tempax--;
+          temp = (tempax & 0xFF00) >> 8;
+          temp &= 0x03;
+-       if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {         /* From 1.10.7w */
+-              if(ModeNo > 0x13) {                     /* From 1.10.7w */
+-                      if(resinfo == 8) tempax = 0x1f; /* From 1.10.7w */
+-              }                                       /* From 1.10.7w */
+-       }                                              /* From 1.10.7w */
++       if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {                 /* From 1.10.7w */
++          if(ModeNo > 0x13) {                                 /* From 1.10.7w */
++             if(resinfo == SIS_RI_1024x768) tempax = 0x1f;    /* From 1.10.7w */
++          }                                                   /* From 1.10.7w */
++       }                                                      /* From 1.10.7w */
+        SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x1D,tempax & 0x00FF);
+        temp <<= 4;
+        temp |= tempbx;
+        SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x1E,temp);
+        if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+-          if(IS_SIS650740) {
+-              temp = 0x0026;  /* 1.10.7w; 1.10.8r; needs corresponding code in Dis/EnableBridge! */
++          if(IS_SIS550650740660) {
++             temp = 0x0026;  /* 1.10.7w; 1.10.8r; needs corresponding code in Dis/EnableBridge! */
+           } else {
+-              temp = 0x0036;
++             temp = 0x0036;
+           }
+        } else {
+-           temp = 0x0036;
++          temp = 0x0036;
+        }
+          if((SiS_Pr->SiS_VBInfo & (SetCRT2ToTV - SetCRT2ToHiVisionTV)) &&
+                                      (!(SiS_Pr->SiS_HiVision & 0x03))) {
+-              temp |= 0x01;
+-              if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+-                if(!(SiS_Pr->SiS_SetFlag & TVSimuMode))
+-                        temp &= 0xFE;
+-              }
++          temp |= 0x01;
++          if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
++             if(!(SiS_Pr->SiS_SetFlag & TVSimuMode))
++                temp &= 0xFE;
++          }
+          }
+          SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x1F,0xC0,temp);
+        tempbx = SiS_Pr->SiS_HT;
+        if(HwDeviceExtension->jChipType >= SIS_315H) {
+-              if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04) tempbx >>= 1;
++          if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04) tempbx >>= 1;
+        }
+          tempbx >>= 1;
+        tempbx -= 2;
+@@ -8238,7 +8496,7 @@ SiS_SetGroup4(SiS_Private *SiS_Pr, USHOR
+          SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x21,0xC0,temp);
+          temp = tempbx & 0x00FF;
+          SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x22,temp);
+-       
++
+          if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+           if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+                SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x24,0x0e);
+@@ -8246,24 +8504,24 @@ SiS_SetGroup4(SiS_Private *SiS_Pr, USHOR
+        }
+        if(HwDeviceExtension->jChipType >= SIS_315H) {
+-           /* TW: 650/LV BIOS does this for all bridge types - assumingly wrong */
+-           /* 315, 330, 650+301B BIOS don't do this at all */
+-             /* TW: This is a duplicate; done for LCDA as well (see above) */
+-           if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+-              if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04) {
+-                 SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x27,0x2c);
+-              }
+-              SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x2a,0x00);
+-              SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x30,0x00);
+-              SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x34,0x10);
+-           }
++          /* 650/LV BIOS does this for all bridge types - assumingly wrong */
++          /* 315, 330, 650+301B BIOS don't do this at all */
++            /* This is a duplicate; done for LCDA as well (see above) */
++          if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
++             if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04) {
++                SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x27,0x2c);
++             }
++             SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x2a,0x00);
++             SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x30,0x00);
++             SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x34,0x10);
++          }
+          } else if(HwDeviceExtension->jChipType == SIS_300) {
+-           /* TW: 300/301LV BIOS does this for all bridge types - assumingly wrong */
+-           if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+-              SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x2a,0x00);
+-              SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x30,0x00);
+-              SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x34,0x10);
+-           }
++          /* 300/301LV BIOS does this for all bridge types - assumingly wrong */
++          if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
++             SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x2a,0x00);
++             SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x30,0x00);
++             SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x34,0x10);
++          }
+        }
+   }  /* 301B */
+@@ -8278,21 +8536,26 @@ SiS_SetCRT2VCLK(SiS_Private *SiS_Pr, USH
+                  USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
+ {
+   USHORT vclkindex;
+-  USHORT tempah;
++  USHORT temp, reg1, reg2;
+-  vclkindex = SiS_GetVCLK2Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+-                              HwDeviceExtension);
++  if(SiS_Pr->UseCustomMode) {
++     reg1 = SiS_Pr->CSR2B;
++     reg2 = SiS_Pr->CSR2C;
++  } else {
++     vclkindex = SiS_GetVCLK2Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
++                                 HwDeviceExtension);
++     reg1 = SiS_Pr->SiS_VBVCLKData[vclkindex].Part4_A;
++     reg2 = SiS_Pr->SiS_VBVCLKData[vclkindex].Part4_B;
++  }
+   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+-     tempah = SiS_Pr->SiS_VBVCLKData[vclkindex].Part4_A;
+-     SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0A,tempah);
+-     tempah = SiS_Pr->SiS_VBVCLKData[vclkindex].Part4_B;
+-     SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0B,tempah);
++     SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0A,reg1);
++     SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0B,reg2);
+      if(HwDeviceExtension->jChipType >= SIS_315H) {
+       if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+            if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+             if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+-                 if((ModeNo == 0x4a) || (ModeNo == 0x38)) {
++                 if((ModeNo == 0x64) || (ModeNo == 0x4a) || (ModeNo == 0x38)) {
+                   SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0a,0x57);
+                   SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0b,0x46);
+                   SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x1f,0xf6);
+@@ -8303,15 +8566,13 @@ SiS_SetCRT2VCLK(SiS_Private *SiS_Pr, USH
+      }
+   } else {    
+      SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0A,0x01);
+-     tempah = SiS_Pr->SiS_VBVCLKData[vclkindex].Part4_B;
+-     SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0B,tempah);
+-     tempah = SiS_Pr->SiS_VBVCLKData[vclkindex].Part4_A;
+-     SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0A,tempah);
++     SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0B,reg2);
++     SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0A,reg1);
+   }
+   SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x12,0x00);
+-  tempah = 0x08;
+-  if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) tempah |= 0x20;
+-  SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x12,tempah);
++  temp = 0x08;
++  if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) temp |= 0x20;
++  SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x12,temp);
+ }
+ USHORT
+@@ -8319,23 +8580,24 @@ SiS_GetVCLK2Ptr(SiS_Private *SiS_Pr, UCH
+                 USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
+ {
+   USHORT tempbx;
+-  const USHORT LCDXlat0VCLK[4]    = {VCLK40, VCLK40, VCLK40, VCLK40};
+-  const USHORT LVDSXlat1VCLK[4]   = {VCLK40, VCLK40, VCLK40, VCLK40};
++  const USHORT LCDXlat0VCLK[4]    = {VCLK40,       VCLK40,       VCLK40,       VCLK40};
++  const USHORT LVDSXlat1VCLK[4]   = {VCLK40,       VCLK40,       VCLK40,       VCLK40};
++  const USHORT LVDSXlat4VCLK[4]   = {VCLK28,       VCLK28,       VCLK28,       VCLK28};
+ #ifdef SIS300
+-  const USHORT LCDXlat1VCLK300[4] = {VCLK65,   VCLK65,   VCLK65,   VCLK65};
+-  const USHORT LCDXlat2VCLK300[4] = {VCLK108_2,VCLK108_2,VCLK108_2,VCLK108_2};
+-  const USHORT LVDSXlat2VCLK300[4]= {VCLK65,   VCLK65,   VCLK65,   VCLK65};
+-  const USHORT LVDSXlat3VCLK300[4]= {VCLK65,   VCLK65,   VCLK65,   VCLK65};
++  const USHORT LCDXlat1VCLK300[4] = {VCLK65_300,   VCLK65_300,   VCLK65_300,   VCLK65_300};
++  const USHORT LCDXlat2VCLK300[4] = {VCLK108_2_300,VCLK108_2_300,VCLK108_2_300,VCLK108_2_300};
++  const USHORT LVDSXlat2VCLK300[4]= {VCLK65_300,   VCLK65_300,   VCLK65_300,   VCLK65_300};
++  const USHORT LVDSXlat3VCLK300[4]= {VCLK65_300,   VCLK65_300,   VCLK65_300,   VCLK65_300};
+ #endif
+ #ifdef SIS315H
+-  const USHORT LCDXlat1VCLK310[4] = {VCLK65+2,   VCLK65+2,   VCLK65+2,   VCLK65+2};
+-  const USHORT LCDXlat2VCLK310[4] = {VCLK108_2+5,VCLK108_2+5,VCLK108_2+5,VCLK108_2+5};
+-  const USHORT LVDSXlat2VCLK310[4]= {VCLK65+2,   VCLK65+2,   VCLK65+2,   VCLK65+2};
+-  const USHORT LVDSXlat3VCLK310[4]= {VCLK108_2+5,VCLK108_2+5,VCLK108_2+5,VCLK108_2+5};
++  const USHORT LCDXlat1VCLK310[4] = {VCLK65_315,   VCLK65_315,   VCLK65_315,   VCLK65_315};
++  const USHORT LCDXlat2VCLK310[4] = {VCLK108_2_315,VCLK108_2_315,VCLK108_2_315,VCLK108_2_315};
++  const USHORT LVDSXlat2VCLK310[4]= {VCLK65_315,   VCLK65_315,   VCLK65_315,   VCLK65_315};
++  const USHORT LVDSXlat3VCLK310[4]= {VCLK108_2_315,VCLK108_2_315,VCLK108_2_315,VCLK108_2_315};
+ #endif
+   USHORT CRT2Index,VCLKIndex=0;
+   USHORT modeflag,resinfo;
+-  const UCHAR *CHTVVCLKPtr=NULL;
++  const UCHAR  *CHTVVCLKPtr = NULL;
+   const USHORT *LCDXlatVCLK1 = NULL;
+   const USHORT *LCDXlatVCLK2 = NULL;
+   const USHORT *LVDSXlatVCLK2 = NULL;
+@@ -8372,33 +8634,40 @@ SiS_GetVCLK2Ptr(SiS_Private *SiS_Pr, UCH
+      if(SiS_Pr->SiS_SetFlag & ProgrammingCRT2) {
+         CRT2Index >>= 6;
+-        if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)){      /*  LCD */
++        if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {      /*  LCD */
+             if(HwDeviceExtension->jChipType < SIS_315H) {
+-             if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600)
++             if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) {
+                       VCLKIndex = LCDXlat0VCLK[CRT2Index];
+-             else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)
++             } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+                       VCLKIndex = LCDXlatVCLK1[CRT2Index];
+-             else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600)
++             } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) {
+                       VCLKIndex = LCDXlatVCLK1[CRT2Index];
+-             else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768)
++             } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768) {
+                       VCLKIndex = LCDXlatVCLK1[CRT2Index];
+-             else
++             } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768) {
++                      VCLKIndex = VCLK81_300; /* guessed */
++             } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960) {
++                      VCLKIndex = VCLK108_3_300;
++                      if(resinfo == SIS_RI_1280x1024) VCLKIndex = VCLK100_300;
++             } else {
+                       VCLKIndex = LCDXlatVCLK2[CRT2Index];
++             }
+           } else {
+-               /* TW: 330, 650/301LV BIOS does not check expanding, 315 does  */
+-             if( (HwDeviceExtension->jChipType > SIS_315PRO) ||
++             if( (SiS_Pr->SiS_VBType & VB_SIS301LV302LV) ||
+                  (!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) ) {
+                         if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
+-                   VCLKIndex = 0x19;
++                   VCLKIndex = VCLK108_2_315;
++                } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768) {
++                   VCLKIndex = VCLK81_315;    /* guessed */
+                 } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+-                   VCLKIndex = 0x19;
++                   VCLKIndex = VCLK108_2_315;
+                 } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) {
+-                   VCLKIndex = 0x21;
++                   VCLKIndex = VCLK162_315;
++                } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960) {
++                   VCLKIndex = VCLK108_3_315;
++                   if(resinfo == SIS_RI_1280x1024) VCLKIndex = VCLK100_315;
+                 } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+                    VCLKIndex = LCDXlatVCLK1[CRT2Index];
+-                  } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960) {
+-                   VCLKIndex = 0x45;  /* TW: in VBVCLK table */
+-                   if(resinfo == 0x09) VCLKIndex++;
+                 } else {
+                    VCLKIndex = LCDXlatVCLK2[CRT2Index];
+                         }
+@@ -8408,12 +8677,18 @@ SiS_GetVCLK2Ptr(SiS_Private *SiS_Pr, UCH
+                  if(ModeNo > 0x13) {
+                       VCLKIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
+                  }
+-                 if(ModeNo <= 0x13) {  /* TW: 315 BIOS */
+-                    if(SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC == 1) VCLKIndex = 0x42;
++                 if(ModeNo <= 0x13) {
++                    if(HwDeviceExtension->jChipType <= SIS_315PRO) {
++                       if(SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC == 1) VCLKIndex = 0x42;
++                    } else {
++                       if(SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC == 1) VCLKIndex = 0x00;
++                    }
++                 }
++                 if(HwDeviceExtension->jChipType <= SIS_315PRO) {
++                    if(VCLKIndex == 0) VCLKIndex = 0x41;
++                    if(VCLKIndex == 1) VCLKIndex = 0x43;
++                    if(VCLKIndex == 4) VCLKIndex = 0x44;
+                  }
+-                 if(VCLKIndex == 0) VCLKIndex = 0x41;
+-                 if(VCLKIndex == 1) VCLKIndex = 0x43;
+-                 if(VCLKIndex == 4) VCLKIndex = 0x44;
+              }
+           }
+         } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {                 /*  TV */
+@@ -8429,9 +8704,11 @@ SiS_GetVCLK2Ptr(SiS_Private *SiS_Pr, UCH
+                               if(SiS_Pr->SiS_SetFlag & RPLLDIV2XO)  VCLKIndex = TVVCLKDIV2;
+                       else                                  VCLKIndex = TVVCLK;
+               }
+-              if(HwDeviceExtension->jChipType >= SIS_315H) {
+-                              VCLKIndex += 25;
+-              }
++              if(HwDeviceExtension->jChipType < SIS_315H) {
++                              VCLKIndex += TVCLKBASE_300;
++              } else {
++                      VCLKIndex += TVCLKBASE_315;
++              }
+         } else {                                              /* RAMDAC2 */
+               VCLKIndex = (UCHAR)SiS_GetReg2((USHORT)(SiS_Pr->SiS_P3ca+0x02));
+               VCLKIndex = ((VCLKIndex >> 2) & 0x03);
+@@ -8441,7 +8718,11 @@ SiS_GetVCLK2Ptr(SiS_Private *SiS_Pr, UCH
+                               VCLKIndex &= 0x3f;
+                               if( (HwDeviceExtension->jChipType == SIS_630) &&
+                                   (HwDeviceExtension->jChipRevision >= 0x30)) {
+-                                   if(VCLKIndex == 0x14) VCLKIndex = 0x2e;
++                                   /* This is certainly wrong: It replaces clock
++                                    * 108 by 47...
++                                    */
++                                   /* if(VCLKIndex == 0x14) VCLKIndex = 0x2e; */
++                                   if(VCLKIndex == 0x14) VCLKIndex = 0x34;
+                               }
+                       }
+               }
+@@ -8505,6 +8786,10 @@ SiS_GetVCLK2Ptr(SiS_Private *SiS_Pr, UCH
+               if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) ||
+                  (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel320x480))
+                       VCLKIndex = LVDSXlat1VCLK[VCLKIndex];
++              else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480   ||
++                      SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2 ||
++                      SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3)
++                      VCLKIndex = LVDSXlat4VCLK[VCLKIndex];
+               else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)
+                       VCLKIndex = LVDSXlatVCLK2[VCLKIndex];
+               else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600)
+@@ -8513,6 +8798,21 @@ SiS_GetVCLK2Ptr(SiS_Private *SiS_Pr, UCH
+                         VCLKIndex = LVDSXlatVCLK2[VCLKIndex];                 
+               else    VCLKIndex = LVDSXlatVCLK3[VCLKIndex];
++              if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) {
++                 /* Special Timing: Barco iQ Pro R300/400/... */
++                 VCLKIndex = 0x44;
++              }
++
++              if(SiS_Pr->SiS_CustomT == CUT_PANEL848) {
++                 if(HwDeviceExtension->jChipType < SIS_315H) {
++                    VCLKIndex = VCLK34_300;
++                    /* if(resinfo == SIS_RI_1360x768) VCLKIndex = ?; */
++                 } else {
++                    VCLKIndex = VCLK34_315;
++                    /* if(resinfo == SIS_RI_1360x768) VCLKIndex = ?; */
++                 }
++              }
++
+          } else {
+               VCLKIndex = (UCHAR)SiS_GetReg2((USHORT)(SiS_Pr->SiS_P3ca+0x02));
+@@ -8556,11 +8856,11 @@ SiS_GetVCLK2Ptr(SiS_Private *SiS_Pr, UCH
+ #ifdef TWDEBUG
+   xf86DrvMsg(0, X_INFO, "VCLKIndex %d (0x%x)\n", VCLKIndex, VCLKIndex);
+ #endif
+-  return (VCLKIndex);
++  return(VCLKIndex);
+ }
+-/* TW: Set 301 Palette address port registers */
+-/* TW: Checked against 650/301LV BIOS */
++/* Set 301 Palette address port registers */
++/* Checked against 650/301LV BIOS */
+ void
+ SiS_SetGroup5(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr,
+               UCHAR *ROMAddr, USHORT ModeNo, USHORT ModeIdIndex)
+@@ -8568,7 +8868,7 @@ SiS_SetGroup5(SiS_Private *SiS_Pr, PSIS_
+   if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)  return;
+-  if(SiS_Pr->SiS_ModeType == ModeVGA){
++  if(SiS_Pr->SiS_ModeType == ModeVGA) {
+      if(!(SiS_Pr->SiS_VBInfo & (SetInSlaveMode | LoadDACFlag))){
+         SiS_EnableCRT2(SiS_Pr);
+         SiS_LoadDAC(SiS_Pr,HwDeviceExtension,ROMAddr,ModeNo,ModeIdIndex);
+@@ -8581,17 +8881,22 @@ SiS_ModCRT1CRTC(SiS_Private *SiS_Pr, UCH
+                 USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
+ {
+   USHORT temp,tempah,i,modeflag,j;
+-  USHORT ResInfo,DisplayType;
++  USHORT ResIndex,DisplayType;
+   const SiS_LVDSCRT1DataStruct *LVDSCRT1Ptr=NULL;
+   if(ModeNo <= 0x13) {
+-      modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
++     modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+   } else {
+-      modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
++     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+   }
++  if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) ||
++     (SiS_Pr->SiS_CustomT == CUT_BARCO1024) ||
++     (SiS_Pr->SiS_CustomT == CUT_PANEL848))
++     return;
++
+   temp = SiS_GetLVDSCRT1Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+-                            &ResInfo,&DisplayType);
++                            &ResIndex,&DisplayType);
+   if(temp == 0) return;
+@@ -8639,47 +8944,53 @@ SiS_ModCRT1CRTC(SiS_Private *SiS_Pr, UCH
+     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);                        /*unlock cr0-7  */
+-  tempah = (LVDSCRT1Ptr+ResInfo)->CR[0];
++  tempah = (LVDSCRT1Ptr + ResIndex)->CR[0];
+   SiS_SetReg1(SiS_Pr->SiS_P3d4,0x00,tempah);
+   for(i=0x02,j=1;i<=0x05;i++,j++){
+-    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
++    tempah = (LVDSCRT1Ptr + ResIndex)->CR[j];
+     SiS_SetReg1(SiS_Pr->SiS_P3d4,i,tempah);
+   }
+   for(i=0x06,j=5;i<=0x07;i++,j++){
+-    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
++    tempah = (LVDSCRT1Ptr + ResIndex)->CR[j];
+     SiS_SetReg1(SiS_Pr->SiS_P3d4,i,tempah);
+   }
+   for(i=0x10,j=7;i<=0x11;i++,j++){
+-    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
++    tempah = (LVDSCRT1Ptr + ResIndex)->CR[j];
+     SiS_SetReg1(SiS_Pr->SiS_P3d4,i,tempah);
+   }
+   for(i=0x15,j=9;i<=0x16;i++,j++){
+-    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
++    tempah = (LVDSCRT1Ptr + ResIndex)->CR[j];
+     SiS_SetReg1(SiS_Pr->SiS_P3d4,i,tempah);
+   }
+   for(i=0x0A,j=11;i<=0x0C;i++,j++){
+-    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
++    tempah = (LVDSCRT1Ptr + ResIndex)->CR[j];
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,i,tempah);
+   }
+-  tempah = (LVDSCRT1Ptr+ResInfo)->CR[14];
++  tempah = (LVDSCRT1Ptr + ResIndex)->CR[14];
+   tempah &= 0xE0;
+-  SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0E,0x1f,tempah);     
++  SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0E,0x1f,tempah);
+-  tempah = (LVDSCRT1Ptr+ResInfo)->CR[14];
++  tempah = (LVDSCRT1Ptr + ResIndex)->CR[14];
+   tempah &= 0x01;
+   tempah <<= 5;
+   if(modeflag & DoubleScanMode)  tempah |= 0x080;
+   SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,~0x020,tempah);
+-  /* TW: 650/LVDS BIOS - doesn't make sense */
++  /* 650/LVDS BIOS - doesn't make sense */
+   if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+      if(modeflag & HalfDCLK)
+         SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f);
+@@ -8688,7 +8999,7 @@ SiS_ModCRT1CRTC(SiS_Private *SiS_Pr, UCH
+ BOOLEAN
+ SiS_GetLVDSCRT1Ptr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+-                 USHORT RefreshRateTableIndex,USHORT *ResInfo,
++                 USHORT RefreshRateTableIndex,USHORT *ResIndex,
+                  USHORT *DisplayType)
+  {
+   USHORT tempbx,modeflag=0;
+@@ -8757,19 +9068,33 @@ SiS_GetLVDSCRT1Ptr(SiS_Private *SiS_Pr, 
+            tempbx = 40;
+          if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx += 2;
+          if(modeflag & HalfDCLK) tempbx++;
++        } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3) {
++           tempbx = 54;
++         if(modeflag & HalfDCLK) tempbx++;
++      } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2) {
++           tempbx = 52;
++         if(modeflag & HalfDCLK) tempbx++;
++      } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) {
++           tempbx = 50;
++         if(modeflag & HalfDCLK) tempbx++;
+         }
++
+      }
+      if(SiS_Pr->SiS_LCDInfo & LCDPass11) {
+         tempbx = 12;
+       if(modeflag & HalfDCLK) tempbx++;
+      }
+   }
+-  if(SiS_Pr->SiS_IF_DEF_FSTN){
++
++#if 0
++  if(SiS_Pr->SiS_IF_DEF_FSTN) {
+      if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel320x480){
+         tempbx = 22;
+      }
+   }
+-  *ResInfo = CRT2CRTC & 0x3F;
++#endif
++
++  *ResIndex = CRT2CRTC & 0x3F;
+   *DisplayType = tempbx;
+   return 1;
+ }
+@@ -8778,54 +9103,54 @@ void
+ SiS_SetCRT2ECLK(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT ModeNo,USHORT ModeIdIndex,
+            USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
+ {
+-  USHORT tempah,tempal,pushax;
+-  USHORT vclkindex=0;
+-    
++  USHORT clkbase, vclkindex=0;
++  UCHAR  sr2b, sr2c;
++
+   if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) || (SiS_Pr->SiS_IF_DEF_TRUMPION == 1)) {
+       SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2);
+-        tempal = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
+-      tempal &= 0x3F;
+-      if(tempal == 2) RefreshRateTableIndex--;
++        if((SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK & 0x3f) == 2) {
++         RefreshRateTableIndex--;
++      }
+       vclkindex = SiS_GetVCLK2Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
+-                               RefreshRateTableIndex,HwDeviceExtension);
++                                    RefreshRateTableIndex,HwDeviceExtension);
+       SiS_Pr->SiS_SetFlag |= ProgrammingCRT2;
+   } else {
+         vclkindex = SiS_GetVCLK2Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
+-                               RefreshRateTableIndex,HwDeviceExtension);
++                                    RefreshRateTableIndex,HwDeviceExtension);
+   }
+-  
+-  tempal = 0x02B;
++
++  sr2b = SiS_Pr->SiS_VCLKData[vclkindex].SR2B;
++  sr2c = SiS_Pr->SiS_VCLKData[vclkindex].SR2C;
++
++  if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) || (SiS_Pr->SiS_CustomT == CUT_BARCO1024)) {
++     if((ROMAddr) && SiS_Pr->SiS_UseROM) {
++      if(ROMAddr[0x220] & 0x01) {
++           sr2b = ROMAddr[0x227];
++         sr2c = ROMAddr[0x228];
++      }
++     }
++  }
++
++  clkbase = 0x02B;
+   if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+      if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+-      tempal += 3;
++      clkbase += 3;
+      }
+   }
++
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x05,0x86);
+-  pushax = tempal;
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x31,0x20);
+-  tempah = SiS_Pr->SiS_VCLKData[vclkindex].SR2B;
+-  SiS_SetReg1(SiS_Pr->SiS_P3c4,tempal,tempah);
+-  tempal++;
+-  tempah = SiS_Pr->SiS_VCLKData[vclkindex].SR2C;
+-  SiS_SetReg1(SiS_Pr->SiS_P3c4,tempal,tempah);
++  SiS_SetReg1(SiS_Pr->SiS_P3c4,clkbase,sr2b);
++  SiS_SetReg1(SiS_Pr->SiS_P3c4,clkbase+1,sr2c);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x31,0x10);
+-  tempal = pushax;
+-  tempah = SiS_Pr->SiS_VCLKData[vclkindex].SR2B;
+-  SiS_SetReg1(SiS_Pr->SiS_P3c4,tempal,tempah);
+-  tempal++;
+-  tempah = SiS_Pr->SiS_VCLKData[vclkindex].SR2C;
+-  SiS_SetReg1(SiS_Pr->SiS_P3c4,tempal,tempah);
++  SiS_SetReg1(SiS_Pr->SiS_P3c4,clkbase,sr2b);
++  SiS_SetReg1(SiS_Pr->SiS_P3c4,clkbase+1,sr2c);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x31,0x00);
+-  tempal = pushax;
+-  tempah = SiS_Pr->SiS_VCLKData[vclkindex].SR2B;
+-  SiS_SetReg1(SiS_Pr->SiS_P3c4,tempal,tempah);
+-  tempal++;
+-  tempah = SiS_Pr->SiS_VCLKData[vclkindex].SR2C;
+-  SiS_SetReg1(SiS_Pr->SiS_P3c4,tempal,tempah);
+-  return;
++  SiS_SetReg1(SiS_Pr->SiS_P3c4,clkbase,sr2b);
++  SiS_SetReg1(SiS_Pr->SiS_P3c4,clkbase+1,sr2c);
+ }
+-#if 0  /* TW: Not used */
++#if 0  /* Not used */
+ void
+ SiS_SetDefCRT2ExtRegs(SiS_Private *SiS_Pr, USHORT BaseAddr)
+ {
+@@ -8844,7 +9169,7 @@ SiS_SetDefCRT2ExtRegs(SiS_Private *SiS_P
+ }
+ #endif
+-/* TW: Start of Chrontel 70xx functions ---------------------- */
++/* Start of Chrontel 70xx functions ---------------------- */
+ /* Set-up the Chrontel Registers */
+ void
+@@ -8890,44 +9215,44 @@ SiS_SetCHTVReg(SiS_Private *SiS_Pr, UCHA
+   if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) {
+ #ifdef SIS300
+-  
+-     /* Chrontel 7005 - I assume that it does not come with a 310/325 series chip */
+-     /* TW: We don't support modes >800x600 */
++     /* Chrontel 7005 - I assume that it does not come with a 315 series chip */
++
++     /* We don't support modes >800x600 */
+      if (resindex > 5) return;
+      if(SiS_Pr->SiS_VBInfo & SetPALTV) {
+-      SiS_SetCH700x(SiS_Pr,0x4304);   /* TW: 0x40=76uA (PAL); 0x03=15bit non-multi RGB*/
+-      SiS_SetCH700x(SiS_Pr,0x6909);   /* TW: Black level for PAL (105)*/
++      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);   /* TW: upper nibble=71uA (NTSC), 0x03=15bit non-multi RGB*/
+-      SiS_SetCH700x(SiS_Pr,0x7109);   /* TW: Black level for NTSC (113)*/
++      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;  /* TW: Mode register */
++     tempbx=((temp&0x00FF)<<8)|0x00;  /* Mode register */
+      SiS_SetCH700x(SiS_Pr,tempbx);
+      temp = CHTVRegData[resindex].Reg[1];
+-     tempbx=((temp&0x00FF)<<8)|0x07;  /* TW: Start active video register */
++     tempbx=((temp&0x00FF)<<8)|0x07;  /* Start active video register */
+      SiS_SetCH700x(SiS_Pr,tempbx);
+      temp = CHTVRegData[resindex].Reg[2];
+-     tempbx=((temp&0x00FF)<<8)|0x08;  /* TW: Position overflow register */
++     tempbx=((temp&0x00FF)<<8)|0x08;  /* Position overflow register */
+      SiS_SetCH700x(SiS_Pr,tempbx);
+      temp = CHTVRegData[resindex].Reg[3];
+-     tempbx=((temp&0x00FF)<<8)|0x0A;  /* TW: Horiz Position register */
++     tempbx=((temp&0x00FF)<<8)|0x0A;  /* Horiz Position register */
+      SiS_SetCH700x(SiS_Pr,tempbx);
+      temp = CHTVRegData[resindex].Reg[4];
+-     tempbx=((temp&0x00FF)<<8)|0x0B;  /* TW: Vertical Position register */
++     tempbx=((temp&0x00FF)<<8)|0x0B;  /* Vertical Position register */
+      SiS_SetCH700x(SiS_Pr,tempbx);
+-     /* TW: Set minimum flicker filter for Luma channel (SR1-0=00),
++     /* 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);
+-     /* TW: 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)
+@@ -8936,22 +9261,24 @@ SiS_SetCHTVReg(SiS_Private *SiS_Pr, UCHA
+      */
+      SiS_SetCH700x(SiS_Pr,0xb103);       /* old: 3103 */
+-     /* TW: 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?)
+       */
+-     /* SiS_SetCH70xx(SiS_Pr,0x003D); */
++#ifndef SIS_CP
++     SiS_SetCH70xx(SiS_Pr,0x003D);
++#endif
+-     /* TW: Register 0x10 only contains 1 writable bit (S0) for sensing,
++     /* Register 0x10 only contains 1 writable bit (S0) for sensing,
+             all other bits a read-only. Macrovision?
+       */
+      SiS_SetCH70xxANDOR(SiS_Pr,0x0010,0x1F);
+-     /* TW: Register 0x11 only contains 3 writable bits (S0-S2) for
++     /* 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);
+-     /* TW: Clear DSEN
++     /* Clear DSEN
+       */
+      SiS_SetCH70xxANDOR(SiS_Pr,0x001C,0xEF);
+@@ -8994,7 +9321,7 @@ SiS_SetCHTVReg(SiS_Private *SiS_Pr, UCHA
+          }
+        }
+      } else {                         /* ---- PAL ---- */
+-           /* TW: We don't play around with FSCI in PAL mode */
++           /* 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 */
+@@ -9012,7 +9339,7 @@ SiS_SetCHTVReg(SiS_Private *SiS_Pr, UCHA
+ #ifdef SIS315H
+-     /* TW: We don't support modes >1024x768 */
++     /* We don't support modes >1024x768 */
+      if (resindex > 6) return;
+      temp = CHTVRegData[resindex].Reg[0];
+@@ -9082,26 +9409,29 @@ SiS_SetCHTVReg(SiS_Private *SiS_Pr, UCHA
+ #endif        /* 315 */
+   }
++
++#ifdef SIS_CP
++  SIS_CP_INIT301_CP3
++#endif
++
+ }
+-/* TW: Chrontel 701x functions ================================= */
++/* Chrontel 701x functions ================================= */
+ void
+-SiS_Chrontel701xBLOn(SiS_Private *SiS_Pr)
++SiS_Chrontel701xBLOn(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+ {
+-#ifndef NEWCH701x
+   USHORT temp;
+-#endif  
+-  /* TW: Enable Chrontel 7019 LCD panel backlight */
++  /* Enable Chrontel 7019 LCD panel backlight */
+   if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+-#ifdef NEWCH701x
++     if(HwDeviceExtension->jChipType == SIS_740) {
+         SiS_SetCH701x(SiS_Pr,0x6566);
+-#else  
++     } else {
+         temp = SiS_GetCH701x(SiS_Pr,0x66);
+         temp |= 0x20;
+       SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x66);
+-#endif        
++     }
+   }
+ }
+@@ -9110,7 +9440,7 @@ SiS_Chrontel701xBLOff(SiS_Private *SiS_P
+ {
+   USHORT temp;
+-  /* TW: Disable Chrontel 7019 LCD panel backlight */
++  /* Disable Chrontel 7019 LCD panel backlight */
+   if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+         temp = SiS_GetCH701x(SiS_Pr,0x66);
+         temp &= 0xDF;
+@@ -9118,47 +9448,54 @@ SiS_Chrontel701xBLOff(SiS_Private *SiS_P
+   }
+ }
+-#ifdef SIS315H  /* -------- 310/325 series only --------- */
++#ifdef SIS315H  /* ----------- 315 series only ---------- */
+ void
+ SiS_SetCH701xForLCD(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr)
+ {
+-#ifdef NEWCH701x  
+-  UCHAR regtable[]  = { 0x1c, 0x5f, 0x64, 0x6f, 0x70, 0x71,
+-                        0x72, 0x73, 0x74, 0x76, 0x78, 0x7d, 0x66 };
+-  UCHAR table1024[] = { 0x60, 0x02, 0x00, 0x07, 0x40, 0xed,
+-                        0xa3, 0xc8, 0xc7, 0xac, 0xe0, 0x02, 0x44 }; 
+-  UCHAR table1280[] = { 0x60, 0x03, 0x11, 0x00, 0x40, 0xe3,
+-                      0xad, 0xdb, 0xf6, 0xac, 0xe0, 0x02, 0x44 };                     
+-  UCHAR table1400[] = { 0x60, 0x03, 0x11, 0x00, 0x40, 0xe3,         
+-                        0xad, 0xdb, 0xf6, 0xac, 0xe0, 0x02, 0x44 }; 
+-  UCHAR table1600[] = { 0x60, 0x04, 0x11, 0x00, 0x40, 0xe3,
+-                      0xad, 0xde, 0xf6, 0xac, 0x60, 0x1a, 0x44 };
+-#else
+-  UCHAR regtable[]  = { 0x1c, 0x5f, 0x64, 0x6f, 0x70, 0x71,
+-                        0x72, 0x73, 0x74, 0x76, 0x78, 0x7d };
+-  UCHAR table1024[] = { 0x60, 0x02, 0x00, 0x07, 0x40, 0xed,
+-                        0xa3, 0xc8, 0xc7, 0xac, 0x60, 0x02 }; 
+-  UCHAR table1280[] = { 0x60, 0x03, 0x11, 0x00, 0x40, 0xe3,
+-                      0xad, 0xdb, 0xf6, 0xac, 0xe0, 0x02 };                   
+-  UCHAR table1400[] = { 0x60, 0x03, 0x11, 0x00, 0x40, 0xef,   
+-                        0xad, 0xdb, 0xf6, 0xac, 0x60, 0x02 }; 
+-  UCHAR table1600[] = { 0x60, 0x04, 0x11, 0x00, 0x40, 0xe3,
+-                      0xad, 0xde, 0xf6, 0xac, 0x60, 0x1a };
+-#endif                        
++  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;
+   int i;
+-  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+-     tableptr = table1024;
+-  } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
+-     tableptr = table1280;
+-  } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+-     tableptr = table1400;
+-  } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) {
+-     tableptr = table1600;
+-  } else return;
++  if(HwDeviceExtension->jChipType == SIS_740) {
++     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
++        tableptr = table1024_740;
++     } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
++        tableptr = table1280_740;
++     } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
++        tableptr = table1400_740;
++     } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) {
++        tableptr = table1600_740;
++     } else return;
++  } else {
++     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
++        tableptr = table1024_650;
++     } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
++        tableptr = table1280_650;
++     } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
++        tableptr = table1400_650;
++     } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) {
++        tableptr = table1600_650;
++     } else return;
++  }
+   tempbh = SiS_GetCH701x(SiS_Pr,0x74);
+   if((tempbh == 0xf6) || (tempbh == 0xc7)) {
+@@ -9172,54 +9509,64 @@ SiS_SetCH701xForLCD(SiS_Private *SiS_Pr,
+         if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) return;
+      }
+   }
+-#ifdef NEWCH701x     /* New from 740/LVDS: */    
+-  for(i=0; i<0x0d; i++) {     
+-#else
+-  for(i=0; i<0x0c; i++) {
+-#endif  
++
++  if(HwDeviceExtension->jChipType == SIS_740) {
++     tempbh = 0x0d;
++  } else {
++     tempbh = 0x0c;
++  }
++  for(i = 0; i < tempbh; i++) {
+      SiS_SetCH701x(SiS_Pr,(tableptr[i] << 8) | regtable[i]);
+   }
+-  SiS_ChrontelPowerSequencing(SiS_Pr);
++  SiS_ChrontelPowerSequencing(SiS_Pr,HwDeviceExtension);
+   tempbh = SiS_GetCH701x(SiS_Pr,0x1e);
+   tempbh |= 0xc0;
+   SiS_SetCH701x(SiS_Pr,(tempbh << 8) | 0x1e);
+-  
+-#ifdef NEWCH701x     /* 740/LVDS: */
+-  tempbh = SiS_GetCH701x(SiS_Pr,0x1c);
+-  tempbh &= 0xfb;
+-  SiS_SetCH701x(SiS_Pr,(tempbh << 8) | 0x1c);
+-  SiS_SetReg1(SiS_Pr->SiS_Part1Port, 0x2d, 0x03);
+-  tempbh = SiS_GetCH701x(SiS_Pr,0x64);
+-  tempbh |= 0x40;
+-  SiS_SetCH701x(SiS_Pr,(tempbh << 8) | 0x64);
+-  tempbh = SiS_GetCH701x(SiS_Pr,0x03);
+-  tempbh &= 0x3f;
+-  SiS_SetCH701x(SiS_Pr,(tempbh << 8) | 0x03);
+-#endif  /* End 740/LVDS */
++
++  if(HwDeviceExtension->jChipType == SIS_740) {
++     tempbh = SiS_GetCH701x(SiS_Pr,0x1c);
++     tempbh &= 0xfb;
++     SiS_SetCH701x(SiS_Pr,(tempbh << 8) | 0x1c);
++     SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2d,0x03);
++     tempbh = SiS_GetCH701x(SiS_Pr,0x64);
++     tempbh |= 0x40;
++     SiS_SetCH701x(SiS_Pr,(tempbh << 8) | 0x64);
++     tempbh = SiS_GetCH701x(SiS_Pr,0x03);
++     tempbh &= 0x3f;
++     SiS_SetCH701x(SiS_Pr,(tempbh << 8) | 0x03);
++  }
+ }
+ void
+-SiS_ChrontelPowerSequencing(SiS_Private *SiS_Pr)
+-{
+-  UCHAR regtable[]  = { 0x67, 0x68, 0x69, 0x6a, 0x6b };
+-#ifdef NEWCH701x  
+-  UCHAR table1024[] = { 0x01, 0x02, 0x01, 0x01, 0x01 };
+-  UCHAR table1400[] = { 0x01, 0x6e, 0x01, 0x01, 0x01 };
+-#else
+-  UCHAR table1024[] = { 0x01, 0x02, 0x01, 0x01, 0x02 };
+-  UCHAR table1400[] = { 0x01, 0x02, 0x01, 0x01, 0x02 };
+-#endif  
++SiS_ChrontelPowerSequencing(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
++{
++  UCHAR regtable[]      = { 0x67, 0x68, 0x69, 0x6a, 0x6b };
++  UCHAR table1024_740[] = { 0x01, 0x02, 0x01, 0x01, 0x01 };
++  UCHAR table1400_740[] = { 0x01, 0x6e, 0x01, 0x01, 0x01 };
++  UCHAR table1024_650[] = { 0x01, 0x02, 0x01, 0x01, 0x02 };
++  UCHAR table1400_650[] = { 0x01, 0x02, 0x01, 0x01, 0x02 };
+   UCHAR *tableptr = NULL;
+   int i;
+   /* Set up Power up/down timing */
+-  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+-     tableptr = table1024;
+-  } else if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) ||
+-            (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) ||
+-          (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200)) {
+-     tableptr = table1400;
+-  } else return;
++
++  if(HwDeviceExtension->jChipType == SIS_740) {
++     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
++        tableptr = table1024_740;
++     } else if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) ||
++               (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) ||
++             (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200)) {
++        tableptr = table1400_740;
++     } else return;
++  } else {
++     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
++        tableptr = table1024_650;
++     } else if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) ||
++               (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) ||
++             (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200)) {
++        tableptr = table1400_650;
++     } else return;
++  }
+   
+   for(i=0; i<5; i++) {
+      SiS_SetCH701x(SiS_Pr,(tableptr[i] << 8) | regtable[i]);
+@@ -9232,66 +9579,72 @@ SiS_Chrontel701xOn(SiS_Private *SiS_Pr, 
+   USHORT temp;
+   if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+-#ifdef NEWCH701x
+-     temp = SiS_GetCH701x(SiS_Pr,0x1c);
+-     temp |= 0x04;
+-     SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x1c);
+-#endif 
++     if(HwDeviceExtension->jChipType == SIS_740) {
++        temp = SiS_GetCH701x(SiS_Pr,0x1c);
++        temp |= 0x04;
++        SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x1c);
++     }
+      if(SiS_IsYPbPr(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+         temp = SiS_GetCH701x(SiS_Pr,0x01);
+       temp &= 0x3f;
+-      temp |= 0x80;   /* TW: Enable YPrPb (HDTV) */
++      temp |= 0x80;   /* Enable YPrPb (HDTV) */
+       SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x01);
+      }
+      if(SiS_IsChScart(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+         temp = SiS_GetCH701x(SiS_Pr,0x01);
+       temp &= 0x3f;
+-      temp |= 0xc0;   /* TW: Enable SCART + CVBS */
++      temp |= 0xc0;   /* Enable SCART + CVBS */
+       SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x01);
+      }
+-#ifdef NEWCH701x
+-     SiS_ChrontelDoSomething5(SiS_Pr);
+-     SiS_SetCH701x(SiS_Pr,0x2049);                    /* TW: Enable TV path */
+-#else      
+-     SiS_SetCH701x(SiS_Pr,0x2049);                    /* TW: Enable TV path */
+-     temp = SiS_GetCH701x(SiS_Pr,0x49);
+-     if(SiS_IsYPbPr(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+-        temp = SiS_GetCH701x(SiS_Pr,0x73);
+-      temp |= 0x60;
+-      SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x73);
++     if(HwDeviceExtension->jChipType == SIS_740) {
++        SiS_ChrontelDoSomething5(SiS_Pr);
++        SiS_SetCH701x(SiS_Pr,0x2049);                         /* Enable TV path */
++     } else {
++        SiS_SetCH701x(SiS_Pr,0x2049);                         /* Enable TV path */
++        temp = SiS_GetCH701x(SiS_Pr,0x49);
++        if(SiS_IsYPbPr(SiS_Pr,HwDeviceExtension, BaseAddr)) {
++           temp = SiS_GetCH701x(SiS_Pr,0x73);
++         temp |= 0x60;
++         SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x73);
++        }
++        temp = SiS_GetCH701x(SiS_Pr,0x47);
++        temp &= 0x7f;
++        SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x47);
++        SiS_LongDelay(SiS_Pr,2);
++        temp = SiS_GetCH701x(SiS_Pr,0x47);
++        temp |= 0x80;
++        SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x47);
+      }
+-     temp = SiS_GetCH701x(SiS_Pr,0x47);
+-     temp &= 0x7f;
+-     SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x47);
+-     SiS_LongDelay(SiS_Pr,2);
+-     temp = SiS_GetCH701x(SiS_Pr,0x47);
+-     temp |= 0x80;
+-     SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x47);
+-#endif     
+   }
+ }
+ void
+-SiS_Chrontel701xOff(SiS_Private *SiS_Pr)
++SiS_Chrontel701xOff(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+ {
+   USHORT temp;
++  /* Complete power down of LVDS */
+   if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
++     if(HwDeviceExtension->jChipType == SIS_740) {
++        SiS_LongDelay(SiS_Pr,1);
++      SiS_GenericDelay(SiS_Pr,0x16ff);
++      SiS_SetCH701x(SiS_Pr,0xac76);
++      SiS_SetCH701x(SiS_Pr,0x0066);
++     } else {
+         SiS_LongDelay(SiS_Pr,2);
+-      /* TW: Complete power down of LVDS */
+       temp = SiS_GetCH701x(SiS_Pr,0x76);
+       temp &= 0xfc;
+       SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x76);
+       SiS_SetCH701x(SiS_Pr,0x0066);
++     }
+   }
+ }
+-#ifdef NEWCH701x
+ void
+ SiS_ChrontelDoSomething5(SiS_Private *SiS_Pr)
+ {
+      unsigned char temp, temp1;
+-     
++
+      temp1 = SiS_GetCH701x(SiS_Pr,0x49);
+      SiS_SetCH701x(SiS_Pr,0x3e49);
+      temp = SiS_GetCH701x(SiS_Pr,0x47);
+@@ -9303,130 +9656,134 @@ SiS_ChrontelDoSomething5(SiS_Private *Si
+      SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x47);
+      SiS_SetCH701x(SiS_Pr,(temp1 << 8) | 0x49);
+ }
+-#endif
+ void
+ SiS_ChrontelResetDB(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr)
+ {
+-#ifdef NEWCH701x
+      USHORT temp;
+-     
+-     /* 740/LVDS: */
+-     temp = SiS_GetCH701x(SiS_Pr,0x4a);
+-     temp &= 0x01;
+-     if(!(temp)) {
+-     
+-        if(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+-         temp = SiS_GetCH701x(SiS_Pr,0x49);
+-         SiS_SetCH701x(SiS_Pr,0x3e49);
+-      }
+-      /* TW: Reset Chrontel 7019 datapath */
++
++     if(HwDeviceExtension->jChipType == SIS_740) {
++        temp = SiS_GetCH701x(SiS_Pr,0x4a);
++        temp &= 0x01;
++        if(!(temp)) {
++
++           if(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr)) {
++            temp = SiS_GetCH701x(SiS_Pr,0x49);
++            SiS_SetCH701x(SiS_Pr,0x3e49);
++         }
++         /* Reset Chrontel 7019 datapath */
++           SiS_SetCH701x(SiS_Pr,0x1048);
++           SiS_LongDelay(SiS_Pr,1);
++           SiS_SetCH701x(SiS_Pr,0x1848);
++
++         if(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr)) {
++            SiS_ChrontelDoSomething5(SiS_Pr);
++            SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x49);
++         }
++
++        } else {
++
++           temp = SiS_GetCH701x(SiS_Pr,0x5c);
++         temp &= 0xef;
++         SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x5c);
++         temp = SiS_GetCH701x(SiS_Pr,0x5c);
++         temp |= 0x10;
++         SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x5c);
++         temp = SiS_GetCH701x(SiS_Pr,0x5c);
++         temp &= 0xef;
++         SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x5c);
++         temp = SiS_GetCH701x(SiS_Pr,0x61);
++         if(!temp) {
++            SiS_SetCH701xForLCD(SiS_Pr,HwDeviceExtension,BaseAddr);
++         }
++        }
++     } else { /* 650 */
++        /* Reset Chrontel 7019 datapath */
+         SiS_SetCH701x(SiS_Pr,0x1048);
+         SiS_LongDelay(SiS_Pr,1);
+         SiS_SetCH701x(SiS_Pr,0x1848);
+-      
+-      if(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+-         SiS_ChrontelDoSomething5(SiS_Pr);
+-         SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x49);
+-      }    
+-     } else {
+-     
+-        temp = SiS_GetCH701x(SiS_Pr,0x5c);
+-      temp &= 0xef;
+-      SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x5c);
+-      temp = SiS_GetCH701x(SiS_Pr,0x5c);
+-      temp |= 0x10;
+-      SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x5c);
+-      temp = SiS_GetCH701x(SiS_Pr,0x5c);
+-      temp &= 0xef;
+-      SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x5c);
+-      temp = SiS_GetCH701x(SiS_Pr,0x61);
+-      if(!temp) {
+-         SiS_SetCH701xForLCD(SiS_Pr,HwDeviceExtension,BaseAddr);
+-      }
+-     }
+-#else /* pre 740/LVDS code */     
+-     /* TW: Reset Chrontel 7019 datapath */
+-     SiS_SetCH701x(SiS_Pr,0x1048);
+-     SiS_LongDelay(SiS_Pr,1);
+-     SiS_SetCH701x(SiS_Pr,0x1848);
+-#endif     
++     }
+ }
+ void
+ SiS_ChrontelDoSomething4(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr)
+ {
+-#ifdef NEWCH701x
+-     if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+-        SiS_ChrontelDoSomething5(SiS_Pr);
+-     }
+-#else
+      USHORT temp;
+-     SiS_SetCH701x(SiS_Pr,0xaf76);  /* 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);
+-      temp = SiS_GetCH701x(SiS_Pr,0x47);
+-      temp |= 0x80;
+-      SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x47);  /* disable VSYNC */
++     if(HwDeviceExtension->jChipType == SIS_740) {
++
++        if(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr)) {
++           SiS_ChrontelDoSomething5(SiS_Pr);
++        }
++
++     } else {
++
++        SiS_SetCH701x(SiS_Pr,0xaf76);  /* 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);
++         temp = SiS_GetCH701x(SiS_Pr,0x47);
++         temp |= 0x80;
++         SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x47);  /* disable VSYNC */
++        }
++
+      }
+-#endif     
+ }
+ void
+ SiS_ChrontelDoSomething3(SiS_Private *SiS_Pr, USHORT ModeNo, PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                          USHORT BaseAddr)
+ {
+-#ifdef NEWCH701x
+-     USHORT temp;
+-     
+-     temp = SiS_GetCH701x(SiS_Pr,0x61);
+-     if(temp < 1) {
+-          temp++;
+-        SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x61);
+-     }
+-     SiS_SetCH701x(SiS_Pr,0x4566);
+-     SiS_SetCH701x(SiS_Pr,0xaf76);
+-     SiS_LongDelay(SiS_Pr,1);
+-     SiS_GenericDelay(SiS_Pr,0x16ff);
+-
+-#else
+      USHORT temp,temp1;
+-     
+-     temp1 = 0;
+-     temp = SiS_GetCH701x(SiS_Pr,0x61);
+-     if(temp < 2) {
+-          temp++;
+-        SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x61);
+-        temp1 = 1;
+-     }
+-     SiS_SetCH701x(SiS_Pr,0xac76);
+-     temp = SiS_GetCH701x(SiS_Pr,0x66);
+-     temp |= 0x5f;
+-     SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x66);
+-     if(ModeNo > 0x13) {
+-         if(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+-          SiS_GenericDelay(SiS_Pr,0x3ff);
+-       } else {
+-          SiS_GenericDelay(SiS_Pr,0x2ff);
+-       }
+-     } else {
+-         if(!temp1)
+-          SiS_GenericDelay(SiS_Pr,0x2ff);
++
++     if(HwDeviceExtension->jChipType == SIS_740) {
++
++        temp = SiS_GetCH701x(SiS_Pr,0x61);
++        if(temp < 1) {
++           temp++;
++         SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x61);
++        }
++        SiS_SetCH701x(SiS_Pr,0x4566);
++        SiS_SetCH701x(SiS_Pr,0xaf76);
++        SiS_LongDelay(SiS_Pr,1);
++        SiS_GenericDelay(SiS_Pr,0x16ff);
++
++     } else {  /* 650 */
++
++        temp1 = 0;
++        temp = SiS_GetCH701x(SiS_Pr,0x61);
++        if(temp < 2) {
++           temp++;
++         SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x61);
++         temp1 = 1;
++        }
++        SiS_SetCH701x(SiS_Pr,0xac76);
++        temp = SiS_GetCH701x(SiS_Pr,0x66);
++        temp |= 0x5f;
++        SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x66);
++        if(ModeNo > 0x13) {
++           if(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr)) {
++            SiS_GenericDelay(SiS_Pr,0x3ff);
++         } else {
++            SiS_GenericDelay(SiS_Pr,0x2ff);
++         }
++        } else {
++           if(!temp1)
++            SiS_GenericDelay(SiS_Pr,0x2ff);
++        }
++        temp = SiS_GetCH701x(SiS_Pr,0x76);
++        temp |= 0x03;
++        SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x76);
++        temp = SiS_GetCH701x(SiS_Pr,0x66);
++        temp &= 0x7f;
++        SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x66);
++        SiS_LongDelay(SiS_Pr,1);
++
+      }
+-     temp = SiS_GetCH701x(SiS_Pr,0x76);
+-     temp |= 0x03;
+-     SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x76);
+-     temp = SiS_GetCH701x(SiS_Pr,0x66);
+-     temp &= 0x7f;
+-     SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x66);
+-     SiS_LongDelay(SiS_Pr,1);
+-#endif     
+ }
+ void
+@@ -9443,9 +9800,9 @@ SiS_ChrontelDoSomething2(SiS_Private *Si
+        temp &= 0x04;
+        if(temp == 0x04) break;
+        
+-#ifdef NEWCH701x
+-       SiS_SetCH701x(SiS_Pr,0xac76);    /* 740/LVDS */
+-#endif       
++       if(HwDeviceExtension->jChipType == SIS_740) {
++          SiS_SetCH701x(SiS_Pr,0xac76);
++       }
+        SiS_SetCH701xForLCD(SiS_Pr,HwDeviceExtension,BaseAddr);
+@@ -9463,11 +9820,11 @@ SiS_ChrontelDoSomething2(SiS_Private *Si
+        temp = SiS_GetCH701x(SiS_Pr,0x76);
+        temp |= 0x04;
+        SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x76);
+-#ifdef NEWCH701x
+-       SiS_SetCH701x(SiS_Pr,0xe078);
+-#else       
+-       SiS_SetCH701x(SiS_Pr,0x6078);
+-#endif       
++       if(HwDeviceExtension->jChipType == SIS_740) {
++          SiS_SetCH701x(SiS_Pr,0xe078);
++       } else {
++          SiS_SetCH701x(SiS_Pr,0x6078);
++       }
+        SiS_LongDelay(SiS_Pr,2);
+     } while(0);
+@@ -9485,51 +9842,52 @@ SiS_ChrontelDoSomething1(SiS_Private *Si
+      temp &= 0xbf;    /* Set datapath 2 to LVDS */
+      SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x03);
+      
+-#ifdef NEWCH701x   /* 740/LVDS: */
++     if(HwDeviceExtension->jChipType == SIS_740) {
++
++        temp = SiS_GetCH701x(SiS_Pr,0x1c);
++        temp &= 0xfb;
++        SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x1c);
++
++        SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2d,0x03);
++
++        temp = SiS_GetCH701x(SiS_Pr,0x64);
++        temp |= 0x40;
++        SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x64);
++
++        temp = SiS_GetCH701x(SiS_Pr,0x03);
++        temp &= 0x3f;
++        SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x03);
++
++        temp = SiS_GetCH701x(SiS_Pr,0x66);
++        if(temp != 0x45) {
++           SiS_ChrontelResetDB(SiS_Pr,HwDeviceExtension,BaseAddr);
++           SiS_ChrontelDoSomething2(SiS_Pr,HwDeviceExtension,BaseAddr);
++         temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x34);
++           SiS_ChrontelDoSomething3(SiS_Pr,temp,HwDeviceExtension,BaseAddr);
++        }
++
++     } else { /* 650 */
+-     temp = SiS_GetCH701x(SiS_Pr,0x1c);
+-     temp &= 0xfb;
+-     SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x1c);
+-     
+-     SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2d,0x03);
+-     
+-     temp = SiS_GetCH701x(SiS_Pr,0x64);
+-     temp |= 0x40;
+-     SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x64);
+-     
+-     temp = SiS_GetCH701x(SiS_Pr,0x03);
+-     temp &= 0x3f;    
+-     SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x03);
+-     
+-     temp = SiS_GetCH701x(SiS_Pr,0x66);
+-     if(temp != 0x45) {
+         SiS_ChrontelResetDB(SiS_Pr,HwDeviceExtension,BaseAddr);
+-        SiS_ChrontelDoSomething2(SiS_Pr,HwDeviceExtension,BaseAddr);
+-      temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x34);
+-        SiS_ChrontelDoSomething3(SiS_Pr,temp,HwDeviceExtension,BaseAddr);
+-     }     
+-#else  /* pre-740/LVDS: */     
++        SiS_ChrontelDoSomething2(SiS_Pr,HwDeviceExtension,BaseAddr);
+-     SiS_ChrontelResetDB(SiS_Pr);
++        temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x34);
++        SiS_ChrontelDoSomething3(SiS_Pr,temp,HwDeviceExtension,BaseAddr);
+-     SiS_ChrontelDoSomething2(SiS_Pr,HwDeviceExtension,BaseAddr);
++        SiS_SetCH701x(SiS_Pr,0xaf76);
+-     temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x34);
+-     SiS_ChrontelDoSomething3(SiS_Pr,temp,HwDeviceExtension,BaseAddr);
++     }
+-     SiS_SetCH701x(SiS_Pr,0xaf76);
+-     
+-#endif  /* End of pre-740/LVDS */
+ }
+-#endif  /* 310/325 series --------------------------------- */
++#endif  /* 315 series ------------------------------------ */
+-/* TW: End of Chrontel 701x functions ==================================== */
++/* End of Chrontel 701x functions ==================================== */
+-/* TW: Generic Read/write routines for Chrontel ========================== */
++/* Generic Read/write routines for Chrontel ========================== */
+-/* TW: The Chrontel is connected to the 630/730 via
++/* The Chrontel is connected to the 630/730 via
+  * the 630/730's DDC/I2C port.
+  *
+  * On 630(S)T chipset, the index changed from 0x11 to 0x0a,
+@@ -9539,13 +9897,13 @@ SiS_ChrontelDoSomething1(SiS_Private *Si
+ void
+ SiS_SetCH70xx(SiS_Private *SiS_Pr, USHORT tempbx)
+ {
+-   if (SiS_Pr->SiS_IF_DEF_CH70xx == 1)
++   if(SiS_Pr->SiS_IF_DEF_CH70xx == 1)
+       SiS_SetCH700x(SiS_Pr,tempbx);
+    else
+       SiS_SetCH701x(SiS_Pr,tempbx);
+ }
+-/* TW: Write to Chrontel 700x */
++/* Write to Chrontel 700x */
+ /* Parameter is [Data (S15-S8) | Register no (S7-S0)] */
+ void
+ SiS_SetCH700x(SiS_Private *SiS_Pr, USHORT tempbx)
+@@ -9553,100 +9911,100 @@ SiS_SetCH700x(SiS_Private *SiS_Pr, USHOR
+   USHORT tempah,temp,i;
+   if(!(SiS_Pr->SiS_ChrontelInit)) {
+-     SiS_Pr->SiS_DDC_Index = 0x11;               /* TW: Bit 0 = SC;  Bit 1 = SD */
++     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_DataShift = 0x00;
+-     SiS_Pr->SiS_DDC_DeviceAddr = 0xEA;          /* TW: DAB (Device Address Byte) */
++     SiS_Pr->SiS_DDC_DeviceAddr = 0xEA;          /* DAB (Device Address Byte) */
+   }
+-  for(i=0;i<10;i++) { /* TW: Do only 10 attempts to write */
++  for(i=0;i<10;i++) { /* Do only 10 attempts to write */
+     /* SiS_SetSwitchDDC2(SiS_Pr); */
+-    if(SiS_SetStart(SiS_Pr)) continue;                /* TW: Set start condition */
++    if(SiS_SetStart(SiS_Pr)) continue;                /* Set start condition */
+     tempah = SiS_Pr->SiS_DDC_DeviceAddr;
+-    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);  /* TW: Write DAB (S0=0=write) */
+-    if(temp) continue;                                /* TW:    (ERROR: no ack) */
+-    tempah = tempbx & 0x00FF;                 /* TW: Write RAB */
+-    tempah |= 0x80;                             /* TW: (set bit 7, see datasheet) */
++    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);  /* Write DAB (S0=0=write) */
++    if(temp) continue;                                /*    (ERROR: no ack) */
++    tempah = tempbx & 0x00FF;                 /* Write RAB */
++    tempah |= 0x80;                             /* (set bit 7, see datasheet) */
+     temp = SiS_WriteDDC2Data(SiS_Pr,tempah);
+-    if(temp) continue;                                /* TW:    (ERROR: no ack) */
++    if(temp) continue;                                /*    (ERROR: no ack) */
+     tempah = (tempbx & 0xFF00) >> 8;
+-    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);  /* TW: Write data */
+-    if(temp) continue;                                /* TW:    (ERROR: no ack) */
+-    if(SiS_SetStop(SiS_Pr)) continue;         /* TW: Set stop condition */
++    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);  /* Write data */
++    if(temp) continue;                                /*    (ERROR: no ack) */
++    if(SiS_SetStop(SiS_Pr)) continue;         /* Set stop condition */
+     SiS_Pr->SiS_ChrontelInit = 1;
+     return;
+   }
+-  /* TW: For 630ST */
++  /* For 630ST */
+   if(!(SiS_Pr->SiS_ChrontelInit)) {
+-     SiS_Pr->SiS_DDC_Index = 0x0a;            /* TW: Bit 7 = SC;  Bit 6 = SD */
++     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_DataShift = 0x00;
+-     SiS_Pr->SiS_DDC_DeviceAddr = 0xEA;       /* TW: DAB (Device Address Byte) */
++     SiS_Pr->SiS_DDC_DeviceAddr = 0xEA;       /* DAB (Device Address Byte) */
+-     for(i=0;i<10;i++) {      /* TW: Do only 10 attempts to write */
++     for(i=0;i<10;i++) {      /* Do only 10 attempts to write */
+        /* SiS_SetSwitchDDC2(SiS_Pr); */
+-       if (SiS_SetStart(SiS_Pr)) continue;    /* TW: Set start condition */
++       if (SiS_SetStart(SiS_Pr)) continue;    /* Set start condition */
+        tempah = SiS_Pr->SiS_DDC_DeviceAddr;
+-       temp = SiS_WriteDDC2Data(SiS_Pr,tempah);       /* TW: Write DAB (S0=0=write) */
+-       if(temp) continue;                     /* TW:    (ERROR: no ack) */
+-       tempah = tempbx & 0x00FF;              /* TW: Write RAB */
+-       tempah |= 0x80;                          /* TW: (set bit 7, see datasheet) */
++       temp = SiS_WriteDDC2Data(SiS_Pr,tempah);       /* Write DAB (S0=0=write) */
++       if(temp) continue;                     /*    (ERROR: no ack) */
++       tempah = tempbx & 0x00FF;              /* Write RAB */
++       tempah |= 0x80;                          /* (set bit 7, see datasheet) */
+        temp = SiS_WriteDDC2Data(SiS_Pr,tempah);
+-       if(temp) continue;                     /* TW:    (ERROR: no ack) */
++       if(temp) continue;                     /*    (ERROR: no ack) */
+        tempah = (tempbx & 0xFF00) >> 8;
+-       temp = SiS_WriteDDC2Data(SiS_Pr,tempah);       /* TW: Write data */
+-       if(temp) continue;                     /* TW:    (ERROR: no ack) */
+-       if(SiS_SetStop(SiS_Pr)) continue;      /* TW: Set stop condition */
++       temp = SiS_WriteDDC2Data(SiS_Pr,tempah);       /* Write data */
++       if(temp) continue;                     /*    (ERROR: no ack) */
++       if(SiS_SetStop(SiS_Pr)) continue;      /* Set stop condition */
+        SiS_Pr->SiS_ChrontelInit = 1;
+        return;
+     }
+   }
+ }
+-/* TW: Write to Chrontel 701x */
++/* Write to Chrontel 701x */
+ /* Parameter is [Data (S15-S8) | Register no (S7-S0)] */
+ void
+ SiS_SetCH701x(SiS_Private *SiS_Pr, USHORT tempbx)
+ {
+   USHORT tempah,temp,i;
+-  SiS_Pr->SiS_DDC_Index = 0x11;                       /* TW: Bit 0 = SC;  Bit 1 = SD */
++  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_DataShift = 0x00;
+-  SiS_Pr->SiS_DDC_DeviceAddr = 0xEA;                  /* TW: DAB (Device Address Byte) */
++  SiS_Pr->SiS_DDC_DeviceAddr = 0xEA;                  /* DAB (Device Address Byte) */
+-  for(i=0;i<10;i++) { /* TW: Do only 10 attempts to write */
+-    if (SiS_SetStart(SiS_Pr)) continue;               /* TW: Set start condition */
++  for(i=0;i<10;i++) { /* Do only 10 attempts to write */
++    if (SiS_SetStart(SiS_Pr)) continue;               /* Set start condition */
+     tempah = SiS_Pr->SiS_DDC_DeviceAddr;
+-    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);  /* TW: Write DAB (S0=0=write) */
+-    if(temp) continue;                                /* TW:    (ERROR: no ack) */
++    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);  /* Write DAB (S0=0=write) */
++    if(temp) continue;                                /*    (ERROR: no ack) */
+     tempah = tempbx & 0x00FF;
+-    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);  /* TW: Write RAB */
+-    if(temp) continue;                                /* TW:    (ERROR: no ack) */
++    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);  /* Write RAB */
++    if(temp) continue;                                /*    (ERROR: no ack) */
+     tempah = (tempbx & 0xFF00) >> 8;
+-    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);  /* TW: Write data */
+-    if(temp) continue;                                /* TW:    (ERROR: no ack) */
+-    if(SiS_SetStop(SiS_Pr)) continue;         /* TW: Set stop condition */
++    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);  /* Write data */
++    if(temp) continue;                                /*    (ERROR: no ack) */
++    if(SiS_SetStop(SiS_Pr)) continue;         /* Set stop condition */
+     return;
+   }
+ }
+-/* TW: Read from Chrontel 70xx */
++/* Read from Chrontel 70xx */
+ /* Parameter is [Register no (S7-S0)] */
+ USHORT
+ SiS_GetCH70xx(SiS_Private *SiS_Pr, USHORT tempbx)
+ {
+-   if (SiS_Pr->SiS_IF_DEF_CH70xx == 1)
++   if(SiS_Pr->SiS_IF_DEF_CH70xx == 1)
+       return(SiS_GetCH700x(SiS_Pr,tempbx));
+    else
+       return(SiS_GetCH701x(SiS_Pr,tempbx));
+ }
+-/* TW: Read from Chrontel 700x */
++/* Read from Chrontel 700x */
+ /* Parameter is [Register no (S7-S0)] */
+ USHORT
+ SiS_GetCH700x(SiS_Private *SiS_Pr, USHORT tempbx)
+@@ -9654,57 +10012,57 @@ SiS_GetCH700x(SiS_Private *SiS_Pr, USHOR
+   USHORT tempah,temp,i;
+   if(!(SiS_Pr->SiS_ChrontelInit)) {
+-     SiS_Pr->SiS_DDC_Index = 0x11;            /* TW: Bit 0 = SC;  Bit 1 = SD */
++     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_DataShift = 0x00;
+-     SiS_Pr->SiS_DDC_DeviceAddr = 0xEA;               /* TW: DAB */
++     SiS_Pr->SiS_DDC_DeviceAddr = 0xEA;               /* DAB */
+   }
+   SiS_Pr->SiS_DDC_ReadAddr = tempbx;
+-  for(i=0;i<20;i++) { /* TW: Do only 20 attempts to read */
++  for(i=0;i<20;i++) { /* Do only 20 attempts to read */
+     /* SiS_SetSwitchDDC2(SiS_Pr); */
+-    if(SiS_SetStart(SiS_Pr)) continue;                /* TW: Set start condition */
++    if(SiS_SetStart(SiS_Pr)) continue;                /* Set start condition */
+     tempah = SiS_Pr->SiS_DDC_DeviceAddr;
+-    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);  /* TW: Write DAB (S0=0=write) */
+-    if(temp) continue;                                /* TW:        (ERROR: no ack) */
+-    tempah = SiS_Pr->SiS_DDC_ReadAddr | 0x80; /* TW: Write RAB | 0x80 */
++    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);  /* Write DAB (S0=0=write) */
++    if(temp) continue;                                /*        (ERROR: no ack) */
++    tempah = SiS_Pr->SiS_DDC_ReadAddr | 0x80; /* Write RAB | 0x80 */
+     temp = SiS_WriteDDC2Data(SiS_Pr,tempah);
+-    if(temp) continue;                                /* TW:        (ERROR: no ack) */
+-    if (SiS_SetStart(SiS_Pr)) continue;               /* TW: Re-start */
++    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);  /* TW: DAB (S0=1=read) */
+-    if(temp) continue;                                /* TW:        (ERROR: no ack) */
+-    tempah = SiS_ReadDDC2Data(SiS_Pr,tempah); /* TW: Read byte */
+-    if (SiS_SetStop(SiS_Pr)) continue;                /* TW: Stop condition */
++    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_Pr->SiS_ChrontelInit = 1;
+     return(tempah);
+   }
+-  /* TW: For 630ST */
++  /* For 630ST */
+   if(!SiS_Pr->SiS_ChrontelInit) {
+-     SiS_Pr->SiS_DDC_Index = 0x0a;            /* TW: Bit 0 = SC;  Bit 1 = SD */
++     SiS_Pr->SiS_DDC_Index = 0x0a;            /* Bit 0 = SC;  Bit 1 = 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_DataShift = 0x00;
+-     SiS_Pr->SiS_DDC_DeviceAddr = 0xEA;       /* TW: DAB (Device Address Byte) */
++     SiS_Pr->SiS_DDC_DeviceAddr = 0xEA;       /* DAB (Device Address Byte) */
+-     for(i=0;i<20;i++) {      /* TW: Do only 20 attempts to read */
++     for(i=0;i<20;i++) {      /* Do only 20 attempts to read */
+        /* SiS_SetSwitchDDC2(SiS_Pr); */
+-       if(SiS_SetStart(SiS_Pr)) continue;             /* TW: Set start condition */
++       if(SiS_SetStart(SiS_Pr)) continue;             /* Set start condition */
+        tempah = SiS_Pr->SiS_DDC_DeviceAddr;
+-       temp = SiS_WriteDDC2Data(SiS_Pr,tempah);               /* TW: Write DAB (S0=0=write) */
+-       if(temp) continue;                             /* TW:        (ERROR: no ack) */
+-       tempah = SiS_Pr->SiS_DDC_ReadAddr | 0x80;      /* TW: Write RAB | 0x80 */
++       temp = SiS_WriteDDC2Data(SiS_Pr,tempah);               /* Write DAB (S0=0=write) */
++       if(temp) continue;                             /*        (ERROR: no ack) */
++       tempah = SiS_Pr->SiS_DDC_ReadAddr | 0x80;      /* Write RAB | 0x80 */
+        temp = SiS_WriteDDC2Data(SiS_Pr,tempah);
+-       if(temp) continue;                             /* TW:        (ERROR: no ack) */
+-       if (SiS_SetStart(SiS_Pr)) continue;            /* TW: Re-start */
++       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);               /* TW: DAB (S0=1=read) */
+-       if(temp) continue;                             /* TW:        (ERROR: no ack) */
+-       tempah = SiS_ReadDDC2Data(SiS_Pr,tempah);      /* TW: Read byte */
+-       if (SiS_SetStop(SiS_Pr)) continue;             /* TW: Stop condition */
++       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_Pr->SiS_ChrontelInit = 1;
+        return(tempah);
+      }
+@@ -9712,52 +10070,51 @@ SiS_GetCH700x(SiS_Private *SiS_Pr, USHOR
+   return(0xFFFF);
+ }
+-/* TW: Read from Chrontel 701x */
++/* Read from Chrontel 701x */
+ /* Parameter is [Register no (S7-S0)] */
+ USHORT
+ SiS_GetCH701x(SiS_Private *SiS_Pr, USHORT tempbx)
+ {
+   USHORT tempah,temp,i;
+-  SiS_Pr->SiS_DDC_Index = 0x11;                       /* TW: Bit 0 = SC;  Bit 1 = SD */
++  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_DataShift = 0x00;
+-  SiS_Pr->SiS_DDC_DeviceAddr = 0xEA;          /* TW: DAB */
++  SiS_Pr->SiS_DDC_DeviceAddr = 0xEA;          /* DAB */
+   SiS_Pr->SiS_DDC_ReadAddr = tempbx;
+-   for(i=0;i<20;i++) {        /* TW: Do only 20 attempts to read */
+-    if(SiS_SetStart(SiS_Pr)) continue;                /* TW: Set start condition */
++   for(i=0;i<20;i++) {        /* Do only 20 attempts to read */
++    if(SiS_SetStart(SiS_Pr)) continue;                /* Set start condition */
+     tempah = SiS_Pr->SiS_DDC_DeviceAddr;
+-    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);  /* TW: Write DAB (S0=0=write) */
+-    if(temp) continue;                                /* TW:        (ERROR: no ack) */
+-    tempah = SiS_Pr->SiS_DDC_ReadAddr;                /* TW: Write RAB */
++    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);  /* Write DAB (S0=0=write) */
++    if(temp) continue;                                /*        (ERROR: no ack) */
++    tempah = SiS_Pr->SiS_DDC_ReadAddr;                /* Write RAB */
+     temp = SiS_WriteDDC2Data(SiS_Pr,tempah);
+-    if(temp) continue;                                /* TW:        (ERROR: no ack) */
+-    if (SiS_SetStart(SiS_Pr)) continue;               /* TW: Re-start */
++    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);  /* TW: DAB (S0=1=read) */
+-    if(temp) continue;                                /* TW:        (ERROR: no ack) */
+-    tempah = SiS_ReadDDC2Data(SiS_Pr,tempah); /* TW: Read byte */
+-    SiS_SetStop(SiS_Pr);                      /* TW: Stop condition */
++    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);  /* DAB (S0=1=read) */
++    if(temp) continue;                                /*        (ERROR: no ack) */
++    tempah = SiS_ReadDDC2Data(SiS_Pr,tempah); /* Read byte */
++    SiS_SetStop(SiS_Pr);                      /* Stop condition */
+     return(tempah);
+    }
+   return 0xFFFF;
+ }
+-#ifdef LINUX_XF86
+-/* TW: Our own DDC functions */
++/* Our own DDC functions */
+ USHORT
+-SiS_InitDDCRegs(SiS_Private *SiS_Pr, SISPtr pSiS, USHORT adaptnum, USHORT DDCdatatype,
+-              BOOLEAN checkcr32)
++SiS_InitDDCRegs(SiS_Private *SiS_Pr, unsigned long VBFlags, int VGAEngine,
++                USHORT adaptnum, USHORT DDCdatatype, BOOLEAN checkcr32)
+ {
+      unsigned char ddcdtype[] = { 0xa0, 0xa0, 0xa0, 0xa2, 0xa6 };
+      unsigned char flag, cr32;
+      USHORT        temp = 0, myadaptnum = adaptnum;
+      if(adaptnum != 0) {
+-        if(!(pSiS->VBFlags & (VB_301|VB_301B|VB_302B))) return 0xFFFF;
+-      if((pSiS->VBFlags & VB_30xBDH) && (adaptnum == 1)) return 0xFFFF;
++        if(!(VBFlags & (VB_301|VB_301B|VB_302B))) return 0xFFFF;
++      if((VBFlags & VB_30xBDH) && (adaptnum == 1)) return 0xFFFF;
+      }        
+      
+      /* adapternum for SiS bridges: 0 = CRT1, 1 = LCD, 2 = VGA2 */
+@@ -9771,8 +10128,9 @@ SiS_InitDDCRegs(SiS_Private *SiS_Pr, SIS
+      flag = 0xff;
+      cr32 = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x32);
+-  
+-     if(pSiS->VBFlags & VB_SISBRIDGE) {
++
++#if 0
++     if(VBFlags & VB_SISBRIDGE) {
+       if(myadaptnum == 0) {
+          if(!(cr32 & 0x20)) {
+             myadaptnum = 2;
+@@ -9785,18 +10143,19 @@ SiS_InitDDCRegs(SiS_Private *SiS_Pr, SIS
+          }
+         }
+      }
++#endif
+-     if(pSiS->VGAEngine == SIS_300_VGA) {             /* 300 series */
++     if(VGAEngine == SIS_300_VGA) {           /* 300 series */
+       
+         if(myadaptnum != 0) {
+          flag = 0;
+-         if(pSiS->VBFlags & VB_SISBRIDGE) {
++         if(VBFlags & VB_SISBRIDGE) {
+             SiS_Pr->SiS_DDC_Port = SiS_Pr->SiS_Part4Port;
+               SiS_Pr->SiS_DDC_Index = 0x0f;
+          }
+         }
+-      if(!(pSiS->VBFlags & VB_301)) {
++      if(!(VBFlags & VB_301)) {
+          if((cr32 & 0x80) && (checkcr32)) {
+               if(myadaptnum >= 1) {
+                if(!(cr32 & 0x08)) {
+@@ -9810,11 +10169,11 @@ SiS_InitDDCRegs(SiS_Private *SiS_Pr, SIS
+       temp = 4 - (myadaptnum * 2);
+       if(flag) temp = 0;
+-     } else {                                         /* 310/325/330 series */
++     } else {                                         /* 315/330 series */
+       /* here we simplify: 0 = CRT1, 1 = CRT2 (VGA, LCD) */
+       
+-      if(pSiS->VBFlags & VB_SISBRIDGE) {
++      if(VBFlags & VB_SISBRIDGE) {
+          if(myadaptnum == 2) {
+             myadaptnum = 1;
+            }
+@@ -9822,7 +10181,7 @@ SiS_InitDDCRegs(SiS_Private *SiS_Pr, SIS
+         if(myadaptnum == 1) {
+          flag = 0;
+-         if(pSiS->VBFlags & VB_SISBRIDGE) {
++         if(VBFlags & VB_SISBRIDGE) {
+             SiS_Pr->SiS_DDC_Port = SiS_Pr->SiS_Part4Port;
+               SiS_Pr->SiS_DDC_Index = 0x0f;
+          }
+@@ -9840,7 +10199,7 @@ SiS_InitDDCRegs(SiS_Private *SiS_Pr, SIS
+         temp = myadaptnum;
+         if(myadaptnum == 1) {
+            temp = 0;
+-         if(pSiS->VBFlags & VB_LVDS) flag = 0xff;
++         if(VBFlags & VB_LVDS) flag = 0xff;
+         }
+       if(flag) temp = 0;
+@@ -9852,7 +10211,7 @@ SiS_InitDDCRegs(SiS_Private *SiS_Pr, SIS
+ #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;
+ }
+@@ -9862,15 +10221,9 @@ SiS_WriteDABDDC(SiS_Private *SiS_Pr)
+ {
+    if(SiS_SetStart(SiS_Pr)) return 0xFFFF;
+    if(SiS_WriteDDC2Data(SiS_Pr, SiS_Pr->SiS_DDC_DeviceAddr)) {
+-#ifdef TWDEBUG
+-        xf86DrvMsg(0, X_INFO, "WriteDAB 1 failed\n");
+-#endif         
+       return 0xFFFF;
+    }
+    if(SiS_WriteDDC2Data(SiS_Pr, SiS_Pr->SiS_DDC_SecAddr)) {
+-#ifdef TWDEBUG
+-        xf86DrvMsg(0, X_INFO, "WriteDAB 2 failed\n");
+-#endif         
+       return 0xFFFF;
+    }
+    return(0);
+@@ -9881,9 +10234,6 @@ SiS_PrepareReadDDC(SiS_Private *SiS_Pr)
+ {
+    if(SiS_SetStart(SiS_Pr)) return 0xFFFF;
+    if(SiS_WriteDDC2Data(SiS_Pr, (SiS_Pr->SiS_DDC_DeviceAddr | 0x01))) {
+-#ifdef TWDEBUG
+-        xf86DrvMsg(0, X_INFO, "PrepareReadDDC 1 failed\n");
+-#endif         
+       return 0xFFFF;
+    }
+    return(0);
+@@ -9921,9 +10271,6 @@ SiS_DoProbeDDC(SiS_Private *SiS_Pr)
+     SiS_SetSwitchDDC2(SiS_Pr);
+     if(SiS_PrepareDDC(SiS_Pr)) {
+          SiS_SetStop(SiS_Pr);
+-#ifdef TWDEBUG
+-       xf86DrvMsg(0, X_INFO, "DoProbeDDC 1 failed at PrepareDDC\n");
+-#endif         
+          return(0xFFFF);
+     }
+     mask = 0xf0;
+@@ -9972,7 +10319,7 @@ SiS_ProbeDDC(SiS_Private *SiS_Pr)
+ }
+ USHORT
+-SiS_ReadDDC(SiS_Private *SiS_Pr, SISPtr pSiS, USHORT DDCdatatype, unsigned char *buffer)
++SiS_ReadDDC(SiS_Private *SiS_Pr, USHORT DDCdatatype, unsigned char *buffer)
+ {
+    USHORT flag, length, i;
+    unsigned char chksum,gotcha;
+@@ -10004,28 +10351,7 @@ SiS_ReadDDC(SiS_Private *SiS_Pr, SISPtr 
+    return(flag);
+ }
+-USHORT
+-SiS_ReadLCDDDC(SiS_Private *SiS_Pr, USHORT length, unsigned char *buffer)
+-{
+-   USHORT i=0, flag=0;
+-
+-   length--;
+-   
+-   SiS_SetSwitchDDC2(SiS_Pr);
+-   if(!(SiS_PrepareDDC(SiS_Pr))) {
+-      for(i=0; i<length; i++) {
+-         buffer[i] = (unsigned char)SiS_ReadDDC2Data(SiS_Pr, 0);
+-         SiS_SendACK(SiS_Pr, 0);
+-      }
+-      buffer[i] = (unsigned char)SiS_ReadDDC2Data(SiS_Pr, 0);
+-      SiS_SendACK(SiS_Pr, 1);
+-   } else flag = 0xFFFF;
+-   
+-   SiS_SetStop(SiS_Pr);
+-   return(0);
+-}
+-
+-/* TW: Our private DDC function
++/* Our private DDC functions
+    It complies somewhat with the corresponding VESA function
+    in arguments and return values.
+@@ -10036,7 +10362,7 @@ SiS_ReadLCDDDC(SiS_Private *SiS_Pr, USHO
+    Arguments:
+        adaptnum: 0=CRT1, 1=LCD, 2=VGA2
+-                 CRT2 DDC is only supported on SiS301, 301B (non-DH version), 302B.
++                 CRT2 DDC is only supported on SiS301, 301B, 302B.
+        DDCdatatype: 0=Probe, 1=EDID, 2=EDID+VDIF, 3=EDID V2 (P&D), 4=EDID V2 (FPDI-2)
+        buffer: ptr to 256 data bytes which will be filled with read data.
+@@ -10046,43 +10372,48 @@ SiS_ReadLCDDDC(SiS_Private *SiS_Pr, USHO
+  */
+ USHORT
+-SiS_HandleDDC(SiS_Private *SiS_Pr, SISPtr pSiS, USHORT adaptnum,
+-              USHORT DDCdatatype, unsigned char *buffer)
++SiS_HandleDDC(SiS_Private *SiS_Pr, unsigned long VBFlags, int VGAEngine,
++              USHORT adaptnum, USHORT DDCdatatype, unsigned char *buffer)
+ {
+    if(adaptnum > 2) return 0xFFFF;
+    if(DDCdatatype > 4) return 0xFFFF;
+-   if((!(pSiS->VBFlags & VB_VIDEOBRIDGE)) && (adaptnum > 0)) return 0xFFFF;
+-   if(SiS_InitDDCRegs(SiS_Pr, pSiS, adaptnum, DDCdatatype, TRUE) == 0xFFFF) return 0xFFFF;
++   if((!(VBFlags & VB_VIDEOBRIDGE)) && (adaptnum > 0)) return 0xFFFF;
++   if(SiS_InitDDCRegs(SiS_Pr, VBFlags, VGAEngine, adaptnum, DDCdatatype, TRUE) == 0xFFFF) return 0xFFFF;
+    if(DDCdatatype == 0) {
+        return(SiS_ProbeDDC(SiS_Pr));
+    } else {
+-       return(SiS_ReadDDC(SiS_Pr, pSiS, DDCdatatype, buffer));
++       return(SiS_ReadDDC(SiS_Pr, DDCdatatype, buffer));
+    }
+ }
++#ifdef LINUX_XF86
+ /* 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, yres;
++   USHORT DDCdatatype, paneltype, flag, xres=0, yres=0;
+    USHORT index, myindex, lumsize, numcodes;
+    unsigned char cr37=0, seekcode;
+    BOOLEAN checkexpand = 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;
++
+    if(!(pSiS->VBFlags & (VB_301|VB_301B|VB_302B))) return 0;
+    if(pSiS->VBFlags & VB_30xBDH) return 0;
+   
+-   if(SiS_InitDDCRegs(SiS_Pr, pSiS, 1, 0, FALSE) == 0xFFFF) 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, 
++   xf86DrvMsg(pSiS->pScrn->scrnIndex, X_INFO,
+       "CRT2 DDC capabilities 0x%x\n", flag);
+ #endif        
+    if(flag & 0x10) {
+@@ -10099,7 +10430,7 @@ SiS_SenseLCDDDC(SiS_Private *SiS_Pr, SIS
+    /* Read the entire EDID */
+    retry = 2;
+    do {
+-      if(SiS_ReadDDC(SiS_Pr, pSiS, DDCdatatype, buffer)) {
++      if(SiS_ReadDDC(SiS_Pr, DDCdatatype, buffer)) {
+          xf86DrvMsg(pSiS->pScrn->scrnIndex, X_INFO, 
+               "CRT2: DDC read failed (attempt %d), %s\n", 
+               (3-retry), (retry == 1) ? "giving up" : "retrying");
+@@ -10132,7 +10463,7 @@ SiS_SenseLCDDDC(SiS_Private *SiS_Pr, SIS
+       }
+       
+       if((buffer[0x18] & 0x18) != 0x08) {
+-         xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED, 
++         xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
+               "CRT2: 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" : 
+@@ -10140,103 +10471,226 @@ SiS_SenseLCDDDC(SiS_Private *SiS_Pr, SIS
+               buffer[0x18]);
+        return 0;
+       }
+-      
+-      /* Now analyze the first Detailed Timing Block and hope
+-       * that the preferred timing mode is stored there.
+-       */     
+-      xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
+-      yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
++
++      /* 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;
+-      switch(xres) {
+-         case 800:
+-           if(yres == 600) {
+-              paneltype = Panel310_800x600;
+-              checkexpand = TRUE;
+-           }
+-           break;
+-         case 1024:
+-           if(yres == 768) {
+-              paneltype = Panel310_1024x768;
+-              checkexpand = FALSE;    /* expand causes error at 640x480, should otherwise be TRUE; */
+-           }
+-           break;
+-       case 1280:
+-           if(yres == 960) {
+-              if(pSiS->VGAEngine == SIS_300_VGA) {
+-                 paneltype = Panel300_1280x960;
+-              } else {
+-                 paneltype = Panel310_1280x960; 
+-              }
+-           } else if(yres == 1024) {
+-              paneltype = Panel310_1280x1024;  
+-              checkexpand = TRUE;
+-           } else if(pSiS->VGAEngine == SIS_315_VGA) {
++
++      if(buffer[0x18] & 0x02) {
++
++         xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
++         yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
++
++       SiS_Pr->CP_PreferredX = xres;
++       SiS_Pr->CP_PreferredY = yres;
++
++         switch(xres) {
++            case 800:
++              if(yres == 600) {
++                 paneltype = Panel_800x600;
++                 checkexpand = TRUE;
++              }
++              break;
++            case 1024:
+               if(yres == 768) {
+-                 paneltype = Panel310_1280x768;       /* Panel size 1280x768 not supported yet */
+-                 checkexpand = TRUE;  
+-              }       
+-           }
+-           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(yres == 1200) {
+-                 paneltype = Panel310_1600x1200;
++                 paneltype = Panel_1024x768;
++                 checkexpand = TRUE;
++              }
++              break;
++          case 1280:
++              if(yres == 1024) {
++                 paneltype = Panel_1280x1024;
+                  checkexpand = TRUE;
+-              } 
+-           }
+-                   break;
++              } else if(yres == 960) {
++                 if(pSiS->VGAEngine == SIS_300_VGA) {
++                    paneltype = Panel300_1280x960;
++                 } else {
++                    paneltype = Panel310_1280x960;
++                 }
++              } else if(yres == 768) {
++                 paneltype = Panel_1280x768;
++                 checkexpand = FALSE;
++                 cr37 |= 0x10;
++              }
++              break;
++          case 1400:
++              if(pSiS->VGAEngine == SIS_315_VGA) {
++                 if(yres == 1050) {
++                    paneltype = Panel310_1400x1050;
++                    checkexpand = TRUE;
++                 }
++              }
++                      break;
++#if 0     /* Treat this as custom, as we have no valid timing data yet */
++          case 1600:
++              if(pSiS->VGAEngine == SIS_315_VGA) {
++                 if(yres == 1200) {
++                    paneltype = Panel310_1600x1200;
++                    checkexpand = TRUE;
++                 }
++              }
++                      break;
++#endif
++         }
++
++       if(paneltype != Panel_Custom) {
++          if((buffer[0x47] & 0x18) == 0x18) {
++             cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
++          } else {
++             /* What now? There is no digital separate output timing... */
++             xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING,
++                 "CRT2: Unable to retrieve Sync polarity information\n");
++          }
++       }
++
+       }
+-      if(buffer[0x18] & 0x02) {
+-         /* If the preferred timing mode is stored in the first
+-        * detailed timing block, we now can extract the sync
+-        * polarisation information as well. This only works
+-        * if the Flags indicate a digital separate output.
+-        */
+-        if((buffer[0x47] & 0x18) == 0x18) {
+-           cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
+-        } else {
+-           /* What now? There is no digital separate output timing... */
+-           xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING, 
+-              "CRT2: Unable to retrieve Sync polarity information\n");
+-        }
+-        
+-      } else {
+-         /* If the preferred timing mode is *not* stored in the first
+-        * detailed timing block, we need to guess the resolution
+-        * from the supported Established Timings and assume the
+-        * default sync polarity
+-        */
++      /* 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) {
++
++         BOOLEAN havesync = FALSE;
++       int i, temp, base = 0x36;
++       unsigned long estpack;
++       unsigned short estx[] = {
++              720, 720, 640, 640, 640, 640, 800, 800,
++              800, 800, 832,1024,1024,1024,1024,1280,
++              1152
++       };
++       unsigned short esty[] = {
++              400, 400, 480, 480, 480, 480, 600, 600,
++              600, 600, 624, 768, 768, 768, 768,1024,
++              870
++       };
++
+        paneltype = 0;
+-       if(buffer[0x24] & 0x01) {      
+-              paneltype = Panel310_1280x1024;
+-              checkexpand = TRUE;
+-              cr37 |= 0x20;
+-       } else if(buffer[0x24] & 0x0e) {
+-              paneltype = Panel310_1024x768;
+-              cr37 |= 0xe0;
+-              checkexpand = FALSE;            /* Bug at 640x480 */
+-       } else if(buffer[0x23] & 0x01) {
+-              paneltype = Panel310_800x600;
+-              cr37 |= 0xe0;
+-              checkexpand = 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];
++           }
++       }
++
++       /* 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] > 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])      ||
++                (SiS_Pr->CP_Clock[i] > 108000)                       ||
++                (buffer[base+17] & 0x80)) {
++
++                SiS_Pr->CP_DataValid[i] = FALSE;
++
++             } else {
++
++                paneltype = Panel_Custom;
++
++                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];
++
++                SiS_Pr->CP_Vendor = buffer[9] | (buffer[8] << 8);
++                SiS_Pr->CP_Product = buffer[10] | (buffer[11] << 8);
++
++                /* We must assume the panel can scale, since we have
++                 * no scaling data
++                 */
++                checkexpand = FALSE;
++                cr37 |= 0x10;
++
++                /* 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(!havesync) {
++                      cr37 |= ((((buffer[base+17] & 0x06) ^ 0x06) << 5) | 0x20);
++                      havesync = TRUE;
++                   }
++                } else {
++                   SiS_Pr->CP_SyncValid[i] = FALSE;
++                }
++             }
++            }
++       }
++       if(!havesync) {
++          xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING,
++                 "CRT2: Unable to retrieve Sync polarity information\n");
++       }
+       }
+-      
+-      if(checkexpand) {
+-         /* If any of the Established low-res modes is supported, the 
++
++      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 == Panel310_800x600) {
++       if(paneltype == Panel_800x600) {
+           if(buffer[0x23] & 0xfc) cr37 |= 0x10;
+        } else {
+             if(buffer[0x23])      cr37 |= 0x10;
+@@ -10262,20 +10716,31 @@ SiS_SenseLCDDDC(SiS_Private *SiS_Pr, SIS
+               buffer[0x41]);
+        return 0;
+       }
+-   
+-      xres = buffer[0x76] | (buffer[0x77] << 8);
+-      yres = buffer[0x78] | (buffer[0x79] << 8);
++
++      paneltype = Panel_Custom;
++      SiS_Pr->CP_MaxX = xres = buffer[0x76] | (buffer[0x77] << 8);
++      SiS_Pr->CP_MaxY = yres = buffer[0x78] | (buffer[0x79] << 8);
+       switch(xres) {
+          case 800:
+            if(yres == 600) {
+-              paneltype = Panel310_800x600;
++              paneltype = Panel_800x600;
+               checkexpand = TRUE;
+            }
+            break;
+          case 1024:
+            if(yres == 768) {
+-              paneltype = Panel310_1024x768;
+-              checkexpand = FALSE;                    /* Bug at 640x480; we do the scaling ourselves */
++              paneltype = Panel_1024x768;
++              checkexpand = TRUE;
++           }
++           break;
++       case 1152:
++           if(yres == 768) {
++              if(pSiS->VGAEngine == SIS_300_VGA) {
++                 paneltype = Panel300_1152x768;
++              } else {
++                 paneltype = Panel310_1152x768;
++              }
++              checkexpand = TRUE;
+            }
+            break;
+        case 1280:
+@@ -10286,45 +10751,46 @@ SiS_SenseLCDDDC(SiS_Private *SiS_Pr, SIS
+                  paneltype = Panel300_1280x960;
+               }
+            } else if(yres == 1024) {
+-              paneltype = Panel310_1280x1024;  
++              paneltype = Panel_1280x1024;
+               checkexpand = TRUE;
+-           } else if(pSiS->VGAEngine == SIS_315_VGA) {
+-              if(yres == 768) {
+-                 paneltype = Panel310_1280x768;       /* Panel size 1280x768 not supported yet */
+-                 checkexpand = TRUE;
+-              }
+-           } 
++           } else if(yres == 768) {
++              paneltype = Panel_1280x768;
++              checkexpand = FALSE;
++              cr37 |= 0x10;
++           }
+            break;
+        case 1400:
+            if(pSiS->VGAEngine == SIS_315_VGA) {
+               if(yres == 1050) {
+                  paneltype = Panel310_1400x1050;
+                  checkexpand = TRUE;
+-              } 
++              }
+            }
+                    break;
++#if 0    /* Treat this one as custom since we have no timing data yet */
+        case 1600:
+            if(pSiS->VGAEngine == SIS_315_VGA) {
+               if(yres == 1200) {
+                  paneltype = Panel310_1600x1200;
+                  checkexpand = TRUE;
+-              } 
++              }
+            }
+                    break;
++#endif
+       }
+-                 
++
+       /* 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) */
+@@ -10346,28 +10812,117 @@ SiS_SenseLCDDDC(SiS_Private *SiS_Pr, SIS
+        if(buffer[myindex] == seekcode) {
+           cr37 |= ((((buffer[myindex + 1] & 0x0c) ^ 0x0c) << 4) | 0x20);
+        } else {
+-          xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING, 
+-              "CRT2: Unable to retrieve Sync polarity information\n");    
++          xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING,
++              "CRT2: Unable to retrieve Sync polarity information\n");
+        }
+       } else {
+-         xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING, 
+-              "CRT2: Unable to retrieve Sync polarity information\n");
++         xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING,
++           "CRT2: Unable to retrieve Sync polarity information\n");
++      }
++
++      /* Now seek the detailed timing descriptions for custom panels */
++      if(paneltype == Panel_Custom) {
++         index += (numcodes * 4);
++       numcodes = buffer[0x7f] & 0x07;
++       for(i=0; i<numcodes; i++) {
++          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] > 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])      ||
++             (SiS_Pr->CP_Clock[i] > 108000)                       ||
++             (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];
++
++             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;
++
++             SiS_Pr->CP_Vendor = buffer[2] | (buffer[1] << 8);
++             SiS_Pr->CP_Product = buffer[3] | (buffer[4] << 8);
++
++             /* We must assume the panel can scale, since we have
++              * no scaling data
++              */
++             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; 
++      if(paneltype == Panel310_1280x960) cr37 &= 0x0e;
+    } else {
+-      if(paneltype == Panel300_1280x960) cr37 &= 0x0e; 
++      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 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 Display 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;
+        cr37 &= 0xf1;
+        cr37 |= 0x02;    /* SiS301 */
+        SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x36,0xf0,paneltype);
+@@ -10392,7 +10947,7 @@ SiS_SenseVGA2DDC(SiS_Private *SiS_Pr, SI
+    if(!(pSiS->VBFlags & (VB_301|VB_301B|VB_302B))) return 0;
+ /* if(pSiS->VBFlags & VB_30xBDH) return 0;  */
+    
+-   if(SiS_InitDDCRegs(SiS_Pr, pSiS, 2, 0, FALSE) == 0xFFFF) return 0;
++   if(SiS_InitDDCRegs(SiS_Pr, pSiS->VBFlags, pSiS->VGAEngine, 2, 0, FALSE) == 0xFFFF) return 0;
+    
+    SiS_Pr->SiS_DDC_SecAddr = 0x00;
+    
+@@ -10416,7 +10971,7 @@ SiS_SenseVGA2DDC(SiS_Private *SiS_Pr, SI
+    /* Read the entire EDID */
+    retry = 2;
+    do {
+-      if(SiS_ReadDDC(SiS_Pr, pSiS, DDCdatatype, buffer)) {
++      if(SiS_ReadDDC(SiS_Pr, DDCdatatype, buffer)) {
+          xf86DrvMsg(pSiS->pScrn->scrnIndex, X_INFO, 
+               "CRT2: DDC read failed (attempt %d), %s\n", 
+               (3-retry), (retry == 1) ? "giving up" : "retrying");
+@@ -10435,6 +10990,8 @@ SiS_SenseVGA2DDC(SiS_Private *SiS_Pr, SI
+               "CRT2: 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:
+@@ -10448,198 +11005,19 @@ SiS_SenseVGA2DDC(SiS_Private *SiS_Pr, SI
+               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;    
++      break;
+    }
+-   
++
+    if(foundcrt) {
+        SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x32,0x10);
+    }
+    return(0);
+ }
+-#if 0
+-   /* ----- */
+-USHORT
+-SiS_SenseLCDDDC(SiS_Private *SiS_Pr, SISPtr pSiS)
+-{
+-   USHORT DDCdatatype, paneltype, flag;
+-   unsigned char cr36=0, cr37=0;
+-   unsigned char tempal, tempah, tempbl, tempbh;
+-   USHORT tempax, tempbx, tempcx, push1, push2, push3;
+-   unsigned char addresstable[] = { 0x00, 0x22, 0x30, 0x40 };
+-   int i;
+-   unsigned char buffer[256];
+-   
+-   if(pSiS->VGAEngine != SIS_315_VGA) return 0xFFFF;
+-   if(!(pSiS->VBFlags & (VB_301B|VB_302B))) return 0xFFFF;
+-   
+-   if(SiS_InitDDCRegs(SiS_Pr, pSiS, 1, 0, FALSE) == 0xFFFF) return 0xFFFF;   
+-   
+-   flag = SiS_ProbeDDC(SiS_Pr);
+-   if(flag & 0x02) {
+-      SiS_Pr->SiS_DDC_DeviceAddr = 0xa0;      /* EDID V1 */
+-      DDCdatatype = 1;
+-      SiS_Pr->SiS_DDC_SecAddr = 0x3a;
+-   } else if(flag & 0x08) {
+-      SiS_Pr->SiS_DDC_DeviceAddr = 0xa2;      /* EDID V2 (P&D-D Monitor) */
+-      DDCdatatype = 3;
+-      SiS_Pr->SiS_DDC_SecAddr = 0x76;
+-   } else if(flag & 0x10) {
+-      SiS_Pr->SiS_DDC_DeviceAddr = 0xa6;      /* EDID V2 (FP) */
+-      DDCdatatype = 4;
+-      SiS_Pr->SiS_DDC_SecAddr = 0x76;
+-   } else return 0xFFFF;
+-   
+-   
+-   SiS_ReadLCDDDC(SiS_Pr, 4, buffer);
+-   tempbl = buffer[0];  /* 3a - 76 */
+-   tempbh = buffer[1];  /* 3b - 77 */
+-   
+-   if(SiS_Pr->SiS_DDC_DeviceAddr == 0xa0) {
+-   
+-      /* Read and analyze EDID V1 (res) */
+-   
+-      tempah = 0x02;                          /* 1024x768 by default */
+-      tempbl &= 0xf0;
+-      if(tempbl != 0x40) {                    
+-         tempah = 0x03;                               /* 1280x1024 by default */
+-       if(tempbl == 0x50) {
+-          if(!tempbh) {
+-             tempbh = buffer[3] & 0xf0;
+-             if(tempbh == 0x30) {
+-                 SiS_Pr->SiS_DDC_DeviceAddr = 0xa0;
+-                         SiS_Pr->SiS_DDC_SecAddr = 0x23;
+-                 SiS_ReadLCDDDC(SiS_Pr, 2, buffer);
+-                 tempbl = buffer[0];  /* 0x23 */
+-                 tempbh = buffer[1];  /* 0x24 */
+-                 if(tempbl) cr37 |= 0x10;
+-                 tempah = 0x0a;               /* 1280x768 */
+-             }
+-             if(tempbh == 0x40) {
+-                 SiS_Pr->SiS_DDC_DeviceAddr = 0xa0;
+-                         SiS_Pr->SiS_DDC_SecAddr = 0x23;
+-                 SiS_ReadLCDDDC(SiS_Pr, 2, buffer);
+-                 tempbl = buffer[0];  /* 0x23 */
+-                 tempbh = buffer[1];  /* 0x24 */
+-                 if(tempbl) cr37 |= 0x10;
+-                 tempah = 0x03;               /* 1280x1024 */
+-             }
+-             tempbh = 0x00;
+-          }
+-       }
+-       if(tempbh == 0x00) goto cr36ready;
+-       tempah = 0x07;                         /* 1280x960 */
+-       if(tempbh == 0xc0) goto cr36ready;
+-      }
+-      SiS_Pr->SiS_DDC_DeviceAddr = 0xa0;
+-      SiS_Pr->SiS_DDC_SecAddr = 0x18;         /* feature support */
+-      SiS_ReadLCDDDC(SiS_Pr, 2, buffer);
+-      tempbl = buffer[0];
+-      tempbh = buffer[1];
+-      if(tempbl & 0x02) goto cr36ready;
+-      SiS_Pr->SiS_DDC_DeviceAddr = 0xa0;
+-      SiS_Pr->SiS_DDC_SecAddr = 0x23;         /* Established Timings */
+-      SiS_ReadLCDDDC(SiS_Pr, 2, buffer);
+-      tempbl = buffer[0];
+-      tempbh = buffer[1];
+-      tempah = 0x03;
+-      if(!(tempbh & 0x01)) tempah = 0x02;
+-      if(!tempbl) cr37 |= 0x10;
+-      
+-  } else {
+-  
+-      /* Read and analyze EDID V2 (res) */
+-      
+-      tempah = 0x02;
+-      tempbx = tempbl | (tempbh << 8);
+-      if(tempbx != 1024) tempah = 0x03;
+-      
+-  }     
+-
+-cr36ready:
+-  cr36 = tempah;      
+-  
+-  if(SiS_Pr->SiS_DDC_DeviceAddr == 0xa0) {
+-  
+-     /* Read and analyze EDID V1 (pol) */
+-  
+-     SiS_Pr->SiS_DDC_SecAddr = 0x47;
+-     SiS_ReadLCDDDC(SiS_Pr, 2, buffer);
+-     tempah = buffer[0];
+-     tempah &= 0x06;
+-     tempah ^= 0x06;
+-     tempah <<= 5;
+-     tempah |= 0x20;
+-     cr37 &= 0x1f;
+-     cr37 |= tempah;
+-     if((cr36 & 0x07) == 0x07) cr37 &= 0x0e;
+-     
+-  } else {
+-  
+-     /* Read and analyze EDID V2 (depth, pol) */
+-  
+-     push1 = tempah;
+-     SiS_Pr->SiS_DDC_SecAddr = 0x45;
+-     SiS_ReadLCDDDC(SiS_Pr, 2, buffer);
+-     tempah = 0x01;
+-     if((buffer[0] != 0x20) && (buffer[0] != 0x34)) {   /* RGB18 or 24? */
+-        tempah = 0x00;
+-     }
+-     cr37 &= 0xfe;
+-     cr37 |= tempah;
+-     
+-     SiS_Pr->SiS_DDC_SecAddr = 0x7e;
+-     SiS_ReadLCDDDC(SiS_Pr, 2, buffer);
+-     tempax = (USHORT)(buffer[0] | (buffer[1] << 8));
+-     push2 = tempax;
+-     tempax &= 0x0003;
+-     tempax *= 0x1b;
+-     push3 = tempax;
+-     tempax = (USHORT)buffer[0];
+-     tempax &= 0x001c;
+-     tempax >>= 2;
+-     tempax *= 8;
+-     tempbx = push3;
+-     tempbx += tempax;
+-     if(buffer[0] & 0x20) {           /* Luminance table provided? */
+-        SiS_Pr->SiS_DDC_SecAddr = 0x80;
+-      SiS_ReadLCDDDC(SiS_Pr, 2, buffer);
+-      tempax = buffer[0] | (buffer[1] << 8);
+-      tempax &= 0x1f;
+-      if(buffer[0] & 0x70) tempax <<= 1;
+-      tempax++;       
+-      tempbx += tempax;               /* yes -> skip it */
+-     }
+-     tempcx = push2;
+-     tempax = push1 << 8;
+-     tempbx = (tempbx & 0xff00) | (((tempbx & 0x00ff) + 0x80) & 0x00ff);
+-     if(tempcx & 0xf800) {
+-        tempal = addresstable[((tempax & 0xff00) >> 8)];
+-      tempcx &= 0xf8ff;
+-      tempcx >>= 11;
+-      for(i=0; i<tempcx; i++) {
+-         SiS_Pr->SiS_DDC_SecAddr = (tempbx & 0x00ff);
+-         SiS_ReadLCDDDC(SiS_Pr, 2, buffer);
+-         tempbx += 0x04;
+-         if(buffer[0] == tempal) break;
+-      }
+-      tempah = buffer[1];
+-      tempah &= 0x0c;
+-      tempah ^= 0x0c;
+-      tempah <<= 4;
+-      tempah |= 0x20;
+-        cr37 &= 0x1f;
+-        cr37 |= tempah;
+-      if((cr36 & 0x07) == 0x07) cr37 &= 0x0e;
+-     }
+-  }
+-  xf86DrvMsg(0, X_INFO, "DDC: cr36 = 0x%02x, cr37 = 0x%02x\n", cr36, cr37);
+-  return 0;
+-}
+-#endif
+-
+-/* TW: Generic I2C functions (compliant to i2c library) */
++/* Generic I2C functions (compliant to i2c library) */
+ #if 0
+ USHORT
+@@ -10675,16 +11053,14 @@ SiS_I2C_Stop(SiS_Private *SiS_Pr)
+ void
+ SiS_SetCH70xxANDOR(SiS_Private *SiS_Pr, USHORT tempax,USHORT tempbh)
+ {
+-  USHORT tempal,tempah,tempbl;
++  USHORT tempbl;
+-  tempal = tempax & 0x00FF;
+-  tempah =(tempax >> 8) & 0x00FF;
+-  tempbl = SiS_GetCH70xx(SiS_Pr,tempal);
+-  tempbl = (((tempbl & tempbh) | tempah) << 8 | tempal);
++  tempbl = SiS_GetCH70xx(SiS_Pr,(tempax & 0x00FF));
++  tempbl = (((tempbl & tempbh) << 8) | tempax);
+   SiS_SetCH70xx(SiS_Pr,tempbl);
+ }
+-/* TW: Generic I2C functions for Chrontel --------- */
++/* Generic I2C functions for Chrontel --------- */
+ void
+ SiS_SetSwitchDDC2(SiS_Private *SiS_Pr)
+@@ -10698,37 +11074,37 @@ SiS_SetSwitchDDC2(SiS_Private *SiS_Pr)
+   SiS_WaitRetraceDDC(SiS_Pr);
+ }
+-/* TW: Set I2C start condition */
+-/* TW: This is done by a SD high-to-low transition while SC is high */
++/* Set I2C start condition */
++/* This is done by a SD high-to-low transition while SC is high */
+ USHORT
+ SiS_SetStart(SiS_Private *SiS_Pr)
+ {
+-  if(SiS_SetSCLKLow(SiS_Pr)) return 0xFFFF;                              /* TW: (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_Data,SiS_Pr->SiS_DDC_Data);             /* TW: SD->high */
+-  if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF;                             /* TW: SC->high */
++                  ~SiS_Pr->SiS_DDC_Data,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_Data,0x00);                             /* TW: SD->low = start condition */
+-  if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF;                             /* TW: (SC->low) */
++                  ~SiS_Pr->SiS_DDC_Data,0x00);                             /* SD->low = start condition */
++  if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF;                             /* (SC->low) */
+   return 0;
+ }
+-/* TW: Set I2C stop condition */
+-/* TW: This is done by a SD low-to-high transition while SC is high */
++/* Set I2C stop condition */
++/* This is done by a SD low-to-high transition while SC is high */
+ USHORT
+ SiS_SetStop(SiS_Private *SiS_Pr)
+ {
+-  if(SiS_SetSCLKLow(SiS_Pr)) return 0xFFFF;                              /* TW: (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_Data,0x00);                           /* TW: SD->low   */
+-  if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF;                             /* TW: SC->high  */
++                  ~SiS_Pr->SiS_DDC_Data,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_Data,SiS_Pr->SiS_DDC_Data);           /* TW: SD->high = stop condition */
+-  if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF;                             /* TW: (SC->high) */
++                  ~SiS_Pr->SiS_DDC_Data,SiS_Pr->SiS_DDC_Data);           /* SD->high = stop condition */
++  if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF;                             /* (SC->high) */
+   return 0;
+ }
+-/* TW: Write 8 bits of data */
++/* Write 8 bits of data */
+ USHORT
+ SiS_WriteDDC2Data(SiS_Private *SiS_Pr, USHORT tempax)
+ {
+@@ -10736,18 +11112,18 @@ SiS_WriteDDC2Data(SiS_Private *SiS_Pr, U
+   flag=0x80;
+   for(i=0;i<8;i++) {
+-    SiS_SetSCLKLow(SiS_Pr);                                                 /* TW: SC->low */
++    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_Data,SiS_Pr->SiS_DDC_Data);            /* TW: Write bit (1) to SD */
++                      ~SiS_Pr->SiS_DDC_Data,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_Data,0x00);                            /* TW: Write bit (0) to SD */
++                      ~SiS_Pr->SiS_DDC_Data,0x00);                            /* Write bit (0) to SD */
+     }
+-    SiS_SetSCLKHigh(SiS_Pr);                                                /* TW: SC->high */
++    SiS_SetSCLKHigh(SiS_Pr);                                                /* SC->high */
+     flag >>= 1;
+   }
+-  temp = SiS_CheckACK(SiS_Pr);                                                      /* TW: Check acknowledge */
++  temp = SiS_CheckACK(SiS_Pr);                                                      /* Check acknowledge */
+   return(temp);
+ }
+@@ -10808,27 +11184,27 @@ SiS_DDC2Delay(SiS_Private *SiS_Pr, USHOR
+   }
+ }
+-/* TW: Check I2C acknowledge */
++/* Check I2C acknowledge */
+ /* Returns 0 if ack ok, non-0 if ack not ok */
+ USHORT
+ SiS_CheckACK(SiS_Private *SiS_Pr)
+ {
+   USHORT tempah;
+-  SiS_SetSCLKLow(SiS_Pr);                                        /* TW: (SC->low) */
++  SiS_SetSCLKLow(SiS_Pr);                                        /* (SC->low) */
+   SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index,
+-                  ~SiS_Pr->SiS_DDC_Data,SiS_Pr->SiS_DDC_Data);     /* TW: (SD->high) */
+-  SiS_SetSCLKHigh(SiS_Pr);                                       /* TW: SC->high = clock impulse for ack */
+-  tempah = SiS_GetReg1(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index);/* TW: Read SD */
+-  SiS_SetSCLKLow(SiS_Pr);                                        /* TW: SC->low = end of clock impulse */
+-  if(tempah & SiS_Pr->SiS_DDC_Data) return(1);                           /* TW: Ack OK if bit = 0 */
++                  ~SiS_Pr->SiS_DDC_Data,SiS_Pr->SiS_DDC_Data);     /* (SD->high) */
++  SiS_SetSCLKHigh(SiS_Pr);                                       /* SC->high = clock impulse for ack */
++  tempah = SiS_GetReg1(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);
+ }
+-/* TW: End of I2C functions ----------------------- */
++/* End of I2C functions ----------------------- */
+-/* =============== SiS 310/325/330 O.E.M. ================= */
++/* =============== SiS 315/330 O.E.M. ================= */
+ #ifdef SIS315H
+@@ -10838,11 +11214,11 @@ GetRAMDACromptr(SiS_Private *SiS_Pr, PSI
+   USHORT romptr;
+   if(HwDeviceExtension->jChipType < SIS_330) {
+-     romptr = ROMAddr[0x128] | (ROMAddr[0x129] << 8);  
++     romptr = ROMAddr[0x128] | (ROMAddr[0x129] << 8);
+      if(SiS_Pr->SiS_VBType & VB_SIS301B302B)
+         romptr = ROMAddr[0x12a] | (ROMAddr[0x12b] << 8);
+   } else {
+-     romptr = ROMAddr[0x1a8] | (ROMAddr[0x1a9] << 8);  
++     romptr = ROMAddr[0x1a8] | (ROMAddr[0x1a9] << 8);
+      if(SiS_Pr->SiS_VBType & VB_SIS301B302B)
+         romptr = ROMAddr[0x1aa] | (ROMAddr[0x1ab] << 8);
+   }
+@@ -10855,11 +11231,11 @@ GetLCDromptr(SiS_Private *SiS_Pr, PSIS_H
+   USHORT romptr;
+   if(HwDeviceExtension->jChipType < SIS_330) {
+-     romptr = ROMAddr[0x120] | (ROMAddr[0x121] << 8);  
++     romptr = ROMAddr[0x120] | (ROMAddr[0x121] << 8);
+      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)
+         romptr = ROMAddr[0x122] | (ROMAddr[0x123] << 8);
+   } else {
+-     romptr = ROMAddr[0x1a0] | (ROMAddr[0x1a1] << 8);  
++     romptr = ROMAddr[0x1a0] | (ROMAddr[0x1a1] << 8);
+      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)
+         romptr = ROMAddr[0x1a2] | (ROMAddr[0x1a3] << 8);
+   }
+@@ -10884,10 +11260,22 @@ GetTVromptr(SiS_Private *SiS_Pr, PSIS_HW
+ }
+ static USHORT
+-GetLCDPtrIndexBIOS(SiS_Private *SiS_Pr)
++GetLCDPtrIndexBIOS(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr)
+ {
+   USHORT index;
+-  
++
++  if((IS_SIS650) && (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) {
++     if(!(SiS_IsNotM650or651(SiS_Pr,HwDeviceExtension, BaseAddr))) {
++        if((index = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36) & 0xf0)) {
++         index >>= 4;
++         index *= 3;
++         if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) index += 2;
++           else if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) index++;
++           return index;
++      }
++     }
++  }
++
+   index = SiS_Pr->SiS_LCDResInfo & 0x0F;
+   if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050)      index -= 5;
+   else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) index -= 6;
+@@ -10895,7 +11283,6 @@ GetLCDPtrIndexBIOS(SiS_Private *SiS_Pr)
+   index *= 3;
+   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) index += 2;
+   else if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) index++;
+-
+   return index;
+ }
+@@ -10945,8 +11332,9 @@ static void
+ SetDelayComp(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+              UCHAR *ROMAddr, USHORT ModeNo)
+ {
+-  USHORT delay,index,myindex,temp,romptr=0;
+-  
++  USHORT delay=0,index,myindex,temp,romptr=0;
++  BOOLEAN dochiptest = TRUE;
++
+   if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) {                  /* VGA */
+      
+      if((ROMAddr) && SiS_Pr->SiS_UseROM) {
+@@ -10969,61 +11357,81 @@ SetDelayComp(SiS_Private *SiS_Pr, PSIS_H
+         if(SiS_Pr->SiS_IF_DEF_LVDS == 1)
+            delay = 0x00;
+      }
+-  
++
+   } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {              /* LCD */
+-  
+-     index = GetLCDPtrIndexBIOS(SiS_Pr);
+-     myindex = GetLCDPtrIndex(SiS_Pr);
+-     
+-     if(IS_SIS650 && (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) {       /* 650+30xLV */
+-       if(SiS_IsNotM650or651(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+-          if((ROMAddr) && SiS_Pr->SiS_UseROM) {
+-#if 0      /* Always use the second pointer on 650; some BIOSes */
+-             /* still carry old 301 data at the first location    */  
+-           romptr = ROMAddr[0x120] | (ROMAddr[0x121] << 8); 
+-           if(SiS_Pr->SiS_VBType & VB_SIS302LV) 
+-#endif                
+-              romptr = ROMAddr[0x122] | (ROMAddr[0x123] << 8);
+-           if(!romptr) return;
+-           delay = ROMAddr[(romptr + index)];
+-        } else {
+-             delay = SiS310_LCDDelayCompensation_650301B[myindex];   
+-#if 0      
++
++     BOOLEAN gotitfrompci = FALSE;
++
++     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom) return;
++
++     /* This is a piece of typical SiS crap: They code the OEM LCD
++      * delay into the code, at none defined place in the BIOS.
++      * We now have to start doing a PCI subsystem check here.
++      */
++
++     if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
++      if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
++         gotitfrompci = TRUE;
++         dochiptest = FALSE;
++         delay = 0x03;
++      }
++     }
++
++     if(!gotitfrompci) {
++
++        index = GetLCDPtrIndexBIOS(SiS_Pr, HwDeviceExtension, BaseAddr);
++        myindex = GetLCDPtrIndex(SiS_Pr);
++
++        if(IS_SIS650 && (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) {    /* 650+30xLV */
++           if(SiS_IsNotM650or651(SiS_Pr,HwDeviceExtension, BaseAddr)) {
++             if((ROMAddr) && SiS_Pr->SiS_UseROM) {
++#if 0         /* Always use the second pointer on 650; some BIOSes */
++                /* still carry old 301 data at the first location    */
++              romptr = ROMAddr[0x120] | (ROMAddr[0x121] << 8);
++              if(SiS_Pr->SiS_VBType & VB_SIS302LV)
++#endif
++                 romptr = ROMAddr[0x122] | (ROMAddr[0x123] << 8);
++              if(!romptr) return;
++              delay = ROMAddr[(romptr + index)];
++           } else {
++                delay = SiS310_LCDDelayCompensation_650301B[myindex];
++#if 0
++              if(SiS_Pr->SiS_VBType & VB_SIS302LV)
++                 delay = SiS310_LCDDelayCompensation_650301B[myindex];
++#endif
++           }
++          } else {
++             delay = SiS310_LCDDelayCompensation_651301LV[myindex];
+            if(SiS_Pr->SiS_VBType & VB_SIS302LV)
+-              delay = SiS310_LCDDelayCompensation_650301B[myindex];
+-#endif                
+-        }
+-       } else {
+-          delay = SiS310_LCDDelayCompensation_651301LV[myindex];     
+-        if(SiS_Pr->SiS_VBType & VB_SIS302LV)
+-           delay = SiS310_LCDDelayCompensation_651302LV[myindex];  
+-       }
+-     } else {
+-        if((ROMAddr) && SiS_Pr->SiS_UseROM &&                                 /* 315, 330, 740, 650+301B */
+-         (SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x1024)) { 
+-           romptr = GetLCDromptr(SiS_Pr, HwDeviceExtension, ROMAddr);
+-         if(!romptr) return;
+-         delay = ROMAddr[(romptr + index)];
++              delay = SiS310_LCDDelayCompensation_651302LV[myindex];
++          }
+         } else {
+-           delay = SiS310_LCDDelayCompensation_301[myindex];
+-           if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+-#if 0               /* This data is (like the one in the BIOS) wrong. */         
+-            if(IS_SIS650740) {  /* V */
+-               delay = SiS310_LCDDelayCompensation_650301B[myindex];
+-            } else {
+-#endif              
+-                 delay = SiS310_LCDDelayCompensation_3xx301B[myindex];
+-#if 0          
++           if((ROMAddr) && SiS_Pr->SiS_UseROM &&                              /* 315, 330, 740, 650+301B */
++            (SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x1024)) {
++              romptr = GetLCDromptr(SiS_Pr, HwDeviceExtension, ROMAddr);
++            if(!romptr) return;
++            delay = ROMAddr[(romptr + index)];
++           } else {
++              delay = SiS310_LCDDelayCompensation_301[myindex];
++              if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
++#if 0                  /* This data is (like the one in the BIOS) wrong. */
++               if(IS_SIS550650740660) {
++                  delay = SiS310_LCDDelayCompensation_650301B[myindex];
++               } else {
++#endif
++                    delay = SiS310_LCDDelayCompensation_3xx301B[myindex];
++#if 0
++               }
++#endif
+             }
+-#endif              
+-         }
+-           if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+-            if(IS_SIS650) {
+-                 delay = SiS310_LCDDelayCompensation_LVDS650[myindex];
+-            } else {
+-               delay = SiS310_LCDDelayCompensation_LVDS740[myindex];
++              if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
++               if(IS_SIS650) {
++                    delay = SiS310_LCDDelayCompensation_LVDS650[myindex];
++               } else {
++                  delay = SiS310_LCDDelayCompensation_LVDS740[myindex];
++               }
+             }
+-         }
++           }
+         }
+      }
+      
+@@ -11086,16 +11494,18 @@ SetDelayComp(SiS_Private *SiS_Pr, PSIS_H
+         }
+      }
+   } else {
+-     if(IS_SIS650 && (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) {
++     if(dochiptest && IS_SIS650 && (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) {
+         temp = (SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36) & 0xf0) >> 4;
+-        if(temp == 8) {
++        if(temp == 8) {               /* 1400x1050 BIOS */
+          delay &= 0x0f;
+          delay |= 0xb0;
+         } else if(temp == 6) {
+            delay &= 0x0f;
+          delay |= 0xc0;
++        } else if(temp > 7) { /* 1280x1024 BIOS */
++         delay = 0x35;
+         }
+-        SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2D,delay);  /* index 2D D[3:0] */
++        SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2D,delay);
+      } else {
+         SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2D,0xF0,delay);
+      }
+@@ -11118,7 +11528,7 @@ SetAntiFlicker(SiS_Private *SiS_Pr, PSIS
+   if(ROMAddr && SiS_Pr->SiS_UseROM) {
+      romptr = ROMAddr[0x112] | (ROMAddr[0x113] << 8);
+-     if(HwDeviceExtension->jChipType == SIS_330) {
++     if(HwDeviceExtension->jChipType >= SIS_330) {
+         romptr = ROMAddr[0x192] | (ROMAddr[0x193] << 8);
+      }
+   }
+@@ -11150,7 +11560,7 @@ SetEdgeEnhance(SiS_Private *SiS_Pr, PSIS
+   if(ROMAddr && SiS_Pr->SiS_UseROM) {
+      romptr = ROMAddr[0x124] | (ROMAddr[0x125] << 8);
+-     if(HwDeviceExtension->jChipType == SIS_330) {
++     if(HwDeviceExtension->jChipType >= SIS_330) {
+         romptr = ROMAddr[0x1a4] | (ROMAddr[0x1a5] << 8);
+      }
+   }
+@@ -11198,7 +11608,7 @@ SetYFilter(SiS_Private *SiS_Pr, PSIS_HW_
+   if(ROMAddr && SiS_Pr->SiS_UseROM) {
+       OutputSelect = ROMAddr[0xf3];
+-      if(HwDeviceExtension->jChipType == SIS_330) {
++      if(HwDeviceExtension->jChipType >= SIS_330) {
+           OutputSelect = ROMAddr[0x11b];
+       }
+   }
+@@ -11220,6 +11630,7 @@ SetYFilter(SiS_Private *SiS_Pr, PSIS_HW_
+                  }
+               }
+          }
++       /* PALN : Is this data correct? */
+          if(temp == EnablePALN) {
+               if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+                  for(i=0x35, j=0; i<=0x38; i++, j++) {
+@@ -11247,13 +11658,13 @@ SetPhaseIncr(SiS_Private *SiS_Pr, PSIS_H
+   if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) return;
+   temp1 = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x38);        /* if PALM/N not set */
+-  temp1 &=  (EnablePALM | EnablePALN);
++  temp1 &= (EnablePALM | EnablePALN);
+   if(temp1) return;
+-  if (ModeNo<=0x13) {
+-    resinfo =  SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
++  if(ModeNo<=0x13) {
++     resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+   } else {
+-    resinfo =  SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
++     resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+   }
+   temp = GetTVPtrIndex(SiS_Pr);
+@@ -11262,17 +11673,17 @@ SetPhaseIncr(SiS_Private *SiS_Pr, PSIS_H
+    */
+   if((ROMAddr) && SiS_Pr->SiS_UseROM) {
+      romptr = ROMAddr[0x116] | (ROMAddr[0x117] << 8);
+-     if(HwDeviceExtension->jChipType == SIS_330) {
++     if(HwDeviceExtension->jChipType >= SIS_330) {
+         romptr = ROMAddr[0x196] | (ROMAddr[0x197] << 8);
+      }
+      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+         romptr = ROMAddr[0x11c] | (ROMAddr[0x11d] << 8);
+-      if(HwDeviceExtension->jChipType == SIS_330) {
++      if(HwDeviceExtension->jChipType >= SIS_330) {
+          romptr = ROMAddr[0x19c] | (ROMAddr[0x19d] << 8);
+       }
+       if((SiS_Pr->SiS_VBInfo & SetInSlaveMode) && (!(SiS_Pr->SiS_SetFlag & TVSimuMode))) {
+          romptr = ROMAddr[0x116] | (ROMAddr[0x117] << 8);
+-         if(HwDeviceExtension->jChipType == SIS_330) {
++         if(HwDeviceExtension->jChipType >= SIS_330) {
+               romptr = ROMAddr[0x196] | (ROMAddr[0x197] << 8);
+            }
+       }
+@@ -11296,19 +11707,19 @@ SetPhaseIncr(SiS_Private *SiS_Pr, PSIS_H
+      }
+   }
+-  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {    /* TW: 650/301LV: (VB_SIS301LV | VB_SIS302LV)) */
++  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {    /* 650/301LV: (VB_SIS301LV | VB_SIS302LV)) */
+      if((!(SiS_Pr->SiS_VBInfo & SetPALTV)) && (ModeNo > 0x13)) {
+-        if(resinfo == 6) {
++        if(resinfo == SIS_RI_640x480) {
+             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x31,0x21);
+             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x32,0xf0);
+             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x33,0xf5);
+             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x34,0x7f);
+-      } else if (resinfo == 7) {
++      } else if (resinfo == SIS_RI_800x600) {
+             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x31,0x21);
+             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x32,0xf0);
+             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x33,0xf5);
+             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x34,0x7f);
+-      } else if (resinfo == 8) {
++      } else if (resinfo == SIS_RI_1024x768) {
+             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x31,0x1e);
+             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x32,0x8b);
+             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x33,0xfb);
+@@ -11323,7 +11734,9 @@ SiS_OEM310Setting(SiS_Private *SiS_Pr, P
+                   UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
+ {
+    SetDelayComp(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo);
+-   /* TW: The TV functions are not for LVDS */
++
++   if(SiS_Pr->UseCustomMode) return;
++
+    if( (SiS_Pr->SiS_IF_DEF_LVDS == 0) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV) ) {
+        SetAntiFlicker(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
+        SetPhaseIncr(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
+@@ -11335,7 +11748,7 @@ SiS_OEM310Setting(SiS_Private *SiS_Pr, P
+ }
+ /* FinalizeLCD
+- * This finalizes some Part1 registers for the very panel used.
++ * This finalizes some CRT2 registers for the very panel used.
+  * If we have a backup if these registers, we use it; otherwise
+  * we set the register according to most BIOSes. However, this
+  * function looks quite different in every BIOS, so you better
+@@ -11350,6 +11763,11 @@ SiS_FinalizeLCD(SiS_Private *SiS_Pr, USH
+   if(!(SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) return;
++  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom) return;
++  if(SiS_Pr->UseCustomMode) return;
++
++  if(SiS_Pr->SiS_CustomT == CUT_COMPAQ12802) return;
++
+   if(ModeNo <= 0x13) {
+       resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+       modeflag =  SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+@@ -11358,20 +11776,34 @@ SiS_FinalizeLCD(SiS_Private *SiS_Pr, USH
+       modeflag =  SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+   }
++  if(IS_SIS650) {
++     if((SiS_GetReg1(SiS_Pr->SiS_P3d4, 0x5f) & 0xf0)) {
++        SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1e,0x03);
++     }
++  }
++
+   if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+      if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+         SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x2a,0x00);
+       SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x30,0x00);
+       SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x34,0x10);
++     } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {   /* For all panels? */
++        /* Maybe ACER only? */
++        SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,0xfc,0x01);
+      }
+      tempch = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36);
+      tempch &= 0xf0;
+      tempch >>= 4;
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
++        if(tempch == 0x03) {
++         SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x18,0x02);
++         SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1b,0x25);
++         SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1c,0x00);
++         SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1d,0x1b);
++      }
+       if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+          SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1f,0x76);
+-      }
+-      if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {       
++      } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+          if((SiS_Pr->Backup == TRUE) && (SiS_Pr->Backup_Mode == ModeNo)) {
+             SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x14,SiS_Pr->Backup_14);
+             SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x15,SiS_Pr->Backup_15);
+@@ -11387,14 +11819,14 @@ SiS_FinalizeLCD(SiS_Private *SiS_Pr, USH
+              SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x14,0x90);
+              if(ModeNo <= 0x13) {
+                 SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x18,0x11);
+-                if((resinfo == 0) && (resinfo == 2)) return;
++                if((resinfo == 0) || (resinfo == 2)) return;
+                 SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x18,0x18);
+-                if((resinfo == 1) && (resinfo == 3)) return;
++                if((resinfo == 1) || (resinfo == 3)) return;
+              }
+              SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x18,0x02);
+-             if((ModeNo > 0x13) && (resinfo == 8)) {
++             if((ModeNo > 0x13) && (resinfo == SIS_RI_1024x768)) {
+                 SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x18,0x02);  /* 1.10.7u */
+-#if 0        
++#if 0
+                 tempbx = 806;  /* 0x326 */                     /* other older BIOSes */
+                 tempbx--;
+                 temp = tempbx & 0xff;
+@@ -11449,7 +11881,7 @@ SiS_FinalizeLCD(SiS_Private *SiS_Pr, USH
+       tempbl = SiS_GetReg1(SiS_Pr->SiS_Part2Port,0x04);
+       tempbx = (tempbh << 8) | tempbl;
+       if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+-         if((resinfo == 8) || (!(SiS_Pr->SiS_LCDInfo & DontExpandLCD))) {
++         if((resinfo == SIS_RI_1024x768) || (!(SiS_Pr->SiS_LCDInfo & DontExpandLCD))) {
+             if(SiS_Pr->SiS_SetFlag & LCDVESATiming) {
+               tempbx = 770;
+             } else {
+@@ -11477,67 +11909,56 @@ SiS_FinalizeLCD(SiS_Private *SiS_Pr, USH
+   }
+ }
+-#if 0
+-/* TW: New and checked from 650/301LV BIOS */
+-/* This might clash with newer "FinalizeLCD()" function */
++#endif
++
++
++/*  =================  SiS 300 O.E.M. ================== */
++
++#ifdef SIS300
++
+ void
+-SiS_OEMLCD(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+-                  UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
++SetOEMLCDData2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
++              UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex, USHORT RefTabIndex)
+ {
+-   USHORT tempbx,tempah,tempbl,tempbh,tempcl;
+-
+-   if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) return;
++  USHORT crt2crtc=0, modeflag, myindex=0;
++  UCHAR  temp;
++  int i;
+-   if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+-      SiS_UnLockCRT2(SiS_Pr,HwDeviceExtension,BaseAddr);
+-      tempbh = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x1a);
+-      tempbh &= 0x38;
+-      tempbh >>= 3;
+-      tempbl = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x18);
+-      tempbx = (tempbh << 8) | tempbl;
+-      if(SiS_Pr->SiS_LCDTypeInfo == 1)  tempbx -= 0x12;
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x18,tempbx & 0x00ff);
+-      tempah = (tempbx & 0xff00) >> 8;
+-      tempah &= 0x07;
+-      tempah <<= 3;
+-      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x1a,0xc7,tempah);
+-      tempah = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x19);
+-      tempah &= 0x0f;
+-      if(SiS_Pr->SiS_LCDTypeInfo == 1)  tempah -= 2;
+-      tempah &= 0x0f;
+-      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0xF0,tempah);
+-      tempah = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x14);
+-      if(SiS_Pr->SiS_LCDTypeInfo == 1)  tempah++;
+-      tempah -= 8;
+-      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x14,tempah);
+-   } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+-      tempcl = tempbh = SiS_GetReg1(SiS_Pr->SiS_Part2Port,0x01);
+-      tempbh &= 0x70;
+-      tempbh >>= 4;
+-      tempbl = SiS_GetReg1(SiS_Pr->SiS_Part2Port,0x04);
+-      tempbx = (tempbh << 8) | tempbl;
+-      if(SiS_Pr->SiS_LCDTypeInfo == 1)  {
+-           tempbx -= 0x1e;
+-         tempcl &= 0x0f;
+-         tempcl -= 4;
+-         tempcl &= 0x0f;
+-      }
+-      tempbl = tempbx & 0x00ff;
+-      tempbh = (tempbx >> 8) & 0x00ff;
+-      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x04,tempbl);
+-      tempbh <<= 4;
+-      tempbh |= tempcl;
+-      SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x01,0x80,tempbh);
+-   }
+-}
+-#endif
++  if(ModeNo <= 0x13) {
++        modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
++      crt2crtc = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
++  } else {
++        modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
++      crt2crtc = SiS_Pr->SiS_RefIndex[RefTabIndex].Ext_CRT2CRTC;
++  }
+-#endif
++  crt2crtc &= 0x3f;
++  if(SiS_Pr->SiS_CustomT == CUT_BARCO1024) {
++     SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xdf);
++  }
+-/*  =================  SiS 300 O.E.M. ================== */
++  if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) {
++     if(modeflag & HalfDCLK) myindex = 1;
+-#ifdef SIS300
++     if(SiS_LowModeStuff(SiS_Pr,ModeNo,HwDeviceExtension)) {
++        for(i=0; i<7; i++) {
++           if(barco_p1[myindex][crt2crtc][i][0]) {
++            SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,
++                            barco_p1[myindex][crt2crtc][i][0],
++                            barco_p1[myindex][crt2crtc][i][2],
++                            barco_p1[myindex][crt2crtc][i][1]);
++         }
++        }
++     }
++     temp = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00);
++     if(temp & 0x80) {
++        temp = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x18);
++        temp++;
++        SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x18,temp);
++     }
++  }
++}
+ #if 0   /* Not used */
+ static USHORT
+@@ -11582,7 +12003,7 @@ GetOEMLCDPtr(SiS_Private *SiS_Pr, PSIS_H
+   if(HwDeviceExtension->jChipType == SIS_300) {
+-    tempbx = SiS_Pr->SiS_LCDResInfo - 2;
++    tempbx = (SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36) & 0x0f) - 2;
+     if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx += 4;
+     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+        if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx += 3;
+@@ -11636,24 +12057,29 @@ SetOEMLCDDelay(SiS_Private *SiS_Pr, PSIS
+ {
+   USHORT index,temp,romptr=0;
++  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom) return;
++
+   if((ROMAddr) && SiS_Pr->SiS_UseROM) {
+      if(!(ROMAddr[0x237] & 0x01)) return;
+      if(!(ROMAddr[0x237] & 0x02)) return;
+      romptr = ROMAddr[0x24b] | (ROMAddr[0x24c] << 8);
+   }
+-  /* TW: The Panel Compensation Delay should be set according to tables
+-   *     here. Unfortunately, various BIOS versions don't case 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
+-   *     we otherwise detected a valid pdc.
++  /* The Panel Compensation Delay should be set according to tables
++   * here. Unfortunately, various BIOS versions don't case 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
++   * we otherwise detected a valid pdc.
+    */
+   if(HwDeviceExtension->pdc) return;
+   temp = GetOEMLCDPtr(SiS_Pr,HwDeviceExtension, ROMAddr, 0);
+-  index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].VB_LCDDelayIndex;
++  if(SiS_Pr->UseCustomMode)
++     index = 0;
++  else
++     index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].VB_LCDDelayIndex;
+   if(HwDeviceExtension->jChipType != SIS_300) {
+       if(romptr) {
+@@ -11700,9 +12126,9 @@ SetOEMLCDDelay(SiS_Private *SiS_Pr, PSIS
+ static void
+ SetOEMLCDData(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+-               UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
++              UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
+ {
+-#if 0  /* TW: Unfinished; VData table missing */
++#if 0  /* Unfinished; Data table missing */
+   USHORT index,temp;
+   if((ROMAddr) && SiS_Pr->SiS_UseROM) {
+@@ -11899,25 +12325,29 @@ SetOEMYFilter(SiS_Private *SiS_Pr, PSIS_
+ void
+ SiS_OEM300Setting(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
+-                USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo)
++                USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
++                USHORT RefTableIndex)
+ {
+-  USHORT ModeIdIndex;
++  USHORT OEMModeIdIndex=0;
+-  ModeIdIndex = SiS_SearchVBModeID(SiS_Pr,ROMAddr,&ModeNo);
+-  if(!(ModeIdIndex)) return;
++  if(!SiS_Pr->UseCustomMode) {
++     OEMModeIdIndex = SiS_SearchVBModeID(SiS_Pr,ROMAddr,&ModeNo);
++     if(!(OEMModeIdIndex)) return;
++  }
+   if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+-       SetOEMLCDDelay(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
++       SetOEMLCDDelay(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,OEMModeIdIndex);
+        if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+-            SetOEMLCDData(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
++            SetOEMLCDData(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,OEMModeIdIndex);
+        }
+   }
++  if(SiS_Pr->UseCustomMode) return;
+   if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+-       SetOEMTVDelay(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
++       SetOEMTVDelay(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,OEMModeIdIndex);
+        if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+-                      SetOEMAntiFlicker(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
+-              SetOEMPhaseIncr(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
+-                      SetOEMYFilter(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
++                      SetOEMAntiFlicker(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,OEMModeIdIndex);
++              SetOEMPhaseIncr(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,OEMModeIdIndex);
++                      SetOEMYFilter(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,OEMModeIdIndex);
+        }
+   }
+ }
+--- linux-2.6.0-test6/drivers/video/sis/init301.h      2003-06-14 12:18:21.000000000 -0700
++++ 25/drivers/video/sis/init301.h     2003-10-05 00:34:22.000000000 -0700
+@@ -1,20 +1,47 @@
+-/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/sis/init301.h,v 1.4 2000/12/02 01:16:17 dawes Exp $ */
++/* $XFree86$ */
++/*
++ * Data and prototypes for init301.c
++ *
++ * Copyright 2002, 2003 by Thomas Winischhofer, Vienna, Austria
++ *
++ * If distributed as part of the linux kernel, the contents of this file
++ * is entirely covered by the GPL.
++ *
++ * Otherwise, the following terms apply:
++ *
++ * Permission to use, copy, modify, distribute, and sell this software and its
++ * documentation for any purpose is hereby granted without fee, provided that
++ * the above copyright notice appear in all copies and that both that
++ * copyright notice and this permission notice appear in supporting
++ * documentation, and that the name of the copyright holder not be used in
++ * advertising or publicity pertaining to distribution of the software without
++ * specific, written prior permission.  The copyright holder makes no representations
++ * about the suitability of this software for any purpose.  It is provided
++ * "as is" without express or implied warranty.
++ *
++ * THE COPYRIGHT HOLDER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
++ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
++ * EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR
++ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
++ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
++ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ *
++ * Author:    Thomas Winischhofer <thomas@winischhofer.net>
++ *
++ * Based on code by Silicon Intergrated Systems
++ *
++ */
++
+ #ifndef  _INIT301_
+ #define  _INIT301_
+ #include "osdef.h"
++
+ #include "initdef.h"
+ #include "vgatypes.h"
+ #include "vstruct.h"
+-#ifdef TC
+-#include <stdio.h>
+-#include <string.h>
+-#include <conio.h>
+-#include <dos.h>
+-#include <stdlib.h>
+-#endif
+-
+ #ifdef LINUX_XF86
+ #include "xf86.h"
+ #include "xf86Pci.h"
+@@ -24,6 +51,9 @@
+ #endif
+ #ifdef LINUX_KERNEL
++#ifdef SIS_CP
++#undef SIS_CP
++#endif
+ #include <linux/config.h>
+ #include <linux/version.h>
+ #include <asm/io.h>
+@@ -35,24 +65,60 @@
+ #endif
+ #endif
+-#ifdef WIN2000
+-#include <stdio.h>
+-#include <string.h>
+-#include <miniport.h>
+-#include "dderror.h"
+-#include "devioctl.h"
+-#include "miniport.h"
+-#include "ntddvdeo.h"
+-#include "video.h"
+-#include "sisv.h"
+-#endif
++const UCHAR SiS_HiVisionTable[3][64] = {
++  {
++    0x17, 0x1d, 0x03, 0x09, 0x05, 0x06, 0x0c, 0x0c,
++    0x94, 0x49, 0x01, 0x0a, 0x06, 0x0d, 0x04, 0x0a,
++    0x06, 0x14, 0x0d, 0x04, 0x0a, 0x00, 0x85, 0x1b,
++    0x0c, 0x50, 0x00, 0x97, 0x00, 0xd4, 0x4a, 0x17,
++    0x7d, 0x05, 0x4b, 0x00, 0x00, 0xe2, 0x00, 0x02,
++    0x03, 0x0a, 0x65, 0x9d, 0x08, 0x92, 0x8f, 0x40,
++    0x60, 0x80, 0x14, 0x90, 0x8c, 0x60, 0x14, 0x53,
++    0x00, 0x40, 0x44, 0x00, 0xdb, 0x02, 0x3b, 0x00
++  },
++  {
++    0x1d, 0x1d, 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, 0x2e, 0x16, 0xb5, 0xf4, 0x03,
++    0x7d, 0x11, 0x7d, 0xea, 0x30, 0x36, 0x18, 0x96,
++    0x21, 0x0a, 0x58, 0xee, 0x42, 0x92, 0x0f, 0x40,
++    0x60, 0x80, 0x14, 0x90, 0x8c, 0x60, 0x04, 0xf3,
++    0x00, 0x40, 0x11, 0x00, 0xfc, 0xff, 0x32, 0x00
++  },
++  {
++    0x13, 0x1d, 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, 0x9f, 0x16, 0x59, 0x2b, 0x13,
++    0x27, 0x0b, 0x27, 0xfc, 0x30, 0x27, 0x1c, 0xb0,
++    0x4b, 0x4b, 0x6f, 0x2f, 0x63, 0x92, 0x0f, 0x40,
++    0x60, 0x80, 0x14, 0x90, 0x8c, 0x60, 0x14, 0x2a,
++    0x00, 0x40, 0x11, 0x00, 0xfc, 0xff, 0x32, 0x00
++  }
++};
+-#if 0
+-extern   const USHORT   SiS_MDA_DAC[];
+-extern   const USHORT   SiS_CGA_DAC[];
+-extern   const USHORT   SiS_EGA_DAC[];
+-extern   const USHORT   SiS_VGA_DAC[];
+-#endif
++const UCHAR 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,
++    0xac, 0xda, 0x60, 0xfe, 0x6a, 0x9a, 0x06, 0x10,
++    0xd1, 0x04, 0x18, 0x0a, 0xff, 0x80, 0x00, 0x80,
++    0x3b, 0x77, 0x00, 0xef, 0xe0, 0x10, 0xb0, 0xe0,
++    0x10, 0x4f, 0x0f, 0x0f, 0x05, 0x0f, 0x08, 0x6e,
++    0x1a, 0x1f, 0x25, 0x2a, 0x4c, 0xaa, 0x01
++};
++
++const UCHAR 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,
++    0xac, 0x6a, 0x60, 0x2b, 0x52, 0xcd, 0x61, 0x10,
++    0x51, 0x04, 0x18, 0x0a, 0x1f, 0x80, 0x00, 0x80,
++    0xff, 0xa4, 0x04, 0x2b, 0x94, 0x21, 0x72, 0x94,
++    0x26, 0x05, 0x01, 0x0f, 0xed, 0x0f, 0x0a, 0x64,
++    0x18, 0x1d, 0x23, 0x28, 0x4c, 0xaa, 0x01
++};
+ extern   BOOLEAN  SiS_SearchVBModeID(SiS_Private *SiS_Pr, UCHAR *RomAddr, USHORT *);
+@@ -77,7 +143,8 @@ void     SiS_GetCRT2PtrA(SiS_Private *Si
+                          USHORT RefreshRateTableIndex,USHORT *CRT2Index,USHORT *ResIndex);
+ #endif
+ void     SiS_GetCRT2Part2Ptr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+-                           USHORT RefreshRateTableIndex,USHORT *CRT2Index, USHORT *ResIndex);
++                           USHORT RefreshRateTableIndex,USHORT *CRT2Index, USHORT *ResIndex,
++                           PSIS_HW_DEVICE_INFO HwDeviceExtension);
+ void     SiS_GetCRT2Data301(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                             USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+ USHORT   SiS_GetResInfo(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+@@ -129,7 +196,6 @@ void     SiS_GetVBInfo(SiS_Private *SiS_
+ BOOLEAN  SiS_BridgeIsOn(SiS_Private *SiS_Pr, USHORT BaseAddr,PSIS_HW_DEVICE_INFO);
+ BOOLEAN  SiS_BridgeIsEnable(SiS_Private *SiS_Pr, USHORT BaseAddr,PSIS_HW_DEVICE_INFO);
+ BOOLEAN  SiS_BridgeInSlave(SiS_Private *SiS_Pr);
+-void     SiS_PresetScratchregister(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+ void     SiS_SetTVSystem(SiS_Private *SiS_Pr);
+ void     SiS_LongWait(SiS_Private *SiS_Pr);
+ USHORT   SiS_GetQueueConfig(SiS_Private *SiS_Pr);
+@@ -149,7 +215,7 @@ void     SiS_GetLVDSDesPtrA(SiS_Private 
+                             USHORT RefreshRateTableIndex,USHORT *PanelIndex,USHORT *ResIndex);
+ #endif                            
+ void     SiS_SetTPData(SiS_Private *SiS_Pr);
+-void     SiS_WhatIsThis(SiS_Private *SiS_Pr, USHORT myvbinfo);
++void     SiS_SetChrontelGPIO(SiS_Private *SiS_Pr, USHORT myvbinfo);
+ void     SiS_ModCRT1CRTC(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                          USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+ void     SiS_SetCHTVReg(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+@@ -178,30 +244,28 @@ USHORT   SiS_SetSCLKHigh(SiS_Private *Si
+ USHORT   SiS_ReadDDC2Data(SiS_Private *SiS_Pr, USHORT tempax);
+ USHORT   SiS_WriteDDC2Data(SiS_Private *SiS_Pr, USHORT tempax);
+ USHORT   SiS_CheckACK(SiS_Private *SiS_Pr);
+-USHORT   SiS_ReadLCDDDC(SiS_Private *SiS_Pr, USHORT length, unsigned char *buffer);
+-#ifdef LINUX_XF86
+-USHORT   SiS_SenseLCDDDC(SiS_Private *SiS_Pr, SISPtr pSiS);
+-USHORT   SiS_SenseVGA2DDC(SiS_Private *SiS_Pr, SISPtr pSiS);
+-#endif
++
+ #ifdef SIS315H
+ void     SiS_OEM310Setting(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+                            UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+ void     SiS_OEMLCD(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+-                    UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
++                    UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex);
+ #endif
+ #ifdef SIS300
+ void     SiS_OEM300Setting(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+-                           UCHAR *ROMAddr,USHORT ModeNo);
++                           UCHAR *ROMAddr,USHORT ModeNo, USHORT ModeIdIndex, USHORT RefTabindex);
++void     SetOEMLCDData2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
++                      UCHAR *ROMAddr, USHORT ModeNo, USHORT ModeIdIndex,USHORT RefTableIndex);
+ #endif
+ BOOLEAN  SiS_LowModeStuff(SiS_Private *SiS_Pr, USHORT ModeNo,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+-BOOLEAN  SiS_GetLCDResInfo(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo, USHORT ModeIdIndex,
++void     SiS_GetLCDResInfo(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo, USHORT ModeIdIndex,
+                            PSIS_HW_DEVICE_INFO HwDeviceExtension);
+ /* void    SiS_CHACRT1CRTC(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                         USHORT RefreshRateTableIndex); */
+-BOOLEAN  SiS_SetCRT2Group301(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
+-                             PSIS_HW_DEVICE_INFO HwDeviceExtension);
++BOOLEAN  SiS_SetCRT2Group(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
++                          PSIS_HW_DEVICE_INFO HwDeviceExtension);
+ void     SiS_SetGroup1(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                        PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex);
+ void     SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+@@ -237,19 +301,19 @@ void     SiS_VBWait(SiS_Private *SiS_Pr)
+ void     SiS_SiS30xBLOn(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+ void     SiS_SiS30xBLOff(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+-void     SiS_Chrontel701xBLOn(SiS_Private *SiS_Pr);
++void     SiS_Chrontel701xBLOn(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+ void     SiS_Chrontel701xBLOff(SiS_Private *SiS_Pr);
+ #ifdef SIS315H
+ void     SiS_Chrontel701xOn(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                             USHORT BaseAddr);
+-void     SiS_Chrontel701xOff(SiS_Private *SiS_Pr);
++void     SiS_Chrontel701xOff(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+ void     SiS_ChrontelResetDB(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+ void     SiS_ChrontelDoSomething4(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+ void     SiS_ChrontelDoSomething3(SiS_Private *SiS_Pr, USHORT ModeNo, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+ void     SiS_ChrontelDoSomething2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+ void     SiS_ChrontelDoSomething1(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+ BOOLEAN  SiS_WeHaveBacklightCtrl(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+-void     SiS_ChrontelPowerSequencing(SiS_Private *SiS_Pr);
++void     SiS_ChrontelPowerSequencing(SiS_Private *SiS_Pr,  PSIS_HW_DEVICE_INFO HwDeviceExtension);
+ void     SiS_SetCH701xForLCD(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+ #ifdef NEWCH701x
+ void     SiS_ChrontelDoSomething5(SiS_Private *SiS_Pr);
+@@ -289,73 +353,21 @@ extern   void     SiS_LoadDAC(SiS_Privat
+ extern   UCHAR    SiS_Get310DRAMType(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+ #endif
+-#ifdef LINUX_XF86
+ /* DDC functions */
+-USHORT   SiS_InitDDCRegs(SiS_Private *SiS_Pr, SISPtr pSiS, USHORT adaptnum, USHORT DDCdatatype, BOOLEAN checkcr32);
++USHORT   SiS_InitDDCRegs(SiS_Private *SiS_Pr, unsigned long VBFlags, int VGAEngine,
++                         USHORT adaptnum, USHORT DDCdatatype, BOOLEAN checkcr32);
+ USHORT   SiS_WriteDABDDC(SiS_Private *SiS_Pr);
+ USHORT   SiS_PrepareReadDDC(SiS_Private *SiS_Pr);
+ USHORT   SiS_PrepareDDC(SiS_Private *SiS_Pr);
+ void     SiS_SendACK(SiS_Private *SiS_Pr, USHORT yesno);
+ USHORT   SiS_DoProbeDDC(SiS_Private *SiS_Pr);
+ USHORT   SiS_ProbeDDC(SiS_Private *SiS_Pr);
+-USHORT   SiS_ReadDDC(SiS_Private *SiS_Pr, SISPtr pSiS, USHORT DDCdatatype, unsigned char *buffer);
+-USHORT   SiS_HandleDDC(SiS_Private *SiS_Pr, SISPtr pSiS, USHORT adaptnum,
+-                       USHORT DDCdatatype, unsigned char *buffer);
++USHORT   SiS_ReadDDC(SiS_Private *SiS_Pr, USHORT DDCdatatype, unsigned char *buffer);
++USHORT   SiS_HandleDDC(SiS_Private *SiS_Pr, unsigned long VBFlags, int VGAEngine,
++                     USHORT adaptnum, USHORT DDCdatatype, unsigned char *buffer);
++#ifdef LINUX_XF86
++USHORT   SiS_SenseLCDDDC(SiS_Private *SiS_Pr, SISPtr pSiS);
++USHORT   SiS_SenseVGA2DDC(SiS_Private *SiS_Pr, SISPtr pSiS);
+ #endif
+-const UCHAR SiS_HiVisionTable[3][64] = {
+-  { 
+-    0x17, 0x1d, 0x03, 0x09, 0x05, 0x06, 0x0c, 0x0c,
+-    0x94, 0x49, 0x01, 0x0a, 0x06, 0x0d, 0x04, 0x0a,
+-    0x06, 0x14, 0x0d, 0x04, 0x0a, 0x00, 0x85, 0x1b,
+-    0x0c, 0x50, 0x00, 0x97, 0x00, 0xd4, 0x4a, 0x17,
+-    0x7d, 0x05, 0x4b, 0x00, 0x00, 0xe2, 0x00, 0x02,
+-    0x03, 0x0a, 0x65, 0x9d, 0x08, 0x92, 0x8f, 0x40,
+-    0x60, 0x80, 0x14, 0x90, 0x8c, 0x60, 0x14, 0x53,
+-    0x00, 0x40, 0x44, 0x00, 0xdb, 0x02, 0x3b, 0x00
+-  },
+-  { 
+-    0x1d, 0x1d, 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, 0x2e, 0x16, 0xb5, 0xf4, 0x03,
+-    0x7d, 0x11, 0x7d, 0xea, 0x30, 0x36, 0x18, 0x96,
+-    0x21, 0x0a, 0x58, 0xee, 0x42, 0x92, 0x0f, 0x40,
+-    0x60, 0x80, 0x14, 0x90, 0x8c, 0x60, 0x04, 0xf3,
+-    0x00, 0x40, 0x11, 0x00, 0xfc, 0xff, 0x32, 0x00
+-  },
+-  { 
+-    0x13, 0x1d, 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, 0x9f, 0x16, 0x59, 0x2b, 0x13, 
+-    0x27, 0x0b, 0x27, 0xfc, 0x30, 0x27, 0x1c, 0xb0, 
+-    0x4b, 0x4b, 0x6f, 0x2f, 0x63, 0x92, 0x0f, 0x40, 
+-    0x60, 0x80, 0x14, 0x90, 0x8c, 0x60, 0x14, 0x2a, 
+-    0x00, 0x40, 0x11, 0x00, 0xfc, 0xff, 0x32, 0x00 
+-  }
+-};
+-
+-const UCHAR 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,
+-    0xac, 0xda, 0x60, 0xfe, 0x6a, 0x9a, 0x06, 0x10,
+-    0xd1, 0x04, 0x18, 0x0a, 0xff, 0x80, 0x00, 0x80,
+-    0x3b, 0x77, 0x00, 0xef, 0xe0, 0x10, 0xb0, 0xe0,
+-    0x10, 0x4f, 0x0f, 0x0f, 0x05, 0x0f, 0x08, 0x6e,
+-    0x1a, 0x1f, 0x25, 0x2a, 0x4c, 0xaa, 0x01
+-};
+-
+-const UCHAR 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,
+-    0xac, 0x6a, 0x60, 0x2b, 0x52, 0xcd, 0x61, 0x10,
+-    0x51, 0x04, 0x18, 0x0a, 0x1f, 0x80, 0x00, 0x80,
+-    0xff, 0xa4, 0x04, 0x2b, 0x94, 0x21, 0x72, 0x94,
+-    0x26, 0x05, 0x01, 0x0f, 0xed, 0x0f, 0x0a, 0x64,
+-    0x18, 0x1d, 0x23, 0x28, 0x4c, 0xaa, 0x01
+-};
+-
+ #endif
+--- linux-2.6.0-test6/drivers/video/sis/init.c 2003-06-14 12:18:05.000000000 -0700
++++ 25/drivers/video/sis/init.c        2003-10-05 00:34:22.000000000 -0700
+@@ -1,24 +1,17 @@
+ /* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/sis/init.c,v 1.3 2002/24/04 01:16:16 dawes Exp $ */
+ /*
+- * Mode switching code (CRT1 section) for SiS 300/540/630/730/315/550/650/740/330
++ * Mode switching code (CRT1 section) for
++ * SiS 300/540/630/730/315/550/650/M650/651/M652/740/330/660/M660/760
+  * (Universal module for Linux kernel framebuffer and XFree86 4.x)
+  *
+  * Assembler-To-C translation
+- * Copyright 2002 by Thomas Winischhofer <thomas@winischhofer.net>
+- * Minor parts Copyright SiS, Inc.
++ * Copyright 2002, 2003 by Thomas Winischhofer <thomas@winischhofer.net>
++ * Formerly based on non-functional code-fragements by SiS, Inc.
+  *
+- * Based on BIOS
+- *     1.10.07, 1.10a for 650/CH7019
+- *     1.11.21a for 740/CH7019
+- *     1.11.05 for 650/LVDS (w/o Chrontel)
+- *     1.07.1b, 1.11.6s, 1.11.6w, 1.11.7w, 1.11.8r for 650/301(B/LV)
+- *     2.04.50 (I) and 2.04.5c (II) for 630/301(B)
+- *     2.06.50 for 630/301B (dual VGA)
+- *     2.02.3b, 2.03.02, 2.04.5c, 2.07a and 2.08.b3 for 630/LVDS/LVDS+CH7005
+- *     2.04.5c, 2.04.6c for 730+LVDS+CH7005
+- *     1.09b for 315/301(B)
+- *     1.16.51 for 300+301LV (ECS A907)
+- *     1.01.03 for 330 (Xabre 400)
++ * If distributed as part of the linux kernel, the contents of this file
++ * is entirely covered by the GPL.
++ *
++ * Otherwise, the following terms apply:
+  *
+  * Permission to use, copy, modify, distribute, and sell this software and its
+  * documentation for any purpose is hereby granted without fee, provided that
+@@ -61,12 +54,12 @@
+ #ifdef LINUX_XF86
+ BOOLEAN SiSBIOSSetMode(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                        ScrnInfoPtr pScrn, DisplayModePtr mode, BOOLEAN IsCustom);
+-DisplayModePtr SiSBuildBuiltInModeList(ScrnInfoPtr pScrn);
+-#ifdef SISDUALHEAD /* TW: For dual head */
++DisplayModePtr SiSBuildBuiltInModeList(ScrnInfoPtr pScrn, BOOLEAN includelcdmodes, BOOLEAN isfordvi);
++#ifdef SISDUALHEAD
+ BOOLEAN SiSBIOSSetModeCRT1(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                        ScrnInfoPtr pScrn, DisplayModePtr mode, BOOLEAN IsCustom);
+ BOOLEAN SiSBIOSSetModeCRT2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
+-                       ScrnInfoPtr pScrn, DisplayModePtr mode);
++                       ScrnInfoPtr pScrn, DisplayModePtr mode, BOOLEAN IsCustom);
+ #endif /* dual head */
+ #endif /* linux_xf86 */
+@@ -90,49 +83,201 @@ BOOLEAN SiSSetMode(SiS_Private *SiS_Pr, 
+ static ULONG GetDRAMSize(SiS_Private *SiS_Pr,
+                          PSIS_HW_DEVICE_INFO HwDeviceExtension);
+-static void DelaySeconds(int seconds);
+-void SiS_DebugCode(SiS_Private *SiS_Pr, UCHAR code);
+-
+ static void
+-DelaySeconds(int seconds)
+-{
+-  int i;
+-#ifdef WIN2000
+-  int j;
+-#endif
+-
+-  for (i=0;i<seconds;i++) {
+-#ifdef TC
+-    delay(1000);
+-#endif
+-
+-#ifdef WIN2000
+-    for (j=0;j<20000;j++)
+-      VideoPortStallExecution(50);
+-#endif
+-
+-#ifdef WINCE_HEADER
+-#endif
+-
+-#ifdef LINUX_KERNEL
+-#endif
+-  }
+-}
+-
+-void
+-SiS_DebugCode(SiS_Private *SiS_Pr, UCHAR code)
++InitCommonPointer(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+ {
+-  OutPortByte(0x80, code);
+-  DelaySeconds(0x3);
++   SiS_Pr->SiS_StResInfo     = SiS_StResInfo;
++   SiS_Pr->SiS_ModeResInfo   = SiS_ModeResInfo;
++   SiS_Pr->SiS_StandTable    = SiS_StandTable;
++   if(HwDeviceExtension->jChipType < SIS_315H) {
++      SiS_StandTable[0x04].CRTC[4] = 0x2b;
++      SiS_StandTable[0x05].CRTC[4] = 0x2b;
++      SiS_StandTable[0x06].CRTC[4] = 0x54;
++      SiS_StandTable[0x06].CRTC[5] = 0x80;
++      SiS_StandTable[0x0d].CRTC[4] = 0x2b;
++      SiS_StandTable[0x0e].CRTC[4] = 0x54;
++      SiS_StandTable[0x0e].CRTC[5] = 0x80;
++      SiS_StandTable[0x11].CRTC[4] = 0x54;
++      SiS_StandTable[0x11].CRTC[5] = 0x80;
++      SiS_StandTable[0x11].CRTC[16] = 0x83;
++      SiS_StandTable[0x11].CRTC[17] = 0x85;
++      SiS_StandTable[0x12].CRTC[4] = 0x54;
++      SiS_StandTable[0x12].CRTC[5] = 0x80;
++      SiS_StandTable[0x12].CRTC[16] = 0x83;
++      SiS_StandTable[0x12].CRTC[17] = 0x85;
++      SiS_StandTable[0x13].CRTC[5] = 0xa0;
++      SiS_StandTable[0x17].CRTC[5] = 0xa0;
++      SiS_StandTable[0x1a].CRTC[4] = 0x54;
++      SiS_StandTable[0x1a].CRTC[5] = 0x80;
++      SiS_StandTable[0x1a].CRTC[16] = 0xea;
++      SiS_StandTable[0x1a].CRTC[17] = 0x8c;
++      SiS_StandTable[0x1b].CRTC[4] = 0x54;
++      SiS_StandTable[0x1b].CRTC[5] = 0x80;
++      SiS_StandTable[0x1b].CRTC[16] = 0xea;
++      SiS_StandTable[0x1b].CRTC[17] = 0x8c;
++      SiS_StandTable[0x1c].CRTC[4] = 0x54;
++      SiS_StandTable[0x1c].CRTC[5] = 0x80;
++   } else {
++      SiS_StandTable[0x04].CRTC[4] = 0x2c;
++      SiS_StandTable[0x05].CRTC[4] = 0x2c;
++      SiS_StandTable[0x06].CRTC[4] = 0x55;
++      SiS_StandTable[0x06].CRTC[5] = 0x81;
++      SiS_StandTable[0x0d].CRTC[4] = 0x2c;
++      SiS_StandTable[0x0e].CRTC[4] = 0x55;
++      SiS_StandTable[0x0e].CRTC[5] = 0x81;
++      SiS_StandTable[0x11].CRTC[4] = 0x55;
++      SiS_StandTable[0x11].CRTC[5] = 0x81;
++      SiS_StandTable[0x11].CRTC[16] = 0x82;
++      SiS_StandTable[0x11].CRTC[17] = 0x84;
++      SiS_StandTable[0x12].CRTC[4] = 0x55;
++      SiS_StandTable[0x12].CRTC[5] = 0x81;
++      SiS_StandTable[0x12].CRTC[16] = 0x82;
++      SiS_StandTable[0x12].CRTC[17] = 0x84;
++      SiS_StandTable[0x13].CRTC[5] = 0xb1;
++      SiS_StandTable[0x17].CRTC[5] = 0xb1;
++      SiS_StandTable[0x1a].CRTC[4] = 0x55;
++      SiS_StandTable[0x1a].CRTC[5] = 0x81;
++      SiS_StandTable[0x1a].CRTC[16] = 0xe9;
++      SiS_StandTable[0x1a].CRTC[17] = 0x8b;
++      SiS_StandTable[0x1b].CRTC[4] = 0x55;
++      SiS_StandTable[0x1b].CRTC[5] = 0x81;
++      SiS_StandTable[0x1b].CRTC[16] = 0xe9;
++      SiS_StandTable[0x1b].CRTC[17] = 0x8b;
++      SiS_StandTable[0x1c].CRTC[4] = 0x55;
++      SiS_StandTable[0x1c].CRTC[5] = 0x81;
++   }
++
++   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_NTSCTiming     = SiS_NTSCTiming;
++   SiS_Pr->SiS_PALTiming      = SiS_PALTiming;
++   SiS_Pr->SiS_HiTVSt1Timing  = SiS_HiTVSt1Timing;
++   SiS_Pr->SiS_HiTVSt2Timing  = SiS_HiTVSt2Timing;
++   SiS_Pr->SiS_HiTVTextTiming = SiS_HiTVTextTiming;
++   SiS_Pr->SiS_HiTVExtTiming  = SiS_HiTVExtTiming;
++   SiS_Pr->SiS_HiTVGroup3Data = SiS_HiTVGroup3Data;
++   SiS_Pr->SiS_HiTVGroup3Simu = SiS_HiTVGroup3Simu;
++   SiS_Pr->SiS_HiTVGroup3Text = SiS_HiTVGroup3Text;
++
++   SiS_Pr->SiS_StPALData   = SiS_StPALData;
++   SiS_Pr->SiS_ExtPALData  = SiS_ExtPALData;
++   SiS_Pr->SiS_StNTSCData  = SiS_StNTSCData;
++   SiS_Pr->SiS_ExtNTSCData = SiS_ExtNTSCData;
++/* SiS_Pr->SiS_St1HiTVData = SiS_St1HiTVData;  */
++   SiS_Pr->SiS_St2HiTVData = SiS_St2HiTVData;
++   SiS_Pr->SiS_ExtHiTVData = SiS_ExtHiTVData;
++
++   SiS_Pr->pSiS_OutputSelect = &SiS_OutputSelect;
++   SiS_Pr->pSiS_SoftSetting  = &SiS_SoftSetting;
++
++   SiS_Pr->SiS_LCD1280x960Data      = SiS_LCD1280x960Data;
++   SiS_Pr->SiS_ExtLCD1400x1050Data  = SiS_ExtLCD1400x1050Data;
++   SiS_Pr->SiS_ExtLCD1600x1200Data  = SiS_ExtLCD1600x1200Data;
++   SiS_Pr->SiS_StLCD1400x1050Data   = SiS_StLCD1400x1050Data;
++   SiS_Pr->SiS_StLCD1600x1200Data   = SiS_StLCD1600x1200Data;
++   SiS_Pr->SiS_NoScaleData1400x1050 = SiS_NoScaleData1400x1050;
++   SiS_Pr->SiS_NoScaleData1600x1200 = SiS_NoScaleData1600x1200;
++   SiS_Pr->SiS_ExtLCD1280x768Data   = SiS_ExtLCD1280x768Data;
++   SiS_Pr->SiS_StLCD1280x768Data    = SiS_StLCD1280x768Data;
++   SiS_Pr->SiS_NoScaleData1280x768  = SiS_NoScaleData1280x768;
++   SiS_Pr->SiS_NoScaleData          = SiS_NoScaleData;
++
++   SiS_Pr->SiS_LVDS320x480Data_1   = SiS_LVDS320x480Data_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_LVDSBARCO1366Data_1 = SiS_LVDSBARCO1366Data_1;
++   SiS_Pr->SiS_LVDSBARCO1366Data_2 = SiS_LVDSBARCO1366Data_2;
++   SiS_Pr->SiS_LVDSBARCO1024Data_1 = SiS_LVDSBARCO1024Data_1;
++   SiS_Pr->SiS_LVDSBARCO1024Data_2 = SiS_LVDSBARCO1024Data_2;
++   SiS_Pr->SiS_LVDS848x480Data_1   = SiS_LVDS848x480Data_1;
++   SiS_Pr->SiS_LVDS848x480Data_2   = SiS_LVDS848x480Data_2;
++
++   SiS_Pr->SiS_LCDA1400x1050Data_1 = SiS_LCDA1400x1050Data_1;
++   SiS_Pr->SiS_LCDA1400x1050Data_2 = SiS_LCDA1400x1050Data_2;
++   SiS_Pr->SiS_LCDA1600x1200Data_1 = SiS_LCDA1600x1200Data_1;
++   SiS_Pr->SiS_LCDA1600x1200Data_2 = SiS_LCDA1600x1200Data_2;
++   SiS_Pr->SiS_CHTVUNTSCData = SiS_CHTVUNTSCData;
++   SiS_Pr->SiS_CHTVONTSCData = SiS_CHTVONTSCData;
++
++   SiS_Pr->LVDS1024x768Des_1  = SiS_PanelType1076_1;
++   SiS_Pr->LVDS1280x1024Des_1 = SiS_PanelType1210_1;
++   SiS_Pr->LVDS1400x1050Des_1 = SiS_PanelType1296_1;
++   SiS_Pr->LVDS1600x1200Des_1 = SiS_PanelType1600_1;
++   SiS_Pr->LVDS1024x768Des_2  = SiS_PanelType1076_2;
++   SiS_Pr->LVDS1280x1024Des_2 = SiS_PanelType1210_2;
++   SiS_Pr->LVDS1400x1050Des_2 = SiS_PanelType1296_2;
++   SiS_Pr->LVDS1600x1200Des_2 = SiS_PanelType1600_2;
++
++   SiS_Pr->SiS_PanelTypeNS_1 = SiS_PanelTypeNS_1;
++   SiS_Pr->SiS_PanelTypeNS_2 = SiS_PanelTypeNS_2;
++
++   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_LVDSCRT11280x768_1    = SiS_LVDSCRT11280x768_1;
++   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_LVDSCRT1XXXxXXX_1     = SiS_LVDSCRT1XXXxXXX_1;
++   SiS_Pr->SiS_LVDSCRT1XXXxXXX_1_H   = SiS_LVDSCRT1XXXxXXX_1_H;
++   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;
+ }
+ #ifdef SIS300
+ static void
+ InitTo300Pointer(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+ {
++   InitCommonPointer(SiS_Pr, HwDeviceExtension);
++
+    SiS_Pr->SiS_SModeIDTable  = (SiS_StStruct *)SiS300_SModeIDTable;
+    SiS_Pr->SiS_VBModeIDTable = (SiS_VBModeStruct *)SiS300_VBModeIDTable;
+-   SiS_Pr->SiS_StandTable    = (SiS_StandTableStruct *)SiS300_StandTable;
+    SiS_Pr->SiS_EModeIDTable  = (SiS_ExtStruct *)SiS300_EModeIDTable;
+    SiS_Pr->SiS_RefIndex      = (SiS_Ext2Struct *)SiS300_RefIndex;
+    SiS_Pr->SiS_CRT1Table     = (SiS_CRT1TableStruct *)SiS300_CRT1Table;
+@@ -141,15 +286,12 @@ InitTo300Pointer(SiS_Private *SiS_Pr, PS
+    } else {
+       SiS_Pr->SiS_MCLKData_0    = (SiS_MCLKDataStruct *)SiS300_MCLKData_630; /* 630, 730 */
+    }
++#ifdef LINUXBIOS
+    SiS_Pr->SiS_ECLKData      = (SiS_ECLKDataStruct *)SiS300_ECLKData;
++#endif
+    SiS_Pr->SiS_VCLKData      = (SiS_VCLKDataStruct *)SiS300_VCLKData;
+    SiS_Pr->SiS_VBVCLKData    = (SiS_VBVCLKDataStruct *)SiS300_VCLKData;
+    SiS_Pr->SiS_ScreenOffset  = SiS300_ScreenOffset;
+-   SiS_Pr->SiS_StResInfo     = (SiS_StResInfoStruct *)SiS300_StResInfo;
+-   SiS_Pr->SiS_ModeResInfo   = (SiS_ModeResInfoStruct *)SiS300_ModeResInfo;
+-
+-   SiS_Pr->pSiS_OutputSelect = &SiS300_OutputSelect;
+-   SiS_Pr->pSiS_SoftSetting  = &SiS300_SoftSetting;
+    SiS_Pr->SiS_SR15  = SiS300_SR15;
+@@ -178,15 +320,6 @@ InitTo300Pointer(SiS_Private *SiS_Pr, PS
+    SiS_Pr->pSiS_YCSenseData2    = &SiS300_YCSenseData2;
+ #endif
+-   SiS_Pr->SiS_NTSCPhase  = SiS300_NTSCPhase;
+-   SiS_Pr->SiS_PALPhase   = SiS300_PALPhase;
+-   SiS_Pr->SiS_NTSCPhase2 = SiS300_NTSCPhase2;
+-   SiS_Pr->SiS_PALPhase2  = SiS300_PALPhase2;
+-   SiS_Pr->SiS_PALMPhase  = SiS300_PALMPhase;
+-   SiS_Pr->SiS_PALNPhase  = SiS300_PALNPhase;
+-   SiS_Pr->SiS_PALMPhase2 = SiS300_PALMPhase2;
+-   SiS_Pr->SiS_PALNPhase2 = SiS300_PALNPhase2;
+-
+    SiS_Pr->SiS_StLCD1024x768Data    = (SiS_LCDDataStruct *)SiS300_StLCD1024x768Data;
+    SiS_Pr->SiS_ExtLCD1024x768Data   = (SiS_LCDDataStruct *)SiS300_ExtLCD1024x768Data;
+    SiS_Pr->SiS_St2LCD1024x768Data   = (SiS_LCDDataStruct *)SiS300_St2LCD1024x768Data;
+@@ -195,68 +328,18 @@ InitTo300Pointer(SiS_Private *SiS_Pr, PS
+    SiS_Pr->SiS_St2LCD1280x1024Data  = (SiS_LCDDataStruct *)SiS300_St2LCD1280x1024Data;
+    SiS_Pr->SiS_NoScaleData1024x768  = (SiS_LCDDataStruct *)SiS300_NoScaleData1024x768;
+    SiS_Pr->SiS_NoScaleData1280x1024 = (SiS_LCDDataStruct *)SiS300_NoScaleData1280x1024;
+-   SiS_Pr->SiS_LCD1280x960Data      = (SiS_LCDDataStruct *)SiS300_LCD1280x960Data;
+-   SiS_Pr->SiS_ExtLCD1400x1050Data  = (SiS_LCDDataStruct *)SiS300_ExtLCD1400x1050Data;
+-   SiS_Pr->SiS_ExtLCD1600x1200Data  = (SiS_LCDDataStruct *)SiS300_ExtLCD1600x1200Data;
+-   SiS_Pr->SiS_StLCD1400x1050Data   = (SiS_LCDDataStruct *)SiS300_StLCD1400x1050Data;
+-   SiS_Pr->SiS_StLCD1600x1200Data   = (SiS_LCDDataStruct *)SiS300_StLCD1600x1200Data;
+-   SiS_Pr->SiS_NoScaleData1400x1050 = (SiS_LCDDataStruct *)SiS300_NoScaleData1400x1050;
+-   SiS_Pr->SiS_NoScaleData1600x1200 = (SiS_LCDDataStruct *)SiS300_NoScaleData1600x1200;
+-
+-   SiS_Pr->SiS_StPALData   = (SiS_TVDataStruct *)SiS300_StPALData;
+-   SiS_Pr->SiS_ExtPALData  = (SiS_TVDataStruct *)SiS300_ExtPALData;
+-   SiS_Pr->SiS_StNTSCData  = (SiS_TVDataStruct *)SiS300_StNTSCData;
+-   SiS_Pr->SiS_ExtNTSCData = (SiS_TVDataStruct *)SiS300_ExtNTSCData;
+-/* SiS_Pr->SiS_St1HiTVData = (SiS_TVDataStruct *)SiS300_St1HiTVData;  */
+-   SiS_Pr->SiS_St2HiTVData = (SiS_TVDataStruct *)SiS300_St2HiTVData;
+-   SiS_Pr->SiS_ExtHiTVData = (SiS_TVDataStruct *)SiS300_ExtHiTVData;
+-
+-   SiS_Pr->SiS_NTSCTiming     = SiS300_NTSCTiming;
+-   SiS_Pr->SiS_PALTiming      = SiS300_PALTiming;
+-   SiS_Pr->SiS_HiTVSt1Timing  = SiS300_HiTVSt1Timing;
+-   SiS_Pr->SiS_HiTVSt2Timing  = SiS300_HiTVSt2Timing;
+-   SiS_Pr->SiS_HiTVTextTiming = SiS300_HiTVTextTiming;
+-   SiS_Pr->SiS_HiTVGroup3Data = SiS300_HiTVGroup3Data;
+-   SiS_Pr->SiS_HiTVGroup3Simu = SiS300_HiTVGroup3Simu;
+-   SiS_Pr->SiS_HiTVGroup3Text = SiS300_HiTVGroup3Text;
+    SiS_Pr->SiS_PanelDelayTbl     = (SiS_PanelDelayTblStruct *)SiS300_PanelDelayTbl;
+    SiS_Pr->SiS_PanelDelayTblLVDS = (SiS_PanelDelayTblStruct *)SiS300_PanelDelayTblLVDS;
+-   SiS_Pr->SiS_LVDS800x600Data_1   = (SiS_LVDSDataStruct *)SiS300_LVDS800x600Data_1;
+-   SiS_Pr->SiS_LVDS800x600Data_2   = (SiS_LVDSDataStruct *)SiS300_LVDS800x600Data_2;
+-   SiS_Pr->SiS_LVDS1024x768Data_1  = (SiS_LVDSDataStruct *)SiS300_LVDS1024x768Data_1;
+-   SiS_Pr->SiS_LVDS1024x768Data_2  = (SiS_LVDSDataStruct *)SiS300_LVDS1024x768Data_2;
+-   SiS_Pr->SiS_LVDS1280x1024Data_1 = (SiS_LVDSDataStruct *)SiS300_LVDS1280x1024Data_1;
+-   SiS_Pr->SiS_LVDS1280x1024Data_2 = (SiS_LVDSDataStruct *)SiS300_LVDS1280x1024Data_2;
+-   SiS_Pr->SiS_LVDS1280x960Data_1  = (SiS_LVDSDataStruct *)SiS300_LVDS1280x1024Data_1;
+-   SiS_Pr->SiS_LVDS1280x960Data_2  = (SiS_LVDSDataStruct *)SiS300_LVDS1280x1024Data_2;
+-   SiS_Pr->SiS_LVDS1400x1050Data_1 = (SiS_LVDSDataStruct *)SiS300_LVDS1400x1050Data_1;
+-   SiS_Pr->SiS_LVDS1400x1050Data_2 = (SiS_LVDSDataStruct *)SiS300_LVDS1400x1050Data_2;
+-   SiS_Pr->SiS_LVDS1600x1200Data_1 = (SiS_LVDSDataStruct *)SiS300_LVDS1600x1200Data_1;
+-   SiS_Pr->SiS_LVDS1600x1200Data_2 = (SiS_LVDSDataStruct *)SiS300_LVDS1600x1200Data_2;
+-   SiS_Pr->SiS_LVDS1280x768Data_1  = (SiS_LVDSDataStruct *)SiS300_LVDS1280x768Data_1;
+-   SiS_Pr->SiS_LVDS1280x768Data_2  = (SiS_LVDSDataStruct *)SiS300_LVDS1280x768Data_2;
+-   SiS_Pr->SiS_LVDS1024x600Data_1  = (SiS_LVDSDataStruct *)SiS300_LVDS1024x600Data_1;
+-   SiS_Pr->SiS_LVDS1024x600Data_2  = (SiS_LVDSDataStruct *)SiS300_LVDS1024x600Data_2;
+-   SiS_Pr->SiS_LVDS1152x768Data_1  = (SiS_LVDSDataStruct *)SiS300_LVDS1152x768Data_1;
+-   SiS_Pr->SiS_LVDS1152x768Data_2  = (SiS_LVDSDataStruct *)SiS300_LVDS1152x768Data_2;
+-   SiS_Pr->SiS_LVDSXXXxXXXData_1   = (SiS_LVDSDataStruct *)SiS300_LVDSXXXxXXXData_1;
+-   SiS_Pr->SiS_LVDS320x480Data_1   = (SiS_LVDSDataStruct *)SiS300_LVDS320x480Data_1;
+-   SiS_Pr->SiS_LVDS640x480Data_1   = (SiS_LVDSDataStruct *)SiS300_LVDS640x480Data_1;
+-   SiS_Pr->SiS_LCDA1400x1050Data_1 = (SiS_LVDSDataStruct *)SiS300_LCDA1400x1050Data_1;
+-   SiS_Pr->SiS_LCDA1400x1050Data_2 = (SiS_LVDSDataStruct *)SiS300_LCDA1400x1050Data_2;
+-   SiS_Pr->SiS_LCDA1600x1200Data_1 = (SiS_LVDSDataStruct *)SiS300_LCDA1600x1200Data_1;
+-   SiS_Pr->SiS_LCDA1600x1200Data_2 = (SiS_LVDSDataStruct *)SiS300_LCDA1600x1200Data_2;
+-   SiS_Pr->SiS_CHTVUNTSCData = (SiS_LVDSDataStruct *)SiS300_CHTVUNTSCData;
+-   SiS_Pr->SiS_CHTVONTSCData = (SiS_LVDSDataStruct *)SiS300_CHTVONTSCData;
+    SiS_Pr->SiS_CHTVUPALData  = (SiS_LVDSDataStruct *)SiS300_CHTVUPALData;
+    SiS_Pr->SiS_CHTVOPALData  = (SiS_LVDSDataStruct *)SiS300_CHTVOPALData;
+-   SiS_Pr->SiS_CHTVUPALMData = (SiS_LVDSDataStruct *)SiS300_CHTVUNTSCData; /* not supported on 300 series */
+-   SiS_Pr->SiS_CHTVOPALMData = (SiS_LVDSDataStruct *)SiS300_CHTVONTSCData; /* not supported on 300 series */
++   SiS_Pr->SiS_CHTVUPALMData = SiS_CHTVUNTSCData;                        /* not supported on 300 series */
++   SiS_Pr->SiS_CHTVOPALMData = SiS_CHTVONTSCData;                        /* not supported on 300 series */
+    SiS_Pr->SiS_CHTVUPALNData = (SiS_LVDSDataStruct *)SiS300_CHTVUPALData;  /* not supported on 300 series */
+    SiS_Pr->SiS_CHTVOPALNData = (SiS_LVDSDataStruct *)SiS300_CHTVOPALData;  /* not supported on 300 series */
+    SiS_Pr->SiS_CHTVSOPALData = (SiS_LVDSDataStruct *)SiS300_CHTVSOPALData;
++
+    SiS_Pr->SiS_PanelType00_1 = (SiS_LVDSDesStruct *)SiS300_PanelType00_1;
+    SiS_Pr->SiS_PanelType01_1 = (SiS_LVDSDesStruct *)SiS300_PanelType01_1;
+    SiS_Pr->SiS_PanelType02_1 = (SiS_LVDSDesStruct *)SiS300_PanelType02_1;
+@@ -289,32 +372,28 @@ InitTo300Pointer(SiS_Private *SiS_Pr, PS
+    SiS_Pr->SiS_PanelType0d_2 = (SiS_LVDSDesStruct *)SiS300_PanelType0d_2;
+    SiS_Pr->SiS_PanelType0e_2 = (SiS_LVDSDesStruct *)SiS300_PanelType0e_2;
+    SiS_Pr->SiS_PanelType0f_2 = (SiS_LVDSDesStruct *)SiS300_PanelType0f_2;
+-   SiS_Pr->SiS_PanelTypeNS_1 = (SiS_LVDSDesStruct *)SiS300_PanelTypeNS_1;
+-   SiS_Pr->SiS_PanelTypeNS_2 = (SiS_LVDSDesStruct *)SiS300_PanelTypeNS_2;
+-   SiS_Pr->SiS_CHTVUNTSCDesData = (SiS_LVDSDesStruct *)SiS300_CHTVUNTSCDesData;
+-   SiS_Pr->SiS_CHTVONTSCDesData = (SiS_LVDSDesStruct *)SiS300_CHTVONTSCDesData;
+-   SiS_Pr->SiS_CHTVUPALDesData  = (SiS_LVDSDesStruct *)SiS300_CHTVUPALDesData;
+-   SiS_Pr->SiS_CHTVOPALDesData  = (SiS_LVDSDesStruct *)SiS300_CHTVOPALDesData;
++
++   if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) {
++      SiS_Pr->SiS_PanelType04_1 = (SiS_LVDSDesStruct *)SiS300_PanelType04_1a;
++      SiS_Pr->SiS_PanelType04_2 = (SiS_LVDSDesStruct *)SiS300_PanelType04_2a;
++   }
++   if(SiS_Pr->SiS_CustomT == CUT_BARCO1024) {
++      SiS_Pr->SiS_PanelType04_1 = (SiS_LVDSDesStruct *)SiS300_PanelType04_1b;
++      SiS_Pr->SiS_PanelType04_2 = (SiS_LVDSDesStruct *)SiS300_PanelType04_2b;
++   }
++
+    SiS_Pr->SiS_LVDSCRT1800x600_1     = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT1800x600_1;
+    SiS_Pr->SiS_LVDSCRT11024x768_1    = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11024x768_1;
+    SiS_Pr->SiS_LVDSCRT11280x1024_1   = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11280x1024_1;
+-   SiS_Pr->SiS_LVDSCRT11024x600_1    = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11024x600_1;
+-   SiS_Pr->SiS_LVDSCRT11152x768_1    = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11152x768_1;
+    SiS_Pr->SiS_LVDSCRT1800x600_1_H   = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT1800x600_1_H;
+    SiS_Pr->SiS_LVDSCRT11024x768_1_H  = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11024x768_1_H;
+    SiS_Pr->SiS_LVDSCRT11280x1024_1_H = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11280x1024_1_H;
+-   SiS_Pr->SiS_LVDSCRT11024x600_1_H  = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11024x600_1_H;
+-   SiS_Pr->SiS_LVDSCRT11152x768_1_H  = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11152x768_1_H;
+    SiS_Pr->SiS_LVDSCRT1800x600_2     = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT1800x600_2;
+    SiS_Pr->SiS_LVDSCRT11024x768_2    = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11024x768_2;
+    SiS_Pr->SiS_LVDSCRT11280x1024_2   = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11280x1024_2;
+-   SiS_Pr->SiS_LVDSCRT11024x600_2    = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11024x600_2;
+-   SiS_Pr->SiS_LVDSCRT11152x768_2    = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11152x768_2;
+    SiS_Pr->SiS_LVDSCRT1800x600_2_H   = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT1800x600_2_H;
+    SiS_Pr->SiS_LVDSCRT11024x768_2_H  = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11024x768_2_H;
+    SiS_Pr->SiS_LVDSCRT11280x1024_2_H = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11280x1024_2_H;
+-   SiS_Pr->SiS_LVDSCRT11024x600_2_H  = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11024x600_2_H;
+-   SiS_Pr->SiS_LVDSCRT11152x768_2_H  = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11152x768_2_H;
+    SiS_Pr->SiS_CHTVCRT1UNTSC = (SiS_LVDSCRT1DataStruct *)SiS300_CHTVCRT1UNTSC;
+    SiS_Pr->SiS_CHTVCRT1ONTSC = (SiS_LVDSCRT1DataStruct *)SiS300_CHTVCRT1ONTSC;
+    SiS_Pr->SiS_CHTVCRT1UPAL  = (SiS_LVDSCRT1DataStruct *)SiS300_CHTVCRT1UPAL;
+@@ -339,7 +418,6 @@ InitTo300Pointer(SiS_Private *SiS_Pr, PS
+    SiS_Pr->SiS_CHTVVCLKOPALN = SiS300_CHTVVCLKOPAL;   /* not supported on 300 series */
+    SiS_Pr->SiS_CHTVVCLKSOPAL = SiS300_CHTVVCLKSOPAL;
+-   /* TW: New from 300/301LV BIOS */
+    SiS_Pr->SiS_CRT2Part2_1024x768_1  = (SiS_Part2PortTblStruct *)SiS300_CRT2Part2_1024x768_1;
+    SiS_Pr->SiS_CRT2Part2_1280x1024_1 = (SiS_Part2PortTblStruct *)SiS300_CRT2Part2_1280x1024_1;
+    SiS_Pr->SiS_CRT2Part2_1400x1050_1 = (SiS_Part2PortTblStruct *)SiS300_CRT2Part2_1400x1050_1;
+@@ -353,7 +431,7 @@ InitTo300Pointer(SiS_Private *SiS_Pr, PS
+    SiS_Pr->SiS_CRT2Part2_1400x1050_3 = (SiS_Part2PortTblStruct *)SiS300_CRT2Part2_1400x1050_3;
+    SiS_Pr->SiS_CRT2Part2_1600x1200_3 = (SiS_Part2PortTblStruct *)SiS300_CRT2Part2_1600x1200_3;
+-   /* TW: LCDResInfo will on 300 series be translated to 310/325 series definitions */
++   /* TW: LCDResInfo will on 300 series be translated to 315 series definitions */
+    SiS_Pr->SiS_Panel320x480   = Panel_320x480;
+    SiS_Pr->SiS_Panel640x480   = Panel_640x480;
+    SiS_Pr->SiS_Panel800x600   = Panel_800x600;
+@@ -362,13 +440,17 @@ InitTo300Pointer(SiS_Private *SiS_Pr, PS
+    SiS_Pr->SiS_Panel1280x960  = Panel_1280x960;
+    SiS_Pr->SiS_Panel1024x600  = Panel_1024x600;
+    SiS_Pr->SiS_Panel1152x768  = Panel_1152x768;
+-   SiS_Pr->SiS_Panel1600x1200 = 16;           /* TW: Something illegal */
+-   SiS_Pr->SiS_Panel1400x1050 = 16;           /* TW: Something illegal */
+-   SiS_Pr->SiS_Panel1152x864  = 16;                   /* TW: Something illegal */
+-   SiS_Pr->SiS_Panel1280x768  = 16;                   /* TW: Something illegal */
++   SiS_Pr->SiS_Panel1280x768  = Panel_1280x768;
++   SiS_Pr->SiS_Panel1600x1200 = 255;                  /* TW: Something illegal */
++   SiS_Pr->SiS_Panel1400x1050 = 255;                  /* TW: Something illegal */
++   SiS_Pr->SiS_Panel640x480_2 = 255;                  /* TW: Something illegal */
++   SiS_Pr->SiS_Panel640x480_3 = 255;                  /* TW: Something illegal */
++   SiS_Pr->SiS_Panel1152x864  = 255;                  /* TW: Something illegal */
+    SiS_Pr->SiS_PanelMax       = Panel_320x480;     /* TW: highest value */
+    SiS_Pr->SiS_PanelMinLVDS   = Panel_800x600;     /* TW: Lowest value LVDS */
+    SiS_Pr->SiS_PanelMin301    = Panel_1024x768;    /* TW: lowest value 301 */
++   SiS_Pr->SiS_PanelCustom    = Panel_Custom;
++   SiS_Pr->SiS_PanelBarco1366 = Panel_Barco1366;
+ }
+ #endif
+@@ -376,29 +458,33 @@ InitTo300Pointer(SiS_Private *SiS_Pr, PS
+ static void
+ InitTo310Pointer(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+ {
++   InitCommonPointer(SiS_Pr, HwDeviceExtension);
++
+    SiS_Pr->SiS_SModeIDTable  = (SiS_StStruct *)SiS310_SModeIDTable;
+-   SiS_Pr->SiS_StandTable    = (SiS_StandTableStruct *)SiS310_StandTable;
+    SiS_Pr->SiS_EModeIDTable  = (SiS_ExtStruct *)SiS310_EModeIDTable;
+    SiS_Pr->SiS_RefIndex      = (SiS_Ext2Struct *)SiS310_RefIndex;
+    SiS_Pr->SiS_CRT1Table     = (SiS_CRT1TableStruct *)SiS310_CRT1Table;
+    /* TW: MCLK is different */
+-   if(HwDeviceExtension->jChipType == SIS_330) {
++#ifdef LINUXBIOS
++   if(HwDeviceExtension->jChipType >= SIS_660) {
++      SiS_Pr->SiS_MCLKData_0 = (SiS_MCLKDataStruct *)SiS310_MCLKData_0_660;  /* 660/760 */
++   } else if(HwDeviceExtension->jChipType == SIS_330) {
++#endif
+       SiS_Pr->SiS_MCLKData_0 = (SiS_MCLKDataStruct *)SiS310_MCLKData_0_330;  /* 330 */
++#ifdef LINUXBIOS
+    } else if(HwDeviceExtension->jChipType > SIS_315PRO) {
+       SiS_Pr->SiS_MCLKData_0 = (SiS_MCLKDataStruct *)SiS310_MCLKData_0_650;  /* 550, 650, 740 */
+    } else {
+       SiS_Pr->SiS_MCLKData_0 = (SiS_MCLKDataStruct *)SiS310_MCLKData_0_315;  /* 315 */
+    }
++#endif
+    SiS_Pr->SiS_MCLKData_1    = (SiS_MCLKDataStruct *)SiS310_MCLKData_1;
++#ifdef LINUXBIOS
+    SiS_Pr->SiS_ECLKData      = (SiS_ECLKDataStruct *)SiS310_ECLKData;
++#endif
+    SiS_Pr->SiS_VCLKData      = (SiS_VCLKDataStruct *)SiS310_VCLKData;
+    SiS_Pr->SiS_VBVCLKData    = (SiS_VBVCLKDataStruct *)SiS310_VBVCLKData;
+    SiS_Pr->SiS_ScreenOffset  = SiS310_ScreenOffset;
+-   SiS_Pr->SiS_StResInfo     = (SiS_StResInfoStruct *)SiS310_StResInfo;
+-   SiS_Pr->SiS_ModeResInfo   = (SiS_ModeResInfoStruct *)SiS310_ModeResInfo;
+-
+-   SiS_Pr->pSiS_OutputSelect = &SiS310_OutputSelect;
+-   SiS_Pr->pSiS_SoftSetting  = &SiS310_SoftSetting;
+    SiS_Pr->SiS_SR15  = SiS310_SR15;
+@@ -427,16 +513,6 @@ InitTo310Pointer(SiS_Private *SiS_Pr, PS
+    SiS_Pr->pSiS_YCSenseData2    = &SiS310_YCSenseData2;
+ #endif
+-   SiS_Pr->SiS_NTSCPhase    = SiS310_NTSCPhase;
+-   SiS_Pr->SiS_PALPhase     = SiS310_PALPhase;
+-   SiS_Pr->SiS_NTSCPhase2   = SiS310_NTSCPhase2;
+-   SiS_Pr->SiS_PALPhase2    = SiS310_PALPhase2;
+-   SiS_Pr->SiS_PALMPhase    = SiS310_PALMPhase;
+-   SiS_Pr->SiS_PALNPhase    = SiS310_PALNPhase;
+-   SiS_Pr->SiS_PALMPhase2   = SiS310_PALMPhase2;
+-   SiS_Pr->SiS_PALNPhase2   = SiS310_PALNPhase2;
+-   SiS_Pr->SiS_SpecialPhase = SiS310_SpecialPhase;
+-
+    SiS_Pr->SiS_StLCD1024x768Data    = (SiS_LCDDataStruct *)SiS310_StLCD1024x768Data;
+    SiS_Pr->SiS_ExtLCD1024x768Data   = (SiS_LCDDataStruct *)SiS310_ExtLCD1024x768Data;
+    SiS_Pr->SiS_St2LCD1024x768Data   = (SiS_LCDDataStruct *)SiS310_St2LCD1024x768Data;
+@@ -445,62 +521,10 @@ InitTo310Pointer(SiS_Private *SiS_Pr, PS
+    SiS_Pr->SiS_St2LCD1280x1024Data  = (SiS_LCDDataStruct *)SiS310_St2LCD1280x1024Data;
+    SiS_Pr->SiS_NoScaleData1024x768  = (SiS_LCDDataStruct *)SiS310_NoScaleData1024x768;
+    SiS_Pr->SiS_NoScaleData1280x1024 = (SiS_LCDDataStruct *)SiS310_NoScaleData1280x1024;
+-   SiS_Pr->SiS_LCD1280x960Data      = (SiS_LCDDataStruct *)SiS310_LCD1280x960Data;
+-   SiS_Pr->SiS_ExtLCD1400x1050Data  = (SiS_LCDDataStruct *)SiS310_ExtLCD1400x1050Data;
+-   SiS_Pr->SiS_ExtLCD1600x1200Data  = (SiS_LCDDataStruct *)SiS310_ExtLCD1600x1200Data;
+-   SiS_Pr->SiS_StLCD1400x1050Data   = (SiS_LCDDataStruct *)SiS310_StLCD1400x1050Data;
+-   SiS_Pr->SiS_StLCD1600x1200Data   = (SiS_LCDDataStruct *)SiS310_StLCD1600x1200Data;
+-   SiS_Pr->SiS_NoScaleData1400x1050 = (SiS_LCDDataStruct *)SiS310_NoScaleData1400x1050;
+-   SiS_Pr->SiS_NoScaleData1600x1200 = (SiS_LCDDataStruct *)SiS310_NoScaleData1600x1200;
+-
+-   SiS_Pr->SiS_StPALData   = (SiS_TVDataStruct *)SiS310_StPALData;
+-   SiS_Pr->SiS_ExtPALData  = (SiS_TVDataStruct *)SiS310_ExtPALData;
+-   SiS_Pr->SiS_StNTSCData  = (SiS_TVDataStruct *)SiS310_StNTSCData;
+-   SiS_Pr->SiS_ExtNTSCData = (SiS_TVDataStruct *)SiS310_ExtNTSCData;
+-/* SiS_Pr->SiS_St1HiTVData = (SiS_TVDataStruct *)SiS310_St1HiTVData;  */
+-   SiS_Pr->SiS_St2HiTVData = (SiS_TVDataStruct *)SiS310_St2HiTVData;
+-   SiS_Pr->SiS_ExtHiTVData = (SiS_TVDataStruct *)SiS310_ExtHiTVData;
+-
+-   SiS_Pr->SiS_NTSCTiming     = SiS310_NTSCTiming;
+-   SiS_Pr->SiS_PALTiming      = SiS310_PALTiming;
+-   SiS_Pr->SiS_HiTVSt1Timing  = SiS310_HiTVSt1Timing;
+-   SiS_Pr->SiS_HiTVSt2Timing  = SiS310_HiTVSt2Timing;
+-   SiS_Pr->SiS_HiTVTextTiming = SiS310_HiTVTextTiming;
+-   SiS_Pr->SiS_HiTVExtTiming  = SiS310_HiTVExtTiming;
+-   SiS_Pr->SiS_HiTVGroup3Data = SiS310_HiTVGroup3Data;
+-   SiS_Pr->SiS_HiTVGroup3Simu = SiS310_HiTVGroup3Simu;
+-   SiS_Pr->SiS_HiTVGroup3Text = SiS310_HiTVGroup3Text;
+-   SiS_Pr->SiS_PanelDelayTbl = (SiS_PanelDelayTblStruct *)SiS310_PanelDelayTbl;
++   SiS_Pr->SiS_PanelDelayTbl     = (SiS_PanelDelayTblStruct *)SiS310_PanelDelayTbl;
+    SiS_Pr->SiS_PanelDelayTblLVDS = (SiS_PanelDelayTblStruct *)SiS310_PanelDelayTblLVDS;
+-   SiS_Pr->SiS_LVDS800x600Data_1   = (SiS_LVDSDataStruct *)SiS310_LVDS800x600Data_1;
+-   SiS_Pr->SiS_LVDS800x600Data_2   = (SiS_LVDSDataStruct *)SiS310_LVDS800x600Data_2;
+-   SiS_Pr->SiS_LVDS1024x768Data_1  = (SiS_LVDSDataStruct *)SiS310_LVDS1024x768Data_1;
+-   SiS_Pr->SiS_LVDS1024x768Data_2  = (SiS_LVDSDataStruct *)SiS310_LVDS1024x768Data_2;
+-   SiS_Pr->SiS_LVDS1280x1024Data_1 = (SiS_LVDSDataStruct *)SiS310_LVDS1280x1024Data_1;
+-   SiS_Pr->SiS_LVDS1280x1024Data_2 = (SiS_LVDSDataStruct *)SiS310_LVDS1280x1024Data_2;
+-   SiS_Pr->SiS_LVDS1280x960Data_1  = (SiS_LVDSDataStruct *)SiS310_LVDS1280x960Data_1;
+-   SiS_Pr->SiS_LVDS1280x960Data_2  = (SiS_LVDSDataStruct *)SiS310_LVDS1280x960Data_2;
+-   SiS_Pr->SiS_LVDS1400x1050Data_1 = (SiS_LVDSDataStruct *)SiS310_LVDS1400x1050Data_1;
+-   SiS_Pr->SiS_LVDS1400x1050Data_2 = (SiS_LVDSDataStruct *)SiS310_LVDS1400x1050Data_2;
+-   SiS_Pr->SiS_LVDS1600x1200Data_1 = (SiS_LVDSDataStruct *)SiS310_LVDS1600x1200Data_1;
+-   SiS_Pr->SiS_LVDS1600x1200Data_2 = (SiS_LVDSDataStruct *)SiS310_LVDS1600x1200Data_2;
+-   SiS_Pr->SiS_LVDS1280x768Data_1  = (SiS_LVDSDataStruct *)SiS310_LVDS1280x768Data_1;
+-   SiS_Pr->SiS_LVDS1280x768Data_2  = (SiS_LVDSDataStruct *)SiS310_LVDS1280x768Data_2;
+-   SiS_Pr->SiS_LVDS1024x600Data_1  = (SiS_LVDSDataStruct *)SiS310_LVDS1024x600Data_1;
+-   SiS_Pr->SiS_LVDS1024x600Data_2  = (SiS_LVDSDataStruct *)SiS310_LVDS1024x600Data_2;
+-   SiS_Pr->SiS_LVDS1152x768Data_1  = (SiS_LVDSDataStruct *)SiS310_LVDS1152x768Data_1;
+-   SiS_Pr->SiS_LVDS1152x768Data_2  = (SiS_LVDSDataStruct *)SiS310_LVDS1152x768Data_2;
+-   SiS_Pr->SiS_LVDSXXXxXXXData_1   = (SiS_LVDSDataStruct *)SiS310_LVDSXXXxXXXData_1;
+-   SiS_Pr->SiS_LVDS320x480Data_1   = (SiS_LVDSDataStruct *)SiS310_LVDS320x480Data_1;
+-   SiS_Pr->SiS_LVDS640x480Data_1   = (SiS_LVDSDataStruct *)SiS310_LVDS640x480Data_1;
+-   SiS_Pr->SiS_LCDA1400x1050Data_1  = (SiS_LVDSDataStruct *)SiS310_LCDA1400x1050Data_1;
+-   SiS_Pr->SiS_LCDA1400x1050Data_2  = (SiS_LVDSDataStruct *)SiS310_LCDA1400x1050Data_2;
+-   SiS_Pr->SiS_LCDA1600x1200Data_1  = (SiS_LVDSDataStruct *)SiS310_LCDA1600x1200Data_1;
+-   SiS_Pr->SiS_LCDA1600x1200Data_2  = (SiS_LVDSDataStruct *)SiS310_LCDA1600x1200Data_2;
+-   SiS_Pr->SiS_CHTVUNTSCData = (SiS_LVDSDataStruct *)SiS310_CHTVUNTSCData;
+-   SiS_Pr->SiS_CHTVONTSCData = (SiS_LVDSDataStruct *)SiS310_CHTVONTSCData;
+    SiS_Pr->SiS_CHTVUPALData  = (SiS_LVDSDataStruct *)SiS310_CHTVUPALData;
+    SiS_Pr->SiS_CHTVOPALData  = (SiS_LVDSDataStruct *)SiS310_CHTVOPALData;
+    SiS_Pr->SiS_CHTVUPALMData = (SiS_LVDSDataStruct *)SiS310_CHTVUPALMData;
+@@ -508,6 +532,7 @@ InitTo310Pointer(SiS_Private *SiS_Pr, PS
+    SiS_Pr->SiS_CHTVUPALNData = (SiS_LVDSDataStruct *)SiS310_CHTVUPALNData;
+    SiS_Pr->SiS_CHTVOPALNData = (SiS_LVDSDataStruct *)SiS310_CHTVOPALNData;
+    SiS_Pr->SiS_CHTVSOPALData = (SiS_LVDSDataStruct *)SiS310_CHTVSOPALData;
++
+    SiS_Pr->SiS_PanelType00_1 = (SiS_LVDSDesStruct *)SiS310_PanelType00_1;
+    SiS_Pr->SiS_PanelType01_1 = (SiS_LVDSDesStruct *)SiS310_PanelType01_1;
+    SiS_Pr->SiS_PanelType02_1 = (SiS_LVDSDesStruct *)SiS310_PanelType02_1;
+@@ -540,19 +565,7 @@ InitTo310Pointer(SiS_Private *SiS_Pr, PS
+    SiS_Pr->SiS_PanelType0d_2 = (SiS_LVDSDesStruct *)SiS310_PanelType0d_2;
+    SiS_Pr->SiS_PanelType0e_2 = (SiS_LVDSDesStruct *)SiS310_PanelType0e_2;
+    SiS_Pr->SiS_PanelType0f_2 = (SiS_LVDSDesStruct *)SiS310_PanelType0f_2;
+-   SiS_Pr->SiS_PanelTypeNS_1 = (SiS_LVDSDesStruct *)SiS310_PanelTypeNS_1;
+-   SiS_Pr->SiS_PanelTypeNS_2 = (SiS_LVDSDesStruct *)SiS310_PanelTypeNS_2;
+-   SiS_Pr->LVDS1024x768Des_1  = (SiS_LVDSDesStruct *)SiS310_PanelType1076_1;
+-   SiS_Pr->LVDS1280x1024Des_1 = (SiS_LVDSDesStruct *)SiS310_PanelType1210_1;
+-   SiS_Pr->LVDS1400x1050Des_1 = (SiS_LVDSDesStruct *)SiS310_PanelType1296_1 ;
+-   SiS_Pr->LVDS1600x1200Des_1 = (SiS_LVDSDesStruct *)SiS310_PanelType1600_1 ;
+-   SiS_Pr->LVDS1024x768Des_2  = (SiS_LVDSDesStruct *)SiS310_PanelType1076_2;
+-   SiS_Pr->LVDS1280x1024Des_2 = (SiS_LVDSDesStruct *)SiS310_PanelType1210_2;
+-   SiS_Pr->LVDS1400x1050Des_2 = (SiS_LVDSDesStruct *)SiS310_PanelType1296_2;
+-   SiS_Pr->LVDS1600x1200Des_2 = (SiS_LVDSDesStruct *)SiS310_PanelType1600_2 ;
+-
+-   /* TW: New from 650/301LV BIOS */
+    SiS_Pr->SiS_CRT2Part2_1024x768_1  = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1024x768_1;
+    SiS_Pr->SiS_CRT2Part2_1280x1024_1 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1280x1024_1;
+    SiS_Pr->SiS_CRT2Part2_1400x1050_1 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1400x1050_1;
+@@ -566,51 +579,32 @@ InitTo310Pointer(SiS_Private *SiS_Pr, PS
+    SiS_Pr->SiS_CRT2Part2_1400x1050_3 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1400x1050_3;
+    SiS_Pr->SiS_CRT2Part2_1600x1200_3 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1600x1200_3;
+-   SiS_Pr->SiS_CHTVUNTSCDesData = (SiS_LVDSDesStruct *)SiS310_CHTVUNTSCDesData;
+-   SiS_Pr->SiS_CHTVONTSCDesData = (SiS_LVDSDesStruct *)SiS310_CHTVONTSCDesData;
+-   SiS_Pr->SiS_CHTVUPALDesData  = (SiS_LVDSDesStruct *)SiS310_CHTVUPALDesData;
+-   SiS_Pr->SiS_CHTVOPALDesData  = (SiS_LVDSDesStruct *)SiS310_CHTVOPALDesData;
+-
+    SiS_Pr->SiS_LVDSCRT1800x600_1     = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT1800x600_1;
+    SiS_Pr->SiS_LVDSCRT11024x768_1    = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11024x768_1;
+    SiS_Pr->SiS_LVDSCRT11280x1024_1   = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11280x1024_1;
+    SiS_Pr->SiS_LVDSCRT11400x1050_1   = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11400x1050_1;
+-   SiS_Pr->SiS_LVDSCRT11280x768_1    = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11280x768_1;
+-   SiS_Pr->SiS_LVDSCRT11024x600_1    = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11024x600_1;
+-   SiS_Pr->SiS_LVDSCRT11152x768_1    = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11152x768_1;
+    SiS_Pr->SiS_LVDSCRT11600x1200_1   = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11600x1200_1;
+    SiS_Pr->SiS_LVDSCRT1800x600_1_H   = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT1800x600_1_H;
+    SiS_Pr->SiS_LVDSCRT11024x768_1_H  = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11024x768_1_H;
+    SiS_Pr->SiS_LVDSCRT11280x1024_1_H = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11280x1024_1_H;
+    SiS_Pr->SiS_LVDSCRT11400x1050_1_H = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11400x1050_1_H;
+-   SiS_Pr->SiS_LVDSCRT11280x768_1_H  = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11280x768_1_H;
+-   SiS_Pr->SiS_LVDSCRT11024x600_1_H  = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11024x600_1_H;
+-   SiS_Pr->SiS_LVDSCRT11152x768_1_H  = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11152x768_1_H;
+    SiS_Pr->SiS_LVDSCRT11600x1200_1_H = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11600x1200_1_H;
+    SiS_Pr->SiS_LVDSCRT1800x600_2     = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT1800x600_2;
+    SiS_Pr->SiS_LVDSCRT11024x768_2    = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11024x768_2;
+    SiS_Pr->SiS_LVDSCRT11280x1024_2   = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11280x1024_2;
+    SiS_Pr->SiS_LVDSCRT11400x1050_2   = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11400x1050_2;
+-   SiS_Pr->SiS_LVDSCRT11280x768_2    = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11280x768_2;
+-   SiS_Pr->SiS_LVDSCRT11024x600_2    = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11024x600_2;
+-   SiS_Pr->SiS_LVDSCRT11152x768_2    = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11152x768_2;
+    SiS_Pr->SiS_LVDSCRT11600x1200_2   = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11600x1200_2;
+    SiS_Pr->SiS_LVDSCRT1800x600_2_H   = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT1800x600_2_H;
+    SiS_Pr->SiS_LVDSCRT11024x768_2_H  = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11024x768_2_H;
+    SiS_Pr->SiS_LVDSCRT11280x1024_2_H = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11280x1024_2_H;
+    SiS_Pr->SiS_LVDSCRT11400x1050_2_H = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11400x1050_2_H;
+-   SiS_Pr->SiS_LVDSCRT11280x768_2_H  = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11280x768_2_H;
+-   SiS_Pr->SiS_LVDSCRT11024x600_2_H  = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11024x600_2_H;
+-   SiS_Pr->SiS_LVDSCRT11152x768_2_H  = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11152x768_2_H;
+    SiS_Pr->SiS_LVDSCRT11600x1200_2_H = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11600x1200_2_H;
+-   SiS_Pr->SiS_LVDSCRT1XXXxXXX_1     = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT1XXXxXXX_1;
+-   SiS_Pr->SiS_LVDSCRT1XXXxXXX_1_H   = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT1XXXxXXX_1_H;
+-   SiS_Pr->SiS_LVDSCRT1320x480_1     = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT1320x480_1;
+-   SiS_Pr->SiS_CHTVCRT1UNTSC = (SiS_LVDSCRT1DataStruct *)SiS310_CHTVCRT1UNTSC;
+-   SiS_Pr->SiS_CHTVCRT1ONTSC = (SiS_LVDSCRT1DataStruct *)SiS310_CHTVCRT1ONTSC;
+-   SiS_Pr->SiS_CHTVCRT1UPAL  = (SiS_LVDSCRT1DataStruct *)SiS310_CHTVCRT1UPAL;
+-   SiS_Pr->SiS_CHTVCRT1OPAL  = (SiS_LVDSCRT1DataStruct *)SiS310_CHTVCRT1OPAL;
+-   SiS_Pr->SiS_CHTVCRT1SOPAL = (SiS_LVDSCRT1DataStruct *)SiS310_CHTVCRT1SOPAL;
++   SiS_Pr->SiS_CHTVCRT1UNTSC         = (SiS_LVDSCRT1DataStruct *)SiS310_CHTVCRT1UNTSC;
++   SiS_Pr->SiS_CHTVCRT1ONTSC         = (SiS_LVDSCRT1DataStruct *)SiS310_CHTVCRT1ONTSC;
++   SiS_Pr->SiS_CHTVCRT1UPAL          = (SiS_LVDSCRT1DataStruct *)SiS310_CHTVCRT1UPAL;
++   SiS_Pr->SiS_CHTVCRT1OPAL          = (SiS_LVDSCRT1DataStruct *)SiS310_CHTVCRT1OPAL;
++   SiS_Pr->SiS_CHTVCRT1SOPAL         = (SiS_LVDSCRT1DataStruct *)SiS310_CHTVCRT1SOPAL;
++
+    SiS_Pr->SiS_CHTVReg_UNTSC = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_UNTSC;
+    SiS_Pr->SiS_CHTVReg_ONTSC = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_ONTSC;
+    SiS_Pr->SiS_CHTVReg_UPAL  = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_UPAL;
+@@ -620,6 +614,7 @@ InitTo310Pointer(SiS_Private *SiS_Pr, PS
+    SiS_Pr->SiS_CHTVReg_UPALN = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_UPALN;
+    SiS_Pr->SiS_CHTVReg_OPALN = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_OPALN;
+    SiS_Pr->SiS_CHTVReg_SOPAL = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_SOPAL;
++
+    SiS_Pr->SiS_LCDACRT1800x600_1     = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT1800x600_1;
+    SiS_Pr->SiS_LCDACRT11024x768_1    = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11024x768_1;
+    SiS_Pr->SiS_LCDACRT11280x1024_1   = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11280x1024_1;
+@@ -640,6 +635,7 @@ InitTo310Pointer(SiS_Private *SiS_Pr, PS
+    SiS_Pr->SiS_LCDACRT11280x1024_2_H = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11280x1024_2_H;
+    SiS_Pr->SiS_LCDACRT11400x1050_2_H = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11400x1050_2_H;
+    SiS_Pr->SiS_LCDACRT11600x1200_2_H = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11600x1200_2_H;
++
+    SiS_Pr->SiS_CHTVVCLKUNTSC = SiS310_CHTVVCLKUNTSC;
+    SiS_Pr->SiS_CHTVVCLKONTSC = SiS310_CHTVVCLKONTSC;
+    SiS_Pr->SiS_CHTVVCLKUPAL  = SiS310_CHTVVCLKUPAL;
+@@ -662,9 +658,13 @@ InitTo310Pointer(SiS_Private *SiS_Pr, PS
+    SiS_Pr->SiS_Panel1152x864  = Panel_1152x864;
+    SiS_Pr->SiS_Panel1280x768  = Panel_1280x768;
+    SiS_Pr->SiS_Panel1024x600  = Panel_1024x600;
++   SiS_Pr->SiS_Panel640x480_2 = Panel_640x480_2;
++   SiS_Pr->SiS_Panel640x480_3 = Panel_640x480_3;
+    SiS_Pr->SiS_PanelMax       = Panel_320x480;    /* TW: highest value */
+    SiS_Pr->SiS_PanelMinLVDS   = Panel_800x600;    /* TW: lowest value LVDS/LCDA */
+    SiS_Pr->SiS_PanelMin301    = Panel_1024x768;   /* TW: lowest value 301 */
++   SiS_Pr->SiS_PanelCustom    = Panel_Custom;
++   SiS_Pr->SiS_PanelBarco1366 = 255;
+ }
+ #endif
+@@ -727,7 +727,9 @@ SiSInit(SiS_Private *SiS_Pr, PSIS_HW_DEV
+       (HwDeviceExtension->jChipType == SIS_550) ||
+       (HwDeviceExtension->jChipType == SIS_650) ||
+       (HwDeviceExtension->jChipType == SIS_740) ||
+-      (HwDeviceExtension->jChipType == SIS_330))
++      (HwDeviceExtension->jChipType == SIS_330) ||
++      (HwDeviceExtension->jChipType == SIS_660) ||
++      (HwDeviceExtension->jChipType == SIS_760))
+      InitTo310Pointer(SiS_Pr, HwDeviceExtension);
+ #endif
+@@ -896,7 +898,9 @@ SiSInit(SiS_Private *SiS_Pr, PSIS_HW_DEV
+       (HwDeviceExtension->jChipType == SIS_550) ||
+       (HwDeviceExtension->jChipType == SIS_650) ||
+       (HwDeviceExtension->jChipType == SIS_740) ||
+-      (HwDeviceExtension->jChipType == SIS_330)) {
++      (HwDeviceExtension->jChipType == SIS_330) ||
++      (HwDeviceExtension->jChipType == SIS_660) ||
++      (HwDeviceExtension->jChipType == SIS_760)) {
+       for(i=0x12; i<=0x1B; i++) SiS_SetReg1(SiS_Pr->SiS_P3c4,i,0);
+       for(i=0x79; i<=0x7C; i++) SiS_SetReg1(SiS_Pr->SiS_P3d4,i,0);
+    }
+@@ -953,14 +957,16 @@ SiSInit(SiS_Private *SiS_Pr, PSIS_HW_DEV
+    if((HwDeviceExtension->jChipType == SIS_315H)   ||
+       (HwDeviceExtension->jChipType == SIS_315)    ||
+       (HwDeviceExtension->jChipType == SIS_315PRO) ||
+-      (HwDeviceExtension->jChipType == SIS_330) ) {
++      (HwDeviceExtension->jChipType == SIS_330)) {
+               if((*SiS_Pr->pSiS_SoftSetting & SoftDRAMType) == 0) {
+               temp = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x3A) & 0x03;
+         }
+    }
+    if((HwDeviceExtension->jChipType == SIS_550) ||
+       (HwDeviceExtension->jChipType == SIS_740) ||
+-      (HwDeviceExtension->jChipType == SIS_650)) {
++      (HwDeviceExtension->jChipType == SIS_650) ||
++      (HwDeviceExtension->jChipType == SIS_660) ||
++      (HwDeviceExtension->jChipType == SIS_760)) {
+         if((*SiS_Pr->pSiS_SoftSetting & SoftDRAMType) == 0) {
+               temp = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13) & 0x07;
+         }
+@@ -977,7 +983,7 @@ SiSInit(SiS_Private *SiS_Pr, PSIS_HW_DEV
+    if((HwDeviceExtension->jChipType != SIS_540) &&
+       (HwDeviceExtension->jChipType != SIS_630) &&
+       (HwDeviceExtension->jChipType != SIS_730)){
+-      for(i=0x15;i<0x1C;i++) {
++      for(i=0x15; i<0x1C; i++) {
+                   SiS_SetReg1(SiS_Pr->SiS_P3c4,i,SiS_Pr->SiS_SR15[i-0x15][SiS_Pr->SiS_RAMType]);
+       }
+    }
+@@ -1023,7 +1029,9 @@ SiSInit(SiS_Private *SiS_Pr, PSIS_HW_DEV
+       (HwDeviceExtension->jChipType == SIS_550) ||
+       (HwDeviceExtension->jChipType == SIS_650) ||
+       (HwDeviceExtension->jChipType == SIS_740) ||
+-      (HwDeviceExtension->jChipType == SIS_330))
++      (HwDeviceExtension->jChipType == SIS_330) ||
++      (HwDeviceExtension->jChipType == SIS_660) ||
++      (HwDeviceExtension->jChipType == SIS_760))
+       SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2E,0x08);    /* use VB */
+ #endif
+@@ -1180,7 +1188,9 @@ SiS_Set_LVDS_TRUMPION(SiS_Private *SiS_P
+ #ifdef SIS315H
+   if((HwDeviceExtension->jChipType == SIS_650) ||
+      (HwDeviceExtension->jChipType == SIS_740) ||
+-     (HwDeviceExtension->jChipType == SIS_330)) {
++     (HwDeviceExtension->jChipType == SIS_330) ||
++     (HwDeviceExtension->jChipType == SIS_660) ||
++     (HwDeviceExtension->jChipType == SIS_760)) {
+ #if 0 /* TW: This is not required */
+         /* TW: Read POWER_ON_TRAP and copy to CR37 */
+       temp = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1A);
+@@ -1299,7 +1309,7 @@ SiS_ChkBUSWidth_300(SiS_Private *SiS_Pr,
+ #endif
+ /* ===============  SiS 300 dram sizing end    =============== */
+-/* ============  SiS 310/325 dram sizing begin  ============== */
++/* ============  SiS 315 dram sizing begin  ============== */
+ #ifdef SIS315H
+ /* TW: Moved Get310DRAMType further down */
+@@ -1893,8 +1903,7 @@ SiS_Get310DRAMType(SiS_Private *SiS_Pr, 
+    if(*SiS_Pr->pSiS_SoftSetting & SoftDRAMType) {
+      data = *SiS_Pr->pSiS_SoftSetting & 0x03;
+    } else {
+-     if((HwDeviceExtension->jChipType > SIS_315PRO) &&
+-        (HwDeviceExtension->jChipType < SIS_330)) {
++     if(IS_SIS550650740660) {
+         data = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13) & 0x07;
+      } else { /* TW: 315, 330 */
+         data = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x3a) & 0x03;
+@@ -1934,13 +1943,17 @@ void SiSRegInit(SiS_Private *SiS_Pr, USH
+    SiS_Pr->SiS_P3c7 = BaseAddr + 0x17;
+    SiS_Pr->SiS_P3c8 = BaseAddr + 0x18;
+    SiS_Pr->SiS_P3c9 = BaseAddr + 0x19;
+-   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_P3cb = BaseAddr + 0x1b;
++   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;
+ }
+ void
+@@ -1965,7 +1978,9 @@ SiSInitPCIetc(SiS_Private *SiS_Pr, PSIS_
+       (HwDeviceExtension->jChipType == SIS_550) ||
+       (HwDeviceExtension->jChipType == SIS_650) ||
+       (HwDeviceExtension->jChipType == SIS_740) ||
+-      (HwDeviceExtension->jChipType == SIS_330)) {
++      (HwDeviceExtension->jChipType == SIS_330) ||
++      (HwDeviceExtension->jChipType == SIS_660) ||
++      (HwDeviceExtension->jChipType == SIS_760)) {
+       /* TW: This seems to be done the same way on these chipsets */
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x20,0xa1);
+       SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x1E,0xFF,0x5A);
+@@ -1987,10 +2002,14 @@ SiSSetLVDSetc(SiS_Private *SiS_Pr, PSIS_
+    SiS_Pr->SiS_ChrontelInit = 0;
+-   if((ModeNo == 0x5a) || (ModeNo == 0x5b)) {
+-      SiS_Pr->SiS_IF_DEF_DSTN = 1;   /* for 550 dstn */
+-      SiS_Pr->SiS_IF_DEF_FSTN = 1;   /* for fstn */
++#if 0
++   if(HwDeviceExtension->jChipType >= SIS_315H) {
++      if((ModeNo == 0x5a) || (ModeNo == 0x5b)) {
++       SiS_Pr->SiS_IF_DEF_DSTN = 1;   /* for 550 dstn */
++       SiS_Pr->SiS_IF_DEF_FSTN = 1;   /* for fstn */
++      }
+    }
++#endif
+ #ifdef SIS300
+    if((HwDeviceExtension->jChipType == SIS_540) ||
+@@ -2015,11 +2034,15 @@ SiSSetLVDSetc(SiS_Private *SiS_Pr, PSIS_
+    if((HwDeviceExtension->jChipType == SIS_550) ||
+       (HwDeviceExtension->jChipType == SIS_650) ||
+       (HwDeviceExtension->jChipType == SIS_740) ||
+-      (HwDeviceExtension->jChipType == SIS_330))
++      (HwDeviceExtension->jChipType == SIS_330) ||
++      (HwDeviceExtension->jChipType == SIS_660) ||
++      (HwDeviceExtension->jChipType == SIS_760))
+     {
+-        /* TW: CR37 is different on 310/325 series */
++        /* TW: CR37 is different on 315 series */
++#if 0
+         if(SiS_Pr->SiS_IF_DEF_FSTN)                       /* fstn: set CR37=0x04 */
+              SiS_SetReg1(SiS_Pr->SiS_P3d4,0x37,0x04);      /* (fake LVDS bridge) */
++#endif
+       temp=SiS_GetReg1(SiS_Pr->SiS_P3d4,0x37);
+               temp = (temp & 0x0E) >> 1;
+@@ -2044,7 +2067,9 @@ SiSInitPtr(SiS_Private *SiS_Pr, PSIS_HW_
+       (HwDeviceExtension->jChipType == SIS_550) ||
+       (HwDeviceExtension->jChipType == SIS_650) ||
+       (HwDeviceExtension->jChipType == SIS_740) ||
+-      (HwDeviceExtension->jChipType == SIS_330))
++      (HwDeviceExtension->jChipType == SIS_330) ||
++      (HwDeviceExtension->jChipType == SIS_660) ||
++      (HwDeviceExtension->jChipType == SIS_760))
+      InitTo310Pointer(SiS_Pr, HwDeviceExtension);
+ #endif
+@@ -2073,14 +2098,21 @@ SiSDetermineROMUsage(SiS_Private *SiS_Pr
+             SiS_Pr->SiS_UseROM = TRUE;
+        else SiS_Pr->SiS_UseROM = FALSE;
+      } else if(HwDeviceExtension->jChipType < SIS_315H) {
++#if 0
+         /* TW: Rest of 300 series: We don't use the ROM image if
+        *     the BIOS version < 2.0.0 as such old BIOSes don't
+        *     have the needed data at the expected locations.
+        */
+         if(ROMAddr[0x06] < '2')  SiS_Pr->SiS_UseROM = FALSE;
+       else                     SiS_Pr->SiS_UseROM = TRUE;
++#else
++      /* Sony's VAIO BIOS 1.09 follows the standard, so perhaps
++       * the others do as well
++       */
++      SiS_Pr->SiS_UseROM = TRUE;
++#endif
+      } else {
+-        /* TW: 310/325/330 series stick to the standard */
++        /* TW: 315/330 series stick to the standard */
+       SiS_Pr->SiS_UseROM = TRUE;
+      }
+    } else SiS_Pr->SiS_UseROM = FALSE;
+@@ -2104,24 +2136,27 @@ SiSBIOSSetMode(SiS_Private *SiS_Pr, PSIS
+    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->CVDisplay);
+-              
++
++         xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "Setting custom mode %dx%d\n",
++              SiS_Pr->CHDisplay,
++              (mode->Flags & V_INTERLACE ? SiS_Pr->CVDisplay * 2 :
++                 (mode->Flags & V_DBLSCAN ? SiS_Pr->CVDisplay / 2 :
++                    SiS_Pr->CVDisplay)));
++
+        return(SiSSetMode(SiS_Pr, HwDeviceExtension, pScrn, ModeNo, TRUE));
+-   
++
+    }
+-   
+-   ModeNo = SiS_CalcModeIndex(pScrn, mode);
++
++   ModeNo = SiS_CalcModeIndex(pScrn, mode, pSiS->HaveCustomModes);
+    if(!ModeNo) return FALSE;
+-   xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "Setting mode 0x%x\n", ModeNo);
++   xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "Setting standard mode 0x%x\n", ModeNo);
+-   return(SiSSetMode(SiS_Pr, HwDeviceExtension, pScrn, ModeNo, TRUE));   
++   return(SiSSetMode(SiS_Pr, HwDeviceExtension, pScrn, ModeNo, TRUE));
+ }
+ #ifdef SISDUALHEAD
+-/* TW: Set CRT1 mode (used for dual head) */
++/* TW: Set CRT1 mode (used for dual head and MergedFB) */
+ BOOLEAN
+ SiSBIOSSetModeCRT1(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, ScrnInfoPtr pScrn,
+                DisplayModePtr mode, BOOLEAN IsCustom)
+@@ -2134,31 +2169,37 @@ SiSBIOSSetModeCRT1(SiS_Private *SiS_Pr, 
+    SISEntPtr pSiSEnt = pSiS->entityPrivate;
+    unsigned char backupreg=0;
+    BOOLEAN backupcustom;
+-
+    UShort  ModeNo=0;
+    
+    SiS_Pr->UseCustomMode = FALSE;
+-   
++
+    if((IsCustom) && (SiS_CheckBuildCustomMode(pScrn, mode, pSiS->VBFlags))) {
+-   
++
++         USHORT temptemp = SiS_Pr->CVDisplay;
++
++         if(SiS_Pr->CModeFlag & DoubleScanMode)     temptemp >>= 1;
++         else if(SiS_Pr->CInfoFlag & InterlaceMode) temptemp <<= 1;
++
+          xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
+-              "Setting custom mode %dx%d in CRT1\n", 
+-              SiS_Pr->CHDisplay, SiS_Pr->CVDisplay);
++              "Setting custom mode %dx%d on CRT1\n",
++              SiS_Pr->CHDisplay, temptemp);
+        ModeNo = 0xfe;
+-       
++
+    } else {
+-         ModeNo = SiS_CalcModeIndex(pScrn, mode);
++         ModeNo = SiS_CalcModeIndex(pScrn, mode, pSiS->HaveCustomModes);
+          if(!ModeNo) return FALSE;
+          xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
+-              "Setting mode 0x%x on CRT1\n", ModeNo);
++              "Setting standard mode 0x%x on CRT1\n", ModeNo);
+    }
+    SiSInitPtr(SiS_Pr, HwDeviceExtension);
+    SiSRegInit(SiS_Pr, BaseAddr);
++   SiS_GetSysFlags(SiS_Pr, HwDeviceExtension);
++
+    SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff);
+    SiSInitPCIetc(SiS_Pr, HwDeviceExtension);
+@@ -2167,7 +2208,7 @@ SiSBIOSSetModeCRT1(SiS_Private *SiS_Pr, 
+    SiSDetermineROMUsage(SiS_Pr, HwDeviceExtension, ROMAddr);
+-   /* TW: We don't clear the buffer under X */
++   /* We don't clear the buffer under X */
+    SiS_Pr->SiS_flag_clearbuffer = 0;
+    /* 1.Openkey */
+@@ -2175,8 +2216,8 @@ SiSBIOSSetModeCRT1(SiS_Private *SiS_Pr, 
+    SiS_UnLockCRT2(SiS_Pr, HwDeviceExtension, BaseAddr);
++   /* 2.Get ModeID Table  */
+    if(!SiS_Pr->UseCustomMode) {
+-      /* 2.Get ModeID Table  */
+       temp = SiS_SearchModeID(SiS_Pr, ROMAddr,&ModeNo,&ModeIdIndex);
+       if(temp == 0)  return(0);
+    } else {
+@@ -2201,53 +2242,65 @@ SiSBIOSSetModeCRT1(SiS_Private *SiS_Pr, 
+    SiS_GetLCDResInfo(SiS_Pr, ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);
+    if(HwDeviceExtension->jChipType >= SIS_315H) {
+-      if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+-         if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x17) & 0x08)  {
++      if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x17) & 0x08)  {
++         if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+             if(ModeNo != 0x10)  SiS_Pr->SiS_SetFlag |= SetDOSMode;
++         } else if((IS_SIS651) && (SiS_Pr->SiS_VBType & VB_NoLCD)) {
++            SiS_Pr->SiS_SetFlag |= SetDOSMode;
+          }
+       }
+-      /* TW: New from 650/LV 1.10.6x */
+       if(IS_SIS650) {
+-          if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+-            SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x51,0x1f);
+-            SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x56,0xe7);
+-        }
++         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);
++       }
+       }
+    }
+-   /* TW: Set mode on CRT1 */
++   /* Set mode on CRT1 */
+    SiS_SetCRT1Group(SiS_Pr, ROMAddr,HwDeviceExtension,ModeNo,ModeIdIndex,BaseAddr);
+-   pSiSEnt->CRT1ModeNo = ModeNo;
+-   pSiSEnt->CRT1DMode = mode;
+-
+-   /* TW: SetPitch: Adapt to virtual size & position */
++   /* SetPitch: Adapt to virtual size & position */
+    SiS_SetPitchCRT1(SiS_Pr, pScrn, BaseAddr);
++   if(pSiS->DualHeadMode) {
++      pSiSEnt->CRT1ModeNo = ModeNo;
++      pSiSEnt->CRT1DMode = mode;
++   }
++
++   if(SiS_Pr->UseCustomMode) {
++      SiS_Pr->CRT1UsesCustomMode = TRUE;
++      SiS_Pr->CSRClock_CRT1 = SiS_Pr->CSRClock;
++      SiS_Pr->CModeFlag_CRT1 = SiS_Pr->CModeFlag;
++   } else {
++      SiS_Pr->CRT1UsesCustomMode = FALSE;
++   }
++
+    /* We have to reset CRT2 if changing mode on CRT1 */
+-   if(pSiSEnt->CRT2ModeNo != -1) {
+-        xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
+-                              "(Re-)Setting mode 0x%x on CRT2\n",
+-                              pSiSEnt->CRT2ModeNo);
+-      backupcustom = SiS_Pr->UseCustomMode;
+-      if(SiS_Pr->UseCustomMode) {
+-         SiS_Pr->CRT1UsesCustomMode = TRUE;
+-      } else {
+-         SiS_Pr->CRT1UsesCustomMode = FALSE;
+-      }
+-      SiSBIOSSetModeCRT2(SiS_Pr, HwDeviceExtension, pSiSEnt->pScrn_1,
+-                              pSiSEnt->CRT2DMode);
+-      SiS_Pr->UseCustomMode = backupcustom;
+-      SiS_Pr->CRT1UsesCustomMode = FALSE;
++   if(pSiS->DualHeadMode) {
++      if(pSiSEnt->CRT2ModeNo != -1) {
++         xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
++                              "(Re-)Setting mode for CRT2\n");
++       backupcustom = SiS_Pr->UseCustomMode;
++       SiSBIOSSetModeCRT2(SiS_Pr, HwDeviceExtension, pSiSEnt->pScrn_1,
++                          pSiSEnt->CRT2DMode, pSiSEnt->CRT2IsCustom);
++       SiS_Pr->UseCustomMode = backupcustom;
++      }
+    }
+-   
++
++   /* Warning: From here, the custom mode entries in SiS_Pr are
++    * possibly overwritten
++    */
++
+    SiS_HandleCRT1(SiS_Pr);
++   SiS_StrangeStuff(SiS_Pr, HwDeviceExtension);
++
+    SiS_DisplayOn(SiS_Pr);
+    SiS_SetReg3(SiS_Pr->SiS_P3c6,0xFF);
+-   /* TW: New from 650/LV 1.10.6x and 1.10.7w, 630/301B 2.06.50 */
+    if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+       if(HwDeviceExtension->jChipType >= SIS_315H) {
+        SiS_SetReg1(SiS_Pr->SiS_P3d4,0x38,backupreg);
+@@ -2266,7 +2319,7 @@ SiSBIOSSetModeCRT1(SiS_Private *SiS_Pr, 
+ /* TW: Set CRT2 mode (used for dual head) */
+ BOOLEAN
+ SiSBIOSSetModeCRT2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, ScrnInfoPtr pScrn,
+-               DisplayModePtr mode)
++               DisplayModePtr mode, BOOLEAN IsCustom)
+ {
+    ULONG   temp;
+    USHORT  ModeIdIndex;
+@@ -2276,16 +2329,52 @@ SiSBIOSSetModeCRT2(SiS_Private *SiS_Pr, 
+    SISPtr  pSiS     = SISPTR(pScrn);
+    SISEntPtr pSiSEnt = pSiS->entityPrivate;
+    unsigned char tempr1, tempr2, backupreg=0;
+-   
++
+    SiS_Pr->UseCustomMode = FALSE;
+-   
+-   ModeNo = SiS_CalcModeIndex(pScrn, mode);
+-   if(!ModeNo) return FALSE;
++
++   /* Remember: Custom modes for CRT2 are ONLY supported
++    *                 -) on 315/330 series,
++    *           -) on the 301 and 30xB, and
++    *           -) if CRT2 is LCD or VGA
++    */
++
++   if((IsCustom) && (SiS_CheckBuildCustomMode(pScrn, mode, pSiS->VBFlags))) {
++
++       ModeNo = 0xfe;
++
++   } else {
++
++         BOOLEAN havecustommodes = pSiS->HaveCustomModes;
++
++#ifdef SISMERGED
++       if(pSiS->MergedFB) havecustommodes = pSiS->HaveCustomModes2;
++#endif
++
++         ModeNo = SiS_CalcModeIndex(pScrn, mode, havecustommodes);
++         if(!ModeNo) return FALSE;
++
++   }
++
++   /* Save mode info so we can set it from within SetMode for CRT1 */
++   if(pSiS->DualHeadMode) {
++      pSiSEnt->CRT2ModeNo = ModeNo;
++      pSiSEnt->CRT2DMode = mode;
++      pSiSEnt->CRT2IsCustom = IsCustom;
++
++      /* We can't set CRT2 mode before CRT1 mode is set */
++      if(pSiSEnt->CRT1ModeNo == -1) {
++       xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
++              "Setting CRT2 mode delayed until after setting CRT1 mode\n");
++       return TRUE;
++      }
++   }
+    SiSInitPtr(SiS_Pr, HwDeviceExtension);
+    SiSRegInit(SiS_Pr, BaseAddr);
++   SiS_GetSysFlags(SiS_Pr, HwDeviceExtension);
++
+    SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff);
+    SiSInitPCIetc(SiS_Pr, HwDeviceExtension);
+@@ -2294,22 +2383,26 @@ SiSBIOSSetModeCRT2(SiS_Private *SiS_Pr, 
+    SiSDetermineROMUsage(SiS_Pr, HwDeviceExtension, ROMAddr);
+-   /* TW: We don't clear the buffer under X */
++   /* We don't clear the buffer under X */
+    SiS_Pr->SiS_flag_clearbuffer=0;
+-   /* TW: Save ModeNo so we can set it from within SetMode for CRT1 */
+-   pSiSEnt->CRT2ModeNo = ModeNo;
+-   pSiSEnt->CRT2DMode = mode;
+-
+-   /* TW: We can't set CRT2 mode before CRT1 mode is set */
+-   if(pSiSEnt->CRT1ModeNo == -1) {
+-      xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
+-              "Setting CRT2 mode delayed until after setting CRT1 mode\n");
+-      return TRUE;
+-   }
++   if(SiS_Pr->UseCustomMode) {
++
++      USHORT temptemp = SiS_Pr->CVDisplay;
++
++      if(SiS_Pr->CModeFlag & DoubleScanMode)     temptemp >>= 1;
++      else if(SiS_Pr->CInfoFlag & InterlaceMode) temptemp <<= 1;
++
++      xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
++        "Setting custom mode %dx%d on CRT2\n",
++        SiS_Pr->CHDisplay, temptemp);
+-   xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
+-              "Setting mode 0x%x on CRT2\n", ModeNo);
++   } else {
++
++      xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
++        "Setting standard mode 0x%x on CRT2\n", ModeNo);
++
++   }
+    /* 1.Openkey */
+    SiS_SetReg1(SiS_Pr->SiS_P3c4,0x05,0x86);
+@@ -2317,10 +2410,14 @@ SiSBIOSSetModeCRT2(SiS_Private *SiS_Pr, 
+    SiS_UnLockCRT2(SiS_Pr, HwDeviceExtension, BaseAddr);
+    /* 2.Get ModeID */
+-   temp = SiS_SearchModeID(SiS_Pr, ROMAddr,&ModeNo,&ModeIdIndex);
+-   if(temp == 0)  return(0);
++   if(!SiS_Pr->UseCustomMode) {
++      temp = SiS_SearchModeID(SiS_Pr, ROMAddr,&ModeNo,&ModeIdIndex);
++      if(temp == 0)  return(0);
++   } else {
++      ModeIdIndex = 0;
++   }
+-   /* TW: Determine VBType (301,301B,301LV,302B,302LV) */
++   /* Determine VBType (301,301B,301LV,302B,302LV) */
+    SiS_GetVBType(SiS_Pr, BaseAddr,HwDeviceExtension);
+    if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+@@ -2343,15 +2440,22 @@ SiSBIOSSetModeCRT2(SiS_Private *SiS_Pr, 
+       }
+    }
+-   /* TW: Get VB information (connectors, connected devices) */
+-   SiS_GetVBInfo(SiS_Pr, BaseAddr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension,1);
++   /* Get VB information (connectors, connected devices) */
++   if(!SiS_Pr->UseCustomMode) {
++      SiS_GetVBInfo(SiS_Pr, BaseAddr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension,1);
++   } else {
++      /* If this is a custom mode, we don't check the modeflag for CRT2Mode */
++      SiS_GetVBInfo(SiS_Pr, BaseAddr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension,0);
++   }
+    SiS_SetHiVision(SiS_Pr, BaseAddr,HwDeviceExtension);
+    SiS_GetLCDResInfo(SiS_Pr, ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);
+    if(HwDeviceExtension->jChipType >= SIS_315H) {
+-      if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+-         if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x17) & 0x08)  {
++      if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x17) & 0x08)  {
++         if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+             if(ModeNo != 0x10)  SiS_Pr->SiS_SetFlag |= SetDOSMode;
++         } else if((IS_SIS651) && (SiS_Pr->SiS_VBType & VB_NoLCD)) {
++            SiS_Pr->SiS_SetFlag |= SetDOSMode;
+          }
+       }
+    }
+@@ -2364,17 +2468,19 @@ SiSBIOSSetModeCRT2(SiS_Private *SiS_Pr, 
+      case VB_CHIP_302:
+      case VB_CHIP_302B:
+      case VB_CHIP_302LV:
+-        SiS_SetCRT2Group301(SiS_Pr, BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);
++        SiS_SetCRT2Group(SiS_Pr, BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);
+         break;
+      case VB_CHIP_UNKNOWN:
+-        if (SiS_Pr->SiS_IF_DEF_LVDS     == 1 ||
+-          SiS_Pr->SiS_IF_DEF_CH70xx   != 0 ||
+-          SiS_Pr->SiS_IF_DEF_TRUMPION != 0) {
+-              SiS_SetCRT2Group301(SiS_Pr,BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);
++        if(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,BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);
+       }
+         break;
+    }
++   SiS_StrangeStuff(SiS_Pr, HwDeviceExtension);
++
+    SiS_DisplayOn(SiS_Pr);
+    SiS_SetReg3(SiS_Pr->SiS_P3c6,0xFF);
+@@ -2386,7 +2492,6 @@ SiSBIOSSetModeCRT2(SiS_Private *SiS_Pr, 
+       }
+    }
+-   /* TW: New from 650/LV 1.10.6x and 1.10.7w, 630 2.06.50 */
+    if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+       if(HwDeviceExtension->jChipType >= SIS_315H) {
+        if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+@@ -2412,7 +2517,7 @@ SiSBIOSSetModeCRT2(SiS_Private *SiS_Pr, 
+       }
+    }
+-   /* TW: SetPitch: Adapt to virtual size & position */
++   /* SetPitch: Adapt to virtual size & position */
+    SiS_SetPitchCRT2(SiS_Pr, pScrn, BaseAddr);
+    return TRUE;
+@@ -2442,12 +2547,14 @@ SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_
+    
+    if(SiS_Pr->UseCustomMode) {
+       ModeNo = 0xfe;
+-   }      
+-   
++   }
++
+    SiSInitPtr(SiS_Pr, HwDeviceExtension);
+    SiSRegInit(SiS_Pr, BaseAddr);
++   SiS_GetSysFlags(SiS_Pr, HwDeviceExtension);
++
+ #ifdef LINUX_XF86
+    if(pScrn) SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff);
+    else
+@@ -2458,7 +2565,7 @@ SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_
+ #ifdef TWDEBUG
+    xf86DrvMsg(0, X_INFO, "VGAInfo 0x%02x\n", SiS_Pr->SiS_VGAINFO);
+ #endif
+-#endif                 
++#endif
+    SiSInitPCIetc(SiS_Pr, HwDeviceExtension);
+@@ -2469,10 +2576,10 @@ SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_
+    if(!SiS_Pr->UseCustomMode) {
+       /* TW: Shift the clear-buffer-bit away */
+       ModeNo = ((ModeNo & 0x80) << 8) | (ModeNo & 0x7f);
+-   }      
++   }
+ #ifdef LINUX_XF86
+-   /* TW: We never clear the buffer in X */
++   /* We never clear the buffer in X */
+    ModeNo |= 0x8000;
+ #endif
+@@ -2490,21 +2597,21 @@ SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_
+    SiS_UnLockCRT2(SiS_Pr, HwDeviceExtension, BaseAddr);
+    if(!SiS_Pr->UseCustomMode) {
+-   
++
+       /* 2.Get ModeID Table  */
+       temp = SiS_SearchModeID(SiS_Pr,ROMAddr,&ModeNo,&ModeIdIndex);
+       if(temp == 0) return(0);
+-      
++
+    } else {
+-   
++
+       ModeIdIndex = 0;
+-      
++
+    }
+-    
+-   /* TW: Determine VBType (301,301B,301LV,302B,302LV) */
++
++   /* Determine VBType (301,301B,301LV,302B,302LV) */
+    SiS_GetVBType(SiS_Pr,BaseAddr,HwDeviceExtension);
+-   /* TW: Init/restore some VB registers */
++   /* Init/restore some VB registers */
+    if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+        if(HwDeviceExtension->jChipType >= SIS_315H) {
+          SiS_UnLockCRT2(SiS_Pr,HwDeviceExtension,BaseAddr);
+@@ -2525,8 +2632,12 @@ SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_
+        }
+    }
+    
+-   /* TW: Get VB information (connectors, connected devices) */
+-   SiS_GetVBInfo(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension,1);
++   /* Get VB information (connectors, connected devices) */
++   if(SiS_Pr->UseCustomMode) {
++      SiS_GetVBInfo(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension,0);
++   } else {
++      SiS_GetVBInfo(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension,1);
++   }
+    SiS_SetHiVision(SiS_Pr,BaseAddr,HwDeviceExtension);
+    SiS_GetLCDResInfo(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);
+@@ -2535,22 +2646,32 @@ SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_
+    if(!temp) return(0);
+    if(HwDeviceExtension->jChipType >= SIS_315H) {
+-      if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+-         if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x17) & 0x08)  {
++      if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x17) & 0x08)  {
++         if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+             if(ModeNo != 0x10)  SiS_Pr->SiS_SetFlag |= SetDOSMode;
++         } else if((IS_SIS651) && (SiS_Pr->SiS_VBType & VB_NoLCD)) {
++            SiS_Pr->SiS_SetFlag |= SetDOSMode;
+          }
+       }
+-      /* TW: New from 650/LV 1.10.6x; not in any BIOS for other chipsets */
+       if(IS_SIS650) {
+-          if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+-            SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x51,0x1f);
+-            SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x56,0xe7);
+-        }
++         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);
++       }
+       }
+    }
+-   /* TW: Set mode on CRT1 */
++   if(SiS_Pr->UseCustomMode) {
++      SiS_Pr->CRT1UsesCustomMode = TRUE;
++      SiS_Pr->CSRClock_CRT1 = SiS_Pr->CSRClock;
++      SiS_Pr->CModeFlag_CRT1 = SiS_Pr->CModeFlag;
++   } else {
++      SiS_Pr->CRT1UsesCustomMode = FALSE;
++   }
++
++   /* Set mode on CRT1 */
+    if(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SetCRT2ToLCDA)) {
+       SiS_SetCRT1Group(SiS_Pr,ROMAddr,HwDeviceExtension,ModeNo,ModeIdIndex,BaseAddr);
+    } else {
+@@ -2559,7 +2680,7 @@ SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_
+      }
+    }
+-   /* TW: Set mode on CRT2 */
++   /* Set mode on CRT2 */
+    if(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchToCRT2 | SetCRT2ToLCDA)) {
+      switch (HwDeviceExtension->ujVBChipID) {
+      case VB_CHIP_301:
+@@ -2568,18 +2689,20 @@ SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_
+      case VB_CHIP_302:
+      case VB_CHIP_302B:
+      case VB_CHIP_302LV:
+-        SiS_SetCRT2Group301(SiS_Pr,BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);
++        SiS_SetCRT2Group(SiS_Pr,BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);
+         break;
+      case VB_CHIP_UNKNOWN:
+       if(SiS_Pr->SiS_IF_DEF_LVDS     == 1 ||
+          SiS_Pr->SiS_IF_DEF_CH70xx   != 0 ||
+          SiS_Pr->SiS_IF_DEF_TRUMPION != 0)
+-              SiS_SetCRT2Group301(SiS_Pr,BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);
++           SiS_SetCRT2Group(SiS_Pr,BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);
+         break;
+      }
+    }
+    
+    SiS_HandleCRT1(SiS_Pr);
++
++   SiS_StrangeStuff(SiS_Pr, HwDeviceExtension);
+    
+    SiS_DisplayOn(SiS_Pr);
+    SiS_SetReg3(SiS_Pr->SiS_P3c6,0xFF);
+@@ -2592,7 +2715,6 @@ SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_
+       }
+    }
+-   /* TW: New from 650/LV 1.10.6x and 1.10.7w */
+    if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+       if(HwDeviceExtension->jChipType >= SIS_315H) {
+        if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+@@ -2627,7 +2749,7 @@ SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_
+ #ifdef LINUX_XF86
+    if(pScrn) {
+-      /* TW: SetPitch: Adapt to virtual size & position */
++      /* SetPitch: Adapt to virtual size & position */
+       if((ModeNo > 0x13) && (dosetpitch)) {
+          SiS_SetPitch(SiS_Pr, pScrn, BaseAddr);
+       }
+@@ -2637,7 +2759,7 @@ SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_
+    }
+ #endif
+-#ifndef LINUX_XF86  /* TW: We never lock registers in XF86 */
++#ifndef LINUX_XF86  /* We never lock registers in XF86 */
+    if(KeepLockReg == 0xA1) SiS_SetReg1(SiS_Pr->SiS_P3c4,0x05,0x86);
+    else SiS_SetReg1(SiS_Pr->SiS_P3c4,0x05,0x00);
+ #endif
+@@ -2646,10 +2768,15 @@ SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_
+ }
+ void
+-SiS_SetEnableDstn(SiS_Private *SiS_Pr)        /* TW: Called from sis_main.c */
++SiS_SetEnableDstn(SiS_Private *SiS_Pr, int enable)
++{
++   SiS_Pr->SiS_IF_DEF_DSTN = enable ? 1 : 0;
++}
++
++void
++SiS_SetEnableFstn(SiS_Private *SiS_Pr, int enable)
+ {
+-   /* For 550 dstn */
+-   SiS_Pr->SiS_IF_DEF_DSTN = 1;
++   SiS_Pr->SiS_IF_DEF_FSTN = enable ? 1 : 0;
+ }
+ void
+@@ -2663,13 +2790,73 @@ SiS_HandleCRT1(SiS_Private *SiS_Pr)
+   SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x63,0xbf);
+ #if 0
+-  if(!(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x15) & 0x01))
+-     SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x63,0x40);
++  if(!(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x15) & 0x01)) {
++     if((SiS_GetReg1(SiS_Pr->SiS_P3c4,0x15) & 0x0a) ||
++        (SiS_GetReg1(SiS_Pr->SiS_P3c4,0x16) & 0x01)) {
++        SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x63,0x40);
++     }
+   }
+ #endif
+ }
+ void
++SiS_GetSysFlags(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
++{
++   unsigned char cr5f, temp1, temp2;
++
++   /* You should use the macros, not these flags directly */
++
++   SiS_Pr->SiS_SysFlags = 0;
++   if(HwDeviceExtension->jChipType == SIS_650) {
++      cr5f = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x5f) & 0xf0;
++      SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x5c,0x07);
++      temp1 = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x5c) & 0xf8;
++      SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x5c,0xf8);
++      temp2 = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x5c) & 0xf8;
++      if((!temp1) || (temp2)) {
++         switch(cr5f) {
++          case 0x80:
++          case 0x90:
++          case 0xc0:
++             SiS_Pr->SiS_SysFlags |= SF_IsM650;  break;
++          case 0xa0:
++          case 0xb0:
++          case 0xe0:
++             SiS_Pr->SiS_SysFlags |= SF_Is651;   break;
++       }
++      } else {
++         switch(cr5f) {
++          case 0x90:
++             temp1 = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x5c) & 0xf8;
++             switch(temp1) {
++                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;
++          default:
++             SiS_Pr->SiS_SysFlags |= SF_IsM650; break;
++       }
++      }
++   }
++}
++
++void
++SiS_StrangeStuff(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
++{
++   if((IS_SIS651) || (IS_SISM650)) {
++      SiS_SetReg1(SiS_Pr->SiS_VidCapt, 0x3f, 0x00);   /* Fiddle with capture regs */
++      SiS_SetReg1(SiS_Pr->SiS_VidCapt, 0x00, 0x00);
++      SiS_SetReg1(SiS_Pr->SiS_VidPlay, 0x00, 0x86);   /* (BIOS does NOT unlock) */
++      SiS_SetRegAND(SiS_Pr->SiS_VidPlay, 0x30, 0xfe); /* Fiddle with video regs */
++      SiS_SetRegAND(SiS_Pr->SiS_VidPlay, 0x3f, 0xef);
++   }
++   /* !!! This does not support modes < 0x13 !!! */
++}
++
++void
+ SiS_SetCRT1Group(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                  USHORT ModeNo,USHORT ModeIdIndex,USHORT BaseAddr)
+ {
+@@ -2683,6 +2870,9 @@ SiS_SetCRT1Group(SiS_Private *SiS_Pr, UC
+     }
+   }
++  /* 550, 651 */
++  SiS_WhatTheHellIsThis(SiS_Pr,HwDeviceExtension,BaseAddr);
++
+   SiS_SetSeqRegs(SiS_Pr,ROMAddr,StandTableIndex);
+   SiS_SetMiscRegs(SiS_Pr,ROMAddr,StandTableIndex);
+   SiS_SetCRTCRegs(SiS_Pr,ROMAddr,HwDeviceExtension,StandTableIndex);
+@@ -2759,15 +2949,20 @@ void
+ SiS_SetPitch(SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, UShort BaseAddr)
+ {
+    SISPtr pSiS = SISPTR(pScrn);
++   BOOLEAN isslavemode = FALSE;
++
++   if( (pSiS->VBFlags & VB_VIDEOBRIDGE) &&
++       ( ((pSiS->VGAEngine == SIS_300_VGA) && (SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00) & 0xa0) == 0x20) ||
++         ((pSiS->VGAEngine == SIS_315_VGA) && (SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00) & 0x50) == 0x10) ) ) {
++      isslavemode = TRUE;
++   }
+-   /* TW: We need to set pitch for CRT1 if bridge is in SlaveMode, too */
+-   if( (pSiS->VBFlags & DISPTYPE_DISP1) ||
+-       ( (pSiS->VBFlags & VB_VIDEOBRIDGE) &&
+-         ( ((pSiS->VGAEngine == SIS_300_VGA) && (SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00) & 0xa0) == 0x20) ||
+-           ((pSiS->VGAEngine == SIS_315_VGA) && (SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00) & 0x50) == 0x10) ) ) ) {
++   /* We need to set pitch for CRT1 if bridge is in slave mode, too */
++   if( (pSiS->VBFlags & DISPTYPE_DISP1) || (isslavemode) ) {
+       SiS_SetPitchCRT1(SiS_Pr, pScrn, BaseAddr);
+    }
+-   if (pSiS->VBFlags & DISPTYPE_DISP2) {
++   /* We must not set the pitch for CRT2 if bridge is in slave mode */
++   if( (pSiS->VBFlags & DISPTYPE_DISP2) && (!isslavemode) ) {
+       SiS_SetPitchCRT2(SiS_Pr, pScrn, BaseAddr);
+    }
+ }
+@@ -2790,7 +2985,7 @@ SiS_SetPitchCRT2(SiS_Private *SiS_Pr, Sc
+     SISPtr pSiS = SISPTR(pScrn);
+     ULong  HDisplay,temp;
+-    HDisplay = pSiS->scrnPitch / 8;
++    HDisplay = pSiS->scrnPitch2 / 8;
+     /* Unlock CRT2 */
+     if (pSiS->VGAEngine == SIS_315_VGA)
+@@ -2880,7 +3075,6 @@ SiS_SearchModeID(SiS_Private *SiS_Pr, UC
+    return TRUE;
+ }
+-/* For SiS 300 oem util: Search VBModeID */
+ BOOLEAN
+ SiS_SearchVBModeID(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT *ModeNo)
+ {
+@@ -2946,6 +3140,81 @@ SiS_GetModePtr(SiS_Private *SiS_Pr, UCHA
+    return index;
+ }
++static void
++SiS_WhatIsThis1a(SiS_Private *SiS_Pr, USHORT somevalue)
++{
++   USHORT temp, tempbl, tempbh;
++
++   tempbl = tempbh = somevalue;
++   temp = SiS_GetReg2(SiS_Pr->SiS_P3cb);
++   temp &= 0xf0;
++   tempbl >>= 4;
++   temp |= tempbl;
++   SiS_SetReg3(SiS_Pr->SiS_P3cb, temp);
++   temp = SiS_GetReg2(SiS_Pr->SiS_P3cd);
++   temp &= 0xf0;
++   tempbh &= 0x0f;
++   temp |= tempbh;
++   SiS_SetReg3(SiS_Pr->SiS_P3cd, temp);
++}
++
++static void
++SiS_WhatIsThis1b(SiS_Private *SiS_Pr, USHORT somevalue)
++{
++   USHORT temp, tempbl, tempbh;
++
++   tempbl = tempbh = somevalue;
++   temp = SiS_GetReg2(SiS_Pr->SiS_P3cb);
++   temp &= 0x0f;
++   tempbl &= 0xf0;
++   temp |= tempbl;
++   SiS_SetReg3(SiS_Pr->SiS_P3cb, temp);
++   temp = SiS_GetReg2(SiS_Pr->SiS_P3cd);
++   temp &= 0x0f;
++   tempbh <<= 4;
++   temp |= tempbh;
++   SiS_SetReg3(SiS_Pr->SiS_P3cd, temp);
++}
++
++static void
++SiS_WhatIsThis2b(SiS_Private *SiS_Pr, USHORT somevalue)
++{
++   SiS_WhatIsThis1a(SiS_Pr, somevalue);
++   SiS_WhatIsThis1b(SiS_Pr, somevalue);
++}
++
++static void
++SiS_WhatIsThis1(SiS_Private *SiS_Pr)
++{
++   SiS_WhatIsThis2b(SiS_Pr, 0);
++}
++
++static void
++SiS_WhatIsThis2a(SiS_Private *SiS_Pr, USHORT somevalue)
++{
++   USHORT temp = somevalue >> 8;
++
++   temp &= 0x07;
++   temp |= (temp << 4);
++   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x1d,temp);
++   SiS_WhatIsThis2b(SiS_Pr, somevalue);
++}
++
++static void
++SiS_WhatIsThis2(SiS_Private *SiS_Pr)
++{
++   SiS_WhatIsThis2a(SiS_Pr, 0);
++}
++
++void
++SiS_WhatTheHellIsThis(SiS_Private *SiS_Pr,PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr)
++{
++   if(IS_SIS65x) {
++      SiS_WhatIsThis1(SiS_Pr);
++      SiS_WhatIsThis2(SiS_Pr);
++   }
++}
++
+ void
+ SiS_SetSeqRegs(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT StandTableIndex)
+ {
+@@ -3027,7 +3296,7 @@ SiS_SetCRTCRegs(SiS_Private *SiS_Pr, UCH
+       (HwDeviceExtension->jChipRevision >= 0x30) ) {             /* for 630S0 */
+     if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+       if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToTV)) {
+-        SiS_SetReg1(SiS_Pr->SiS_P3d4,0x18,0xFE);
++         SiS_SetReg1(SiS_Pr->SiS_P3d4,0x18,0xFE);
+       }
+     }
+   }
+@@ -3065,7 +3334,7 @@ SiS_SetATTRegs(SiS_Private *SiS_Pr, UCHA
+       }
+       if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+          if(HwDeviceExtension->jChipType >= SIS_315H) {
+-          if(IS_SIS650740 || IS_SIS550) {  
++          if(IS_SIS550650740660) {
+              /* 315, 330 don't do this */
+              if(SiS_Pr->SiS_VBType & VB_SIS301B302B) { 
+                 if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) ARdata=0;
+@@ -3148,7 +3417,7 @@ SiS_SetCRT1CRTC(SiS_Private *SiS_Pr, UCH
+   USHORT tempah,i,modeflag,j;
+ #ifdef SIS315H
+   USHORT temp;
+-  USHORT ResInfo,DisplayType;
++  USHORT ResIndex,DisplayType;
+   const SiS_LCDACRT1DataStruct *LCDACRT1Ptr = NULL;
+ #endif
+@@ -3171,7 +3440,7 @@ SiS_SetCRT1CRTC(SiS_Private *SiS_Pr, UCH
+      /* LCDA */
+      temp = SiS_GetLCDACRT1Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
+-                       RefreshRateTableIndex,&ResInfo,&DisplayType);
++                       RefreshRateTableIndex,&ResIndex,&DisplayType);
+      switch(DisplayType) {
+       case Panel_800x600       : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT1800x600_1;      break;
+@@ -3197,30 +3466,30 @@ SiS_SetCRT1CRTC(SiS_Private *SiS_Pr, UCH
+       default:                   LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11024x768_1;     break;
+      }
+-     tempah = (LCDACRT1Ptr+ResInfo)->CR[0];
++     tempah = (LCDACRT1Ptr+ResIndex)->CR[0];
+      SiS_SetReg1(SiS_Pr->SiS_P3d4,0x00,tempah);
+      for(i=0x01,j=1;i<=0x07;i++,j++){
+-       tempah = (LCDACRT1Ptr+ResInfo)->CR[j];
++       tempah = (LCDACRT1Ptr+ResIndex)->CR[j];
+        SiS_SetReg1(SiS_Pr->SiS_P3d4,i,tempah);
+      }
+      for(i=0x10,j=8;i<=0x12;i++,j++){
+-       tempah = (LCDACRT1Ptr+ResInfo)->CR[j];
++       tempah = (LCDACRT1Ptr+ResIndex)->CR[j];
+        SiS_SetReg1(SiS_Pr->SiS_P3d4,i,tempah);
+      }
+      for(i=0x15,j=11;i<=0x16;i++,j++){
+-       tempah =(LCDACRT1Ptr+ResInfo)->CR[j];
++       tempah =(LCDACRT1Ptr+ResIndex)->CR[j];
+        SiS_SetReg1(SiS_Pr->SiS_P3d4,i,tempah);
+      }
+      for(i=0x0A,j=13;i<=0x0C;i++,j++){
+-       tempah = (LCDACRT1Ptr+ResInfo)->CR[j];
++       tempah = (LCDACRT1Ptr+ResIndex)->CR[j];
+        SiS_SetReg1(SiS_Pr->SiS_P3c4,i,tempah);
+      }
+-     tempah = (LCDACRT1Ptr+ResInfo)->CR[16];
++     tempah = (LCDACRT1Ptr+ResIndex)->CR[16];
+      tempah &= 0x0E0;
+      SiS_SetReg1(SiS_Pr->SiS_P3c4,0x0E,tempah);
+-     tempah = (LCDACRT1Ptr+ResInfo)->CR[16];
++     tempah = (LCDACRT1Ptr+ResIndex)->CR[16];
+      tempah &= 0x01;
+      tempah <<= 5;
+      if(modeflag & DoubleScanMode)  tempah |= 0x080;
+@@ -3301,7 +3570,7 @@ SiS_SetCRT1CRTC(SiS_Private *SiS_Pr, UCH
+ BOOLEAN
+ SiS_GetLCDACRT1Ptr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+-                 USHORT RefreshRateTableIndex,USHORT *ResInfo,
++                 USHORT RefreshRateTableIndex,USHORT *ResIndex,
+                  USHORT *DisplayType)
+  {
+   USHORT tempbx=0,modeflag=0;
+@@ -3320,7 +3589,7 @@ SiS_GetLCDACRT1Ptr(SiS_Private *SiS_Pr, 
+   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx += 32;
+   if(modeflag & HalfDCLK)                 tempbx += 16;
+-  *ResInfo = CRT2CRTC & 0x3F;
++  *ResIndex = CRT2CRTC & 0x3F;
+   *DisplayType = tempbx;
+   return 1;
+@@ -3470,6 +3739,9 @@ SiS_SetCRT1ModeRegs(SiS_Private *SiS_Pr,
+   USHORT data,data2,data3;
+   USHORT infoflag=0,modeflag;
+   USHORT resindex,xres;
++#ifdef SIS315H
++  ULONG  longdata;
++#endif
+   if(SiS_Pr->UseCustomMode) {
+      modeflag = SiS_Pr->CModeFlag;
+@@ -3490,11 +3762,11 @@ SiS_SetCRT1ModeRegs(SiS_Private *SiS_Pr,
+   data2 = 0;
+   if(ModeNo > 0x13) {
+-    if(SiS_Pr->SiS_ModeType > 0x02) {
+-       data2 |= 0x02;
+-       data3 = (SiS_Pr->SiS_ModeType - ModeVGA) << 2;
+-       data2 |= data3;
+-    }
++     if(SiS_Pr->SiS_ModeType > 0x02) {
++        data2 |= 0x02;
++        data3 = (SiS_Pr->SiS_ModeType - ModeVGA) << 2;
++        data2 |= data3;
++     }
+   }
+ #ifdef TWDEBUG
+   xf86DrvMsg(0, X_INFO, "Debug: Mode infoflag = %x, Chiptype %d\n", 
+@@ -3517,7 +3789,8 @@ SiS_SetCRT1ModeRegs(SiS_Private *SiS_Pr,
+   if(HwDeviceExtension->jChipType != SIS_300) {
+      data = 0x0000;
+      if(infoflag & InterlaceMode) {
+-        if(xres == 1024) data = 0x0035;
++        if(xres <= 800)  data = 0x0020;
++        else if(xres <= 1024) data = 0x0035;
+         else data = 0x0048;
+      }
+      data2 = data & 0x00FF;
+@@ -3549,6 +3822,7 @@ SiS_SetCRT1ModeRegs(SiS_Private *SiS_Pr,
+      } else {
+         SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x0F,0xB7);
+      }
++     /* 651 BIOS does something for mode 0x12 here */
+   }
+   if(HwDeviceExtension->jChipType != SIS_300) {
+@@ -3604,9 +3878,9 @@ SiS_SetCRT1ModeRegs(SiS_Private *SiS_Pr,
+         data2 *= data3;
+         data3 = SiS_GetMCLK(SiS_Pr,ROMAddr, HwDeviceExtension);
+-        data3 *= 1024;
++        longdata = data3 * 1024;
+-        data2 = data3 / data2;
++        data2 = longdata / data2;
+         if(SiS_Pr->SiS_ModeType != Mode16Bpp) {
+             if(data2 >= 0x19c)      data = 0xba;
+@@ -3679,7 +3953,7 @@ SiS_SetVCLKState(SiS_Private *SiS_Pr, UC
+     if(VCLK >= 150) data2 |= 0x08;            /* VCLK > 150 */
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xF7,data2);
+-  } else {                                            /* 310/325 series */
++  } else {                                            /* 315 series */
+     data = 0;
+     if(VCLK >= 166) data |= 0x0c;             /* TW: Was 200; is 166 in 650, 315 and 330 BIOSes */
+@@ -3688,12 +3962,6 @@ SiS_SetVCLKState(SiS_Private *SiS_Pr, UC
+     if(VCLK >= 166) {                         /* TW: Was 200, is 166 in 650, 315 and 330 BIOSes */
+        SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1f,0xe7);
+     }
+-#if 0 /* Not done in 315 and 650/301LV/LVDS BIOSes: */
+-    data = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1F);                /* DAC pedestal */
+-    data &= 0xE7;
+-    if(VCLK<200) data |= 0x10;
+-    SiS_SetReg1(SiS_Pr->SiS_P3c4,0x1F,data);          /* DAC pedestal */
+-#endif
+   }
+   data2 = 0x03;
+@@ -3918,7 +4186,9 @@ GetDRAMSize(SiS_Private *SiS_Pr, PSIS_HW
+   } else if((HwDeviceExtension->jChipType == SIS_550) ||
+             (HwDeviceExtension->jChipType == SIS_740) ||
+-            (HwDeviceExtension->jChipType == SIS_650)) {
++            (HwDeviceExtension->jChipType == SIS_650) ||
++          (HwDeviceExtension->jChipType == SIS_660) ||
++          (HwDeviceExtension->jChipType == SIS_760)) {
+       counter = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14) & 0x3F;
+               counter++;
+@@ -4728,7 +4998,7 @@ SiS_GetSenseStatus(SiS_Private *SiS_Pr, 
+           SiS_Pr->SiS_SetFlag = 0x00;
+           SiS_Pr->SiS_ModeType = ModeVGA;
+           SiS_Pr->SiS_VBInfo = SetCRT2ToRAMDAC |LoadDACFlag |SetInSlaveMode;
+-          SiS_SetCRT2Group301(SiS_Pr, BaseAddr,ROMAddr,SenseModeNo,HwDeviceExtension);
++          SiS_SetCRT2Group(SiS_Pr, BaseAddr,ROMAddr,SenseModeNo,HwDeviceExtension);
+           for(i=0;i<20;i++) {
+             SiS_LongWait(SiS_Pr);
+           }
+@@ -4766,7 +5036,7 @@ SiS_GetSenseStatus(SiS_Private *SiS_Pr, 
+ #ifdef SIS315H
+          if(HwDeviceExtension->jChipType >= SIS_315H) {
+               OutputSelect = ROMAddr[0xf3];
+-              if(HwDeviceExtension->jChipType == SIS_330) {
++              if(HwDeviceExtension->jChipType >= SIS_330) {
+                    OutputSelect = ROMAddr[0x11b];
+               }
+          }
+@@ -4814,7 +5084,7 @@ SiS_GetSenseStatus(SiS_Private *SiS_Pr, 
+       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x00,P2reg0);
+       if(!(P2reg0 & 0x20)) {
+         SiS_Pr->SiS_VBInfo = DisableCRT2Display;
+-        SiS_SetCRT2Group301(SiS_Pr,BaseAddr,ROMAddr,SenseModeNo,HwDeviceExtension);
++        SiS_SetCRT2Group(SiS_Pr,BaseAddr,ROMAddr,SenseModeNo,HwDeviceExtension);
+       }
+     }
+   }
+@@ -4884,111 +5154,6 @@ SiS_SenseCHTV(SiS_Private *SiS_Pr)
+ }
+ #endif /* LINUXBIOS */
+-/*  ================ for TC only =================  */
+-
+-#ifdef TC
+-
+-int
+-INT1AReturnCode(union REGS regs)
+-{
+-  if (regs.x.cflag)
+-  {
+-    /*printf("Error to find pci device!\n"); */
+-    return 1;
+-  }
+-
+-  switch(regs.h.ah)
+-  {
+-    case 0: return 0;
+-            break;
+-    case 0x81: printf("Function not support\n");
+-               break;
+-    case 0x83: printf("bad vendor id\n");
+-               break;
+-    case 0x86: printf("device not found\n");
+-               break;
+-    case 0x87: printf("bad register number\n");
+-               break;
+-    case 0x88: printf("set failed\n");
+-               break;
+-    case 0x89: printf("buffer too small");
+-               break;
+-  }
+-  return 1;
+-}
+-
+-unsigned
+-FindPCIIOBase(unsigned index,unsigned deviceid)
+-{
+-  union REGS regs;
+-
+-  regs.h.ah = 0xb1;  /*PCI_FUNCTION_ID */
+-  regs.h.al = 0x02;  /*FIND_PCI_DEVICE */
+-  regs.x.cx = deviceid;
+-  regs.x.dx = 0x1039;
+-  regs.x.si = index;  /* find n-th device */
+-
+-  int86(0x1A, &regs, &regs);
+-
+-  if (INT1AReturnCode(regs)!=0)
+-    return 0;
+-
+-  /* regs.h.bh *//* bus number */
+-  /* regs.h.bl *//* device number */
+-  regs.h.ah = 0xb1;  /*PCI_FUNCTION_ID */
+-  regs.h.al = 0x09;  /*READ_CONFIG_WORD */
+-  regs.x.cx = deviceid;
+-  regs.x.dx = 0x1039;
+-  regs.x.di = 0x18;  /* register number */
+-  int86(0x1A, &regs, &regs);
+-
+-  if (INT1AReturnCode(regs)!=0)
+-    return 0;
+-  return regs.x.cx;
+-}
+-
+-
+-void
+-main(int argc, char *argv[])
+-{
+-  SIS_HW_DEVICE_INFO  HwDeviceExtension;
+-  USHORT temp;
+-  USHORT ModeNo;
+-
+-  /*HwDeviceExtension.pjVirtualRomBase =(PUCHAR) MK_FP(0xC000,0); */
+-  /*HwDeviceExtension.pjVideoMemoryAddress = (PUCHAR)MK_FP(0xA000,0);*/
+-
+-#ifdef SIS300  
+-  HwDeviceExtension.ulIOAddress = (FindPCIIOBase(0,0x6300)&0xFF80) + 0x30;
+-  HwDeviceExtension.jChipType = SIS_630;
+-#endif
+-
+-#ifdef SIS315H  
+-//  HwDeviceExtension.ulIOAddress = (FindPCIIOBase(0,0x5315)&0xFF80) + 0x30;
+-//  HwDeviceExtension.jChipType = SIS_550;
+-  HwDeviceExtension.ulIOAddress = (FindPCIIOBase(0,0x325)&0xFF80) + 0x30;
+-  HwDeviceExtension.jChipType = SIS_315H;
+-#endif
+-
+-  HwDeviceExtension.ujVBChipID = VB_CHIP_301;
+-  strcpy(HwDeviceExtension.szVBIOSVer,"0.84");
+-  HwDeviceExtension.bSkipDramSizing = FALSE;
+-  HwDeviceExtension.ulVideoMemorySize = 0;
+-  if(argc==2) {
+-    ModeNo=atoi(argv[1]);
+-  }
+-  else {
+-    ModeNo=0x2e;
+-    /*ModeNo=0x37; */ /* 1024x768x 4bpp */
+-    /*ModeNo=0x38; *//* 1024x768x 8bpp */
+-    /*ModeNo=0x4A; *//* 1024x768x 16bpp */
+-    /*ModeNo=0x47;*/ /* 800x600x 16bpp */
+-  }
+- /* SiSInit(SiS_Pr, &HwDeviceExtension);*/
+-  SiSSetMode(SiS_Pr, &HwDeviceExtension, ModeNo);
+-}
+-#endif /* TC END */
+-
+ /* ================ XFREE86 ================= */
+ /* Helper functions */
+@@ -5000,44 +5165,78 @@ SiS_CheckBuildCustomMode(ScrnInfoPtr pSc
+    SISPtr pSiS = SISPTR(pScrn);
+    int    out_n, out_dn, out_div, out_sbit, out_scale;
+    int    depth = pSiS->CurrentLayout.bitsPerPixel;
+-   
+-#ifdef SISDUALHEAD
+-   if( ((!pSiS->DualHeadMode) && (VBFlags & DISPTYPE_DISP2)) ||
+-       ((pSiS->DualHeadMode) && (!pSiS->SecondHead)) ) return 0;
+-#else      
+-   if(VBFlags & DISPTYPE_DISP2) return 0; 
+-#endif   
++   unsigned int vclk[5];
++
++#define Midx         0
++#define Nidx         1
++#define VLDidx       2
++#define Pidx         3
++#define PSNidx       4
++
++   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->CHBlankStart = pSiS->SiS_Pr->CHDisplay;
+-   pSiS->SiS_Pr->CHBlankEnd = pSiS->SiS_Pr->CHTotal;
+-   
++
+    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;
++   }
++
++   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;
+-   
+-   pSiS->SiS_Pr->CFlags = mode->Flags;
+-   SiS_compute_vclk(pSiS->SiS_Pr->CDClock, &out_n, &out_dn, &out_div, &out_sbit, &out_scale);
+-   
++   if(SiS_compute_vclk(pSiS->SiS_Pr->CDClock, &out_n, &out_dn, &out_div, &out_sbit, &out_scale)) {
++      pSiS->SiS_Pr->CSR2B = (out_div == 2) ? 0x80 : 0x00;
++      pSiS->SiS_Pr->CSR2B |= ((out_n - 1) & 0x7f);
++      pSiS->SiS_Pr->CSR2C = (out_dn - 1) & 0x1f;
++      pSiS->SiS_Pr->CSR2C |= (((out_scale - 1) & 3) << 5);
++      pSiS->SiS_Pr->CSR2C |= ((out_sbit & 0x01) << 7);
+ #ifdef TWDEBUG
+-   xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Clock %d: n %d dn %d div %d sb %d sc %d\n",
+-              pSiS->SiS_Pr->CDClock, out_n, out_dn, out_div, out_sbit, out_scale);
+-#endif        
+-
+-   pSiS->SiS_Pr->CSR2B = (out_div == 2) ? 0x80 : 0x00;
+-   pSiS->SiS_Pr->CSR2B |= ((out_n - 1) & 0x7f);
+-   pSiS->SiS_Pr->CSR2C = (out_dn - 1) & 0x1f;
+-   pSiS->SiS_Pr->CSR2C |= (((out_scale - 1) & 3) << 5);
+-   pSiS->SiS_Pr->CSR2C |= ((out_sbit & 0x01) << 7);
++      xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Clock %d: n %d dn %d div %d sb %d sc %d\n",
++              pSiS->SiS_Pr->CDClock, out_n, out_dn, out_div, out_sbit, out_scale);
++#endif
++   } else {
++      SiSCalcClock(pScrn, pSiS->SiS_Pr->CDClock, 2, vclk);
++      pSiS->SiS_Pr->CSR2B = (vclk[VLDidx] == 2) ? 0x80 : 0x00;
++      pSiS->SiS_Pr->CSR2B |= (vclk[Midx] - 1) & 0x7f;
++      pSiS->SiS_Pr->CSR2C = (vclk[Nidx] - 1) & 0x1f;
++      if(vclk[Pidx] <= 4) {
++         /* postscale 1,2,3,4 */
++         pSiS->SiS_Pr->CSR2C |= ((vclk[Pidx] - 1) & 3) << 5;
++      } else {
++         /* postscale 6,8 */
++         pSiS->SiS_Pr->CSR2C |= (((vclk[Pidx] / 2) - 1) & 3) << 5;
++       pSiS->SiS_Pr->CSR2C |= 0x80;
++      }
++#ifdef TWDEBUG
++      xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Clock %d: n %d dn %d div %d sc %d\n",
++              pSiS->SiS_Pr->CDClock, vclk[Midx], vclk[Nidx], vclk[VLDidx], vclk[Pidx]);
++#endif
++   }
++
+    pSiS->SiS_Pr->CSRClock = (pSiS->SiS_Pr->CDClock / 1000) + 1;
+    pSiS->SiS_Pr->CCRT1CRTC[0]  =  ((pSiS->SiS_Pr->CHTotal >> 3) - 5) & 0xff;
+@@ -5045,9 +5244,9 @@ SiS_CheckBuildCustomMode(ScrnInfoPtr pSc
+    pSiS->SiS_Pr->CCRT1CRTC[2]  =  (pSiS->SiS_Pr->CHBlankStart >> 3) - 1;
+    pSiS->SiS_Pr->CCRT1CRTC[3]  =  (((pSiS->SiS_Pr->CHBlankEnd >> 3) - 1) & 0x1F) | 0x80;
+    pSiS->SiS_Pr->CCRT1CRTC[4]  =  (pSiS->SiS_Pr->CHSyncStart >> 3) + 3;
+-   pSiS->SiS_Pr->CCRT1CRTC[5]  =  ((((pSiS->SiS_Pr->CHBlankEnd >> 3) - 1) & 0x20) << 2) | 
++   pSiS->SiS_Pr->CCRT1CRTC[5]  =  ((((pSiS->SiS_Pr->CHBlankEnd >> 3) - 1) & 0x20) << 2) |
+                                         (((pSiS->SiS_Pr->CHSyncEnd >> 3) + 3) & 0x1F);
+-   
++
+    pSiS->SiS_Pr->CCRT1CRTC[6]  =  (pSiS->SiS_Pr->CVTotal - 2) & 0xFF;
+    pSiS->SiS_Pr->CCRT1CRTC[7]  =  (((pSiS->SiS_Pr->CVTotal - 2) & 0x100) >> 8)
+                               | (((pSiS->SiS_Pr->CVDisplay - 1) & 0x100) >> 7)
+@@ -5057,50 +5256,50 @@ SiS_CheckBuildCustomMode(ScrnInfoPtr pSc
+                               | (((pSiS->SiS_Pr->CVTotal - 2) & 0x200)   >> 4)
+                               | (((pSiS->SiS_Pr->CVDisplay - 1) & 0x200) >> 3)
+                               | ((pSiS->SiS_Pr->CVSyncStart & 0x200) >> 2);
+-    
++
+    pSiS->SiS_Pr->CCRT1CRTC[16] = ((((pSiS->SiS_Pr->CVBlankStart - 1) & 0x200) >> 4) >> 5);    /* cr9 */
+-    
+-#if 0    
++
++#if 0
+    if (mode->VScan >= 32)
+       regp->CRTC[9] |= 0x1F;
+    else if (mode->VScan > 1)
+       regp->CRTC[9] |= mode->VScan - 1;
+-#endif        
++#endif
+-   pSiS->SiS_Pr->CCRT1CRTC[8] =  (pSiS->SiS_Pr->CVSyncStart - 1) & 0xFF;      /* cr10 */
+-   pSiS->SiS_Pr->CCRT1CRTC[9] =  ((pSiS->SiS_Pr->CVSyncEnd - 1) & 0x0F) | 0x80;       /* cr11 */
+-   pSiS->SiS_Pr->CCRT1CRTC[10] = (pSiS->SiS_Pr->CVDisplay - 1) & 0xFF;                /* cr12 */
+-   pSiS->SiS_Pr->CCRT1CRTC[11] = (pSiS->SiS_Pr->CVBlankStart - 1) & 0xFF;     /* cr15 */
+-   pSiS->SiS_Pr->CCRT1CRTC[12] = (pSiS->SiS_Pr->CVBlankEnd - 1) & 0xFF;               /* cr16 */
+-   
+-   pSiS->SiS_Pr->CCRT1CRTC[13] = 
++   pSiS->SiS_Pr->CCRT1CRTC[8] =  (pSiS->SiS_Pr->CVSyncStart     ) & 0xFF;             /* cr10 */
++   pSiS->SiS_Pr->CCRT1CRTC[9] =  ((pSiS->SiS_Pr->CVSyncEnd      ) & 0x0F) | 0x80;     /* cr11 */
++   pSiS->SiS_Pr->CCRT1CRTC[10] = (pSiS->SiS_Pr->CVDisplay    - 1) & 0xFF;             /* cr12 */
++   pSiS->SiS_Pr->CCRT1CRTC[11] = (pSiS->SiS_Pr->CVBlankStart - 1) & 0xFF;             /* cr15 */
++   pSiS->SiS_Pr->CCRT1CRTC[12] = (pSiS->SiS_Pr->CVBlankEnd   - 1) & 0xFF;             /* cr16 */
++
++   pSiS->SiS_Pr->CCRT1CRTC[13] =
+                         GETBITSTR((pSiS->SiS_Pr->CVTotal     -2), 10:10, 0:0) |
+                         GETBITSTR((pSiS->SiS_Pr->CVDisplay   -1), 10:10, 1:1) |
+                         GETBITSTR((pSiS->SiS_Pr->CVBlankStart-1), 10:10, 2:2) |
+                         GETBITSTR((pSiS->SiS_Pr->CVSyncStart   ), 10:10, 3:3) |
+                         GETBITSTR((pSiS->SiS_Pr->CVBlankEnd  -1),   8:8, 4:4) |
+-                        GETBITSTR((pSiS->SiS_Pr->CVSyncEnd   -1),   4:4, 5:5) ;  
++                        GETBITSTR((pSiS->SiS_Pr->CVSyncEnd     ),   4:4, 5:5) ;
+-   pSiS->SiS_Pr->CCRT1CRTC[14] = 
++   pSiS->SiS_Pr->CCRT1CRTC[14] =
+                         GETBITSTR((pSiS->SiS_Pr->CHTotal      >> 3) - 5, 9:8, 1:0) |
+                         GETBITSTR((pSiS->SiS_Pr->CHDisplay    >> 3) - 1, 9:8, 3:2) |
+                         GETBITSTR((pSiS->SiS_Pr->CHBlankStart >> 3) - 1, 9:8, 5:4) |
+                         GETBITSTR((pSiS->SiS_Pr->CHSyncStart  >> 3) + 3, 9:8, 7:6) ;
+-        
++
+    pSiS->SiS_Pr->CCRT1CRTC[15] =
+                         GETBITSTR((pSiS->SiS_Pr->CHBlankEnd >> 3) - 1, 7:6, 1:0) |
+-                        GETBITSTR((pSiS->SiS_Pr->CHSyncEnd  >> 3) + 3, 5:5, 2:2) ; 
+-                      
++                        GETBITSTR((pSiS->SiS_Pr->CHSyncEnd  >> 3) + 3, 5:5, 2:2) ;
++
+    switch(depth) {
+-   case 8:                    
+-              pSiS->SiS_Pr->CModeFlag = 0x223b;
++   case 8:
++              pSiS->SiS_Pr->CModeFlag |= 0x223b;
+       break;
+-   case 16:                   
+-              pSiS->SiS_Pr->CModeFlag = 0x227d;
++   case 16:
++              pSiS->SiS_Pr->CModeFlag |= 0x227d;
+       break;
+-   case 32:                   
+-              pSiS->SiS_Pr->CModeFlag = 0x22ff;
++   case 32:
++              pSiS->SiS_Pr->CModeFlag |= 0x22ff;
+       break;          
+    default: 
+       return 0;       
+@@ -5114,9 +5313,9 @@ SiS_CheckBuildCustomMode(ScrnInfoPtr pSc
+       pSiS->SiS_Pr->CModeFlag |= LineCompareOff;
+    if(pSiS->SiS_Pr->CFlags & V_CLKDIV2)
+         pSiS->SiS_Pr->CModeFlag |= HalfDCLK;
+-   
++
+    pSiS->SiS_Pr->CInfoFlag = 0x0007;
+-   if(pSiS->SiS_Pr->CFlags & V_NHSYNC) 
++   if(pSiS->SiS_Pr->CFlags & V_NHSYNC)
+       pSiS->SiS_Pr->CInfoFlag |= 0x4000;
+    if(pSiS->SiS_Pr->CFlags & V_NVSYNC) 
+       pSiS->SiS_Pr->CInfoFlag |= 0x8000;
+@@ -5152,13 +5351,13 @@ SiS_CheckBuildCustomMode(ScrnInfoPtr pSc
+       pSiS->SiS_Pr->CSR2B,
+       pSiS->SiS_Pr->CSR2C,
+       pSiS->SiS_Pr->CSRClock);
+-#endif        
++#endif
+    return 1;
+ }
+ /* TW: Build a list of supported modes */
+ DisplayModePtr
+-SiSBuildBuiltInModeList(ScrnInfoPtr pScrn)
++SiSBuildBuiltInModeList(ScrnInfoPtr pScrn, BOOLEAN includelcdmodes, BOOLEAN isfordvi)
+ {
+    SISPtr         pSiS = SISPTR(pScrn);
+    unsigned short VRE, VBE, VRS, VBS, VDE, VT;
+@@ -5166,11 +5365,16 @@ SiSBuildBuiltInModeList(ScrnInfoPtr pScr
+    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, index, vclkindex;
+-   DisplayModePtr new = NULL, current = NULL, first = NULL, backup = NULL;
++   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
+@@ -5194,15 +5398,20 @@ SiSBuildBuiltInModeList(ScrnInfoPtr pScr
+       if(pSiS->VGAEngine == SIS_300_VGA) index &= 0x3F;
+ #endif      
+-      if(((pSiS->SiS_Pr->SiS_RefIndex[i].XRes < 512) && (!pSiS->DSTN)) ||
+-               ((pSiS->DSTN) &&
+-        (pSiS->SiS_Pr->SiS_RefIndex[i].XRes < 512) &&
+-        (pSiS->SiS_Pr->SiS_RefIndex[i].XRes != 320) &&
+-        (pSiS->SiS_Pr->SiS_RefIndex[i].YRes != 480)))  {
++      /* 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))) {
+@@ -5216,13 +5425,13 @@ SiSBuildBuiltInModeList(ScrnInfoPtr pScr
+       }
+       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; 
++      current->type = M_T_DEFAULT;
+       vclkindex = pSiS->SiS_Pr->SiS_RefIndex[i].Ext_CRTVCLK;
+       if(pSiS->VGAEngine == SIS_300_VGA) vclkindex &= 0x3F;
+@@ -5235,7 +5444,7 @@ SiSBuildBuiltInModeList(ScrnInfoPtr pScr
+               ( (((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",
+@@ -5303,10 +5512,29 @@ SiSBuildBuiltInModeList(ScrnInfoPtr pScr
+       D = B - F - C;
+-      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);
++      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,
+@@ -5430,7 +5658,7 @@ SiSBuildBuiltInModeList(ScrnInfoPtr pScr
+        current->VSyncStart <<= 1;
+        current->VSyncEnd <<= 1;
+        current->VTotal <<= 1;
+-       current->VTotal |= 1; 
++       current->VTotal |= 1;
+       }
+       if(current->Flags & V_DBLSCAN) {
+          current->Clock >>= 1;
+@@ -5440,6 +5668,7 @@ SiSBuildBuiltInModeList(ScrnInfoPtr pScr
+        current->VTotal >>= 1;
+       }
++#if 0
+       if((backup = xalloc(sizeof(DisplayModeRec)))) {
+          if(!pSiS->backupmodelist) pSiS->backupmodelist = backup;
+        else {
+@@ -5458,6 +5687,7 @@ SiSBuildBuiltInModeList(ScrnInfoPtr pScr
+        backup->Flags = current->Flags;
+        backup->Clock = current->Clock;
+       }
++#endif
+ #ifdef TWDEBUG
+       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+@@ -5470,6 +5700,187 @@ SiSBuildBuiltInModeList(ScrnInfoPtr pScr
+       i++;
+    }
++   /* Add non-standard LCD modes for panel's detailed timings */
++
++   if(!includelcdmodes) return first;
++
++   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;
++                }
++
++                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;
++
++                pSiS->AddedPlasmaModes = TRUE;
++
++                l = SiS_PlasmaTable[i].plasmamodes[k] & 0x3f;
++
++                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;
++
++               }
++             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;
+ }
+@@ -5486,25 +5897,25 @@ sisfb_mode_rate_to_dclock(SiS_Private *S
+     UCHAR  *ROMAddr  = HwDeviceExtension->pjVirtualRomBase;
+     ULONG  temp = 0;
+     int    Clock;
+-    
++
+     if(HwDeviceExtension->jChipType < SIS_315H) {
+ #ifdef SIS300
+        InitTo300Pointer(SiS_Pr, HwDeviceExtension);
+ #else
+-       return 65;
++       return 65 * 1000 * 1000;
+ #endif
+     } else {
+ #ifdef SIS315H
+        InitTo310Pointer(SiS_Pr, HwDeviceExtension);
+ #else
+-       return 65;
++       return 65 * 1000 * 1000;
+ #endif
+     }
+-    
++
+     temp = SiS_SearchModeID(SiS_Pr, ROMAddr, &ModeNo, &ModeIdIndex);
+     if(!temp) {
+       printk(KERN_ERR "Could not find mode %x\n", ModeNo);
+-      return 65;
++      return 65 * 1000 * 1000;
+     }
+     
+     RefreshRateTableIndex = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
+@@ -5518,6 +5929,56 @@ sisfb_mode_rate_to_dclock(SiS_Private *S
+     return(Clock);
+ }
++BOOLEAN
++sisfb_gettotalfrommode(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
++                     unsigned char modeno, int *htotal, int *vtotal, unsigned char rateindex)
++{
++    USHORT ModeNo = modeno;
++    USHORT ModeIdIndex = 0, CRT1Index = 0;
++    USHORT RefreshRateTableIndex = 0;
++    UCHAR  *ROMAddr  = HwDeviceExtension->pjVirtualRomBase;
++    ULONG  temp = 0;
++    unsigned char  sr_data, cr_data, cr_data2;
++
++    if(HwDeviceExtension->jChipType < SIS_315H) {
++#ifdef SIS300
++       InitTo300Pointer(SiS_Pr, HwDeviceExtension);
++#else
++       return FALSE;
++#endif
++    } else {
++#ifdef SIS315H
++       InitTo310Pointer(SiS_Pr, HwDeviceExtension);
++#else
++       return FALSE;
++#endif
++    }
++
++    temp = SiS_SearchModeID(SiS_Pr, ROMAddr, &ModeNo, &ModeIdIndex);
++    if(!temp) 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_DEVICE_INFO HwDeviceExtension,
+                        unsigned char modeno, unsigned char rateindex,
+@@ -5606,17 +6067,32 @@ sisfb_mode_rate_to_ddata(SiS_Private *Si
+     C = (temp > 0) ? temp : (temp + 64);
+     D = B - F - C;
+-    
+-    *left_margin = D * 8;
+-    *right_margin = F * 8;
+-    *hsync_len = C * 8;
++
++    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...
++        */
++       *left_margin = (400 - 376);
++       *right_margin = (328 - 320);
++       *hsync_len = (376 - 328);
++
++    } else {
++
++       *left_margin = D * 8;
++       *right_margin = F * 8;
++       *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) |
+@@ -5699,19 +6175,19 @@ sisfb_mode_rate_to_ddata(SiS_Private *Si
+         j++;
+       }
+     }       
+-       
+-#if 0  /* That's bullshit, only the resolution needs to be shifted */    
++
+     if((*vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
++#if 0  /* Do this? */
+        *upper_margin <<= 1;
+        *lower_margin <<= 1;
+        *vsync_len <<= 1;
++#endif
+     } else if((*vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
+        *upper_margin >>= 1;
+        *lower_margin >>= 1;
+        *vsync_len >>= 1;
+-    }  
+-#endif
+-          
++    }
++
+     return 1;       
+ }                       
+--- linux-2.6.0-test6/drivers/video/sis/initdef.h      2003-06-14 12:18:24.000000000 -0700
++++ 25/drivers/video/sis/initdef.h     2003-10-05 00:34:22.000000000 -0700
+@@ -1,5 +1,37 @@
+ /* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/sis/initdef.h,v 1.4 2000/12/02 01:16:17 dawes Exp $ */
+-
++/*
++ * Global definitions for init.c and init301.c
++ *
++ * Copyright 2002, 2003 by Thomas Winischhofer, Vienna, Austria
++ *
++ * If distributed as part of the linux kernel, the contents of this file
++ * is entirely covered by the GPL.
++ *
++ * Otherwise, the following terms apply:
++ *
++ * Permission to use, copy, modify, distribute, and sell this software and its
++ * documentation for any purpose is hereby granted without fee, provided that
++ * the above copyright notice appear in all copies and that both that
++ * copyright notice and this permission notice appear in supporting
++ * documentation, and that the name of the copyright holder not be used in
++ * advertising or publicity pertaining to distribution of the software without
++ * specific, written prior permission.  The copyright holder makes no representations
++ * about the suitability of this software for any purpose.  It is provided
++ * "as is" without express or implied warranty.
++ *
++ * THE COPYRIGHT HOLDER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
++ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
++ * EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR
++ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
++ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
++ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ *
++ * Author:    Thomas Winischhofer <thomas@winischhofer.net>
++ *
++ * Based on code by Silicon Intergrated Systems
++ *
++ */
+ #ifndef _INITDEF_
+ #define _INITDEF_
+@@ -22,12 +54,19 @@
+ #define VB_SIS301B302B          (VB_SIS301B|VB_SIS302B)
+ #define VB_SIS301LV302LV        (VB_SIS301LV|VB_SIS302LV)
+-#define IS_SIS650740            ((HwDeviceExtension->jChipType >= SIS_650) && (HwDeviceExtension->jChipType < SIS_330))
+-
+ #define IS_SIS650             (HwDeviceExtension->jChipType == SIS_650)
+ #define IS_SIS740             (HwDeviceExtension->jChipType == SIS_740)
+ #define IS_SIS330             (HwDeviceExtension->jChipType == SIS_330)
+ #define IS_SIS550             (HwDeviceExtension->jChipType == SIS_550)
++#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)
++#define IS_SIS660             (HwDeviceExtension->jChipType == SIS_660)
++#define IS_SIS760             (HwDeviceExtension->jChipType == SIS_760)
++#define IS_SIS650660            (IS_SIS650 || IS_SIS660)
++#define IS_SIS650740            ((HwDeviceExtension->jChipType >= SIS_650) && (HwDeviceExtension->jChipType < SIS_330))
++#define IS_SIS650740660         (IS_SIS650 || IS_SIS660 || IS_SIS740 || IS_SIS760)
++#define IS_SIS550650740660      (IS_SIS550 || IS_SIS650 || IS_SIS660 || IS_SIS740 || IS_SIS760)
+ #define CRT1Len                 17
+ #define LVDSCRT1Len             15
+@@ -63,7 +102,7 @@
+ #define SupportTV               0x0008
+ #define SupportHiVisionTV       0x0010
+ #define SupportLCD              0x0020
+-#define SupportRAMDAC2          0x0040  
++#define SupportRAMDAC2          0x0040
+ #define NoSupportTV             0x0070
+ #define NoSupportHiVisionTV     0x0060
+ #define NoSupportLCD            0x0058
+@@ -105,6 +144,24 @@
+ #define HotKeySwitch            0x8000  /* TW: ? */
+ #define SetCRT2ToLCDA           0x8000
++/* SetFlag */
++#define ProgrammingCRT2         0x01
++#define TVSimuMode              0x02
++#define RPLLDIV2XO              0x04
++#define LCDVESATiming           0x08
++#define EnableLVDSDDA           0x10
++#define SetDispDevSwitchFlag    0x20
++#define CheckWinDos             0x40
++#define SetDOSMode              0x80
++
++/* SysFlags */
++#define SF_Is651                0x0001
++#define SF_IsM650               0x0002
++#define SF_Is652              0x0004
++#define SF_IsM652             0x0008
++#define SF_IsM653             0x0010
++#define SF_Is660              0x8000
++
+ #define PanelRGB18Bit           0x0100
+ #define PanelRGB24Bit           0x0000
+@@ -112,7 +169,7 @@
+ #define TVOverScanShift         4
+ #define ClearBufferFlag         0x20
+-/* CR32 (Newer 630, and 310/325 series)
++/* CR32 (Newer 630, and 315 series)
+    [0]   VB connected with CVBS
+    [1]   VB connected with SVHS
+@@ -134,7 +191,7 @@
+           011   LVDS + Tumpion Zurac
+           100   LVDS + Chrontel 7005
+           110   Chrontel 7005
+-        310/325 series
++        315 series
+           001   SiS30x (never seen)
+           010   LVDS
+           011   LVDS + Chrontel 7019
+@@ -163,14 +220,15 @@
+ #define LCDSyncBit            0x00e0
+ #define LCDSyncShift               6
+-/* CR38 (310/325 series) */
++/* CR38 (315 series) */
+ #define EnableDualEdge                0x01   
+ #define SetToLCDA             0x02   /* LCD channel A (302B/LV and 650+LVDS only) */
+ #define EnableSiSHiVision       0x04   /* HiVision (HDTV) on SiS bridge */
+ #define EnableLVDSScart         0x04   /* Scart on Ch7019 (unofficial definition - TW) */
+ #define EnableLVDSHiVision      0x08   /* YPbPr color format (480i HDTV); only on 650/Ch7019 systems */
+-#define SiSHiVision1            0x10   /* See SetHiVision() */
+-#define SiSHiVision2            0x20
++#define EnableHiVision750       0x08   /* Enable 750P HiVision mode (30xLV only) */
++#define EnableHiVision525       0x10   /* Enable 525P HiVision mode (30xLV only) */
++#define SiSHiVision2            0x20   /* ? - |  --- mask 0x38 combinations have different meaning! */
+ #define EnablePALM              0x40   /* 1 = Set PALM */
+ #define EnablePALN              0x80   /* 1 = Set PALN */
+@@ -184,7 +242,7 @@
+ #define Enable302LV_DualLink    0x04   /* 30xNEW (302LV) only; set by mode switching function */
+-/* CR79 (310/325 series only)
++/* CR79 (315 series only)
+    [3-0] Notify driver
+          0001 Mode Switch event (set by BIOS)
+        0010 Epansion On/Off event
+@@ -202,16 +260,6 @@
+    [7]   TV UnderScan/OverScan (set by BIOS)
+ */
+-/* SetFlag */
+-#define ProgrammingCRT2         0x01
+-#define TVSimuMode              0x02
+-#define RPLLDIV2XO              0x04
+-#define LCDVESATiming           0x08
+-#define EnableLVDSDDA           0x10
+-#define SetDispDevSwitchFlag    0x20
+-#define CheckWinDos             0x40
+-#define SetDOSMode              0x80
+-
+ /* LCDResInfo */
+ #define Panel300_800x600        0x01  /* CR36 */
+ #define Panel300_1024x768       0x02
+@@ -220,7 +268,10 @@
+ #define Panel300_640x480        0x05
+ #define Panel300_1024x600       0x06
+ #define Panel300_1152x768       0x07
+-#define Panel300_320x480        0x08  /* fstn - TW: This is fake, can be any */
++#define Panel300_1280x768       0x0a
++#define Panel300_320x480        0x0e  /* fstn - TW: This is fake, can be any */
++#define Panel300_Custom               0x0f
++#define Panel300_Barco1366      0x10
+ #define Panel310_800x600        0x01
+ #define Panel310_1024x768       0x02
+@@ -231,9 +282,12 @@
+ #define Panel310_1280x960       0x07
+ #define Panel310_1152x768       0x08  /* LVDS only */
+ #define Panel310_1400x1050      0x09
+-#define Panel310_1280x768       0x0a    /* LVDS only */
++#define Panel310_1280x768       0x0a
+ #define Panel310_1600x1200      0x0b
+-#define Panel310_320x480        0x0c    /* fstn - TW: This is fake, can be any */
++#define Panel310_640x480_2      0x0c
++#define Panel310_640x480_3      0x0d
++#define Panel310_320x480        0x0e    /* fstn - TW: This is fake, can be any */
++#define Panel310_Custom               0x0f
+ #define Panel_800x600           0x01  /* Unified values */
+ #define Panel_1024x768          0x02
+@@ -246,7 +300,43 @@
+ #define Panel_1400x1050         0x09
+ #define Panel_1280x768          0x0a    /* LVDS only */
+ #define Panel_1600x1200         0x0b
+-#define Panel_320x480           0x0c    /* fstn - TW: This is fake, can be any */
++#define Panel_640x480_2               0x0c
++#define Panel_640x480_3               0x0d
++#define Panel_320x480           0x0e    /* fstn - TW: This is fake, can be any */
++#define Panel_Custom          0x0f
++#define Panel_Barco1366         0x10
++#define Panel_848x480         0x11
++
++/* Index in ModeResInfo table */
++#define SIS_RI_320x200 0
++#define SIS_RI_320x240 1
++#define SIS_RI_320x400 2
++#define SIS_RI_400x300 3
++#define SIS_RI_512x384 4
++#define SIS_RI_640x400 5
++#define SIS_RI_640x480 6
++#define SIS_RI_800x600 7
++#define SIS_RI_1024x768 8
++#define SIS_RI_1280x1024 9
++#define SIS_RI_1600x1200 10
++#define SIS_RI_1920x1440 11
++#define SIS_RI_2048x1536 12
++#define SIS_RI_720x480 13
++#define SIS_RI_720x576 14
++#define SIS_RI_1280x960 15
++#define SIS_RI_800x480 16
++#define SIS_RI_1024x576 17
++#define SIS_RI_1280x720 18
++#define SIS_RI_856x480 19
++#define SIS_RI_1280x768 20
++#define SIS_RI_1400x1050 21
++#define SIS_RI_1152x864 22
++#define SIS_RI_848x480 23
++#define SIS_RI_1360x768 24
++#define SIS_RI_1024x600 25
++#define SIS_RI_1152x768 26
++#define SIS_RI_768x576 27
++#define SIS_RI_1360x1024 28
+ #define ExtChipType             0x0e
+ #define ExtChip301              0x02
+@@ -278,15 +368,34 @@
+ #define VCLKStartFreq           25
+ #define SoftDramType            0x80
+-#define VCLK40                  0x04   /* Index in VCLKData array */
+-#define VCLK65                  0x09   /* Index in VCLKData array */
+-#define VCLK108_2               0x14   /* Index in VCLKData array */
+-#define TVVCLKDIV2              0x21   /* Indices in (VB)VCLKData arrays */
+-#define TVVCLK                  0x22
+-#define HiTVVCLKDIV2            0x23
+-#define HiTVVCLK                0x24
+-#define HiTVSimuVCLK            0x25
+-#define HiTVTextVCLK            0x26
++/* Indices in (VB)VCLKData tables */
++
++#define VCLK28                  0x00   /* Index in VCLKData table (300 and 315) */
++#define VCLK40                  0x04   /* Index in VCLKData table (300 and 315) */
++#define VCLK65_300              0x09   /* Index in VCLKData table (300) */
++#define VCLK108_2_300           0x14   /* Index in VCLKData table (300) */
++#define VCLK81_300            0x3f   /* Index in VCLKData table (300) */
++#define VCLK108_3_300           0x42   /* Index in VCLKData table (300) */
++#define VCLK100_300             0x43   /* Index in VCLKData table (300) */
++#define VCLK34_300              0x3d   /* Index in VCLKData table (300) */
++#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             0x21   /* 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 VCLK34_315              0x55   /* Index in VBVCLKData table (315) */
++
++#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) */
++#define TVVCLKDIV2              0x00   /* Index relative to TVCLKBASE */
++#define TVVCLK                  0x01   /* Index relative to TVCLKBASE */
++#define HiTVVCLKDIV2            0x02   /* Index relative to TVCLKBASE */
++#define HiTVVCLK                0x03   /* Index relative to TVCLKBASE */
++#define HiTVSimuVCLK            0x04   /* Index relative to TVCLKBASE */
++#define HiTVTextVCLK            0x05   /* Index relative to TVCLKBASE */
++
++/* ------------------------------ */
+ #define LoadDACFlag             0x1000
+ #define AfterLockCRT2           0x4000
+@@ -306,6 +415,8 @@
+ #define HotPlugFunction         0x08
+ #define StStructSize            0x06
++#define SIS_VIDEO_CAPTURE       0x00 - 0x30
++#define SIS_VIDEO_PLAYBACK      0x02 - 0x30
+ #define SIS_CRT2_PORT_04        0x04 - 0x30
+ #define SIS_CRT2_PORT_10        0x10 - 0x30
+ #define SIS_CRT2_PORT_12        0x12 - 0x30
+@@ -393,7 +504,7 @@
+ /*
+   =============================================================
+-                      for 310/325 series
++                        for 315 series
+   =============================================================
+ */
+ #define SoftDRAMType        0x80
+--- linux-2.6.0-test6/drivers/video/sis/init.h 2003-06-14 12:18:30.000000000 -0700
++++ 25/drivers/video/sis/init.h        2003-10-05 00:34:22.000000000 -0700
+@@ -1,19 +1,47 @@
++/* $XFree86$ */
++/*
++ * Data and prototypes for init.c
++ *
++ * Copyright 2002, 2003 by Thomas Winischhofer, Vienna, Austria
++ *
++ * If distributed as part of the linux kernel, the contents of this file
++ * is entirely covered by the GPL.
++ *
++ * Otherwise, the following terms apply:
++ *
++ * Permission to use, copy, modify, distribute, and sell this software and its
++ * documentation for any purpose is hereby granted without fee, provided that
++ * the above copyright notice appear in all copies and that both that
++ * copyright notice and this permission notice appear in supporting
++ * documentation, and that the name of the copyright holder not be used in
++ * advertising or publicity pertaining to distribution of the software without
++ * specific, written prior permission.  The copyright holder makes no representations
++ * about the suitability of this software for any purpose.  It is provided
++ * "as is" without express or implied warranty.
++ *
++ * THE COPYRIGHT HOLDER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
++ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
++ * EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR
++ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
++ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
++ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ *
++ * Author:    Thomas Winischhofer <thomas@winischhofer.net>
++ *
++ * Based on code by Silicon Intergrated Systems
++ *
++ */
++
+ #ifndef _INIT_
+ #define _INIT_
+ #include "osdef.h"
++
+ #include "initdef.h"
+ #include "vgatypes.h"
+ #include "vstruct.h"
+-#ifdef TC
+-#include <stdio.h>
+-#include <string.h>
+-#include <conio.h>
+-#include <dos.h>
+-#include <stdlib.h>
+-#endif
+-
+ #ifdef LINUX_XF86
+ #include "xf86.h"
+ #include "xf86Pci.h"
+@@ -24,6 +52,9 @@
+ #endif
+ #ifdef LINUX_KERNEL
++#ifdef SIS_CP
++#undef SIS_CP
++#endif
+ #include <linux/config.h>
+ #include <linux/version.h>
+ #include <linux/types.h>
+@@ -36,19 +67,6 @@
+ #endif
+ #endif
+-#ifdef WIN2000
+-#include <stdio.h>
+-#include <string.h>
+-#include <miniport.h>
+-#include "dderror.h"
+-#include "devioctl.h"
+-#include "miniport.h"
+-#include "ntddvdeo.h"
+-#include "video.h"
+-#include "sisv.h"
+-#include "tools.h"
+-#endif
+-
+ const USHORT SiS_DRAMType[17][5]={
+       {0x0C,0x0A,0x02,0x40,0x39},
+       {0x0D,0x0A,0x01,0x40,0x48},
+@@ -144,6 +162,2227 @@ const USHORT SiS_VGA_DAC[] =
+       0x0B,0x0C,0x0D,0x0F,0x10
+ };
++static const SiS_StResInfoStruct SiS_StResInfo[]=
++{
++      { 640,400},
++      { 640,350},
++      { 720,400},
++      { 720,350},
++      { 640,480}
++};
++
++static const SiS_ModeResInfoStruct SiS_ModeResInfo[] =
++{
++      {  320, 200, 8, 8},   /* 0x00 */
++      {  320, 240, 8, 8},   /* 0x01 */
++      {  320, 400, 8, 8},   /* 0x02 */
++      {  400, 300, 8, 8},   /* 0x03 */
++      {  512, 384, 8, 8},   /* 0x04 */
++      {  640, 400, 8,16},   /* 0x05 */
++      {  640, 480, 8,16},   /* 0x06 */
++      {  800, 600, 8,16},   /* 0x07 */
++      { 1024, 768, 8,16},   /* 0x08 */
++      { 1280,1024, 8,16},   /* 0x09 */
++      { 1600,1200, 8,16},   /* 0x0a */
++      { 1920,1440, 8,16},   /* 0x0b */
++      { 2048,1536, 8,16},   /* 0x0c */
++      {  720, 480, 8,16},   /* 0x0d */
++      {  720, 576, 8,16},   /* 0x0e */
++      { 1280, 960, 8,16},   /* 0x0f */
++      {  800, 480, 8,16},   /* 0x10 */
++      { 1024, 576, 8,16},   /* 0x11 */
++      { 1280, 720, 8,16},   /* 0x12 */
++      {  856, 480, 8,16},   /* 0x13 */
++      { 1280, 768, 8,16},   /* 0x14 */
++      { 1400,1050, 8,16},   /* 0x15 */
++      { 1152, 864, 8,16},   /* 0x16 */
++      {  848, 480, 8,16},   /* 0x17 */
++      { 1360, 768, 8,16},   /* 0x18 */
++      { 1024, 600, 8,16},   /* 0x19 */
++      { 1152, 768, 8,16},   /* 0x1a */
++      {  768, 576, 8,16},   /* 0x1b */
++      { 1360,1024, 8,16}    /* 0x1c */
++};
++
++static SiS_StandTableStruct SiS_StandTable[]=
++{
++/* 0x00: MD_0_200 */
++ {
++  0x28,0x18,0x08,0x0800,
++  {0x09,0x03,0x00,0x02},
++  0x63,
++  {0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f,
++   0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00,
++   0x9c,0x8e,0x8f,0x14,0x1f,0x96,0xb9,0xa3,
++   0xff},
++  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
++   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
++   0x08,0x00,0x0f,0x00},
++  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
++   0xff}
++ },
++/* 0x01: MD_1_200 */
++ {
++  0x28,0x18,0x08,0x0800,
++  {0x09,0x03,0x00,0x02},
++  0x63,
++  {0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f,
++   0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00,
++   0x9c,0x8e,0x8f,0x14,0x1f,0x96,0xb9,0xa3,
++   0xff},
++  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
++   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
++   0x08,0x00,0x0f,0x00},
++  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
++   0xff}
++ },
++/* 0x02: MD_2_200 */
++ {
++  0x50,0x18,0x08,0x1000,
++  {0x01,0x03,0x00,0x02},
++  0x63,
++  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
++   0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00,
++   0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,
++   0xff},
++  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
++   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
++   0x08,0x00,0x0f,0x00},
++  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
++   0xff}
++ },
++/* 0x03: MD_3_200 - mode 0x03 - 0 */
++ {
++  0x50,0x18,0x08,0x1000,
++  {0x01,0x03,0x00,0x02},
++  0x63,
++  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
++   0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00,
++   0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,
++   0xff},
++  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
++   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
++   0x08,0x00,0x0f,0x00},
++  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
++   0xff}
++ },
++/* 0x04: MD_4 */
++ {
++  0x28,0x18,0x08,0x4000,
++  {0x09,0x03,0x00,0x02},
++  0x63,
++  {0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,   /* 0x2c is 2b for 300 */
++   0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,
++   0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xa2,
++   0xff},
++  {0x00,0x13,0x15,0x17,0x02,0x04,0x06,0x07,
++   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
++   0x01,0x00,0x03,0x00},
++  {0x00,0x00,0x00,0x00,0x00,0x30,0x0f,0x00,
++   0xff}
++ },
++/* 0x05: MD_5 */
++ {
++  0x28,0x18,0x08,0x4000,
++  {0x09,0x03,0x00,0x02},
++  0x63,
++  {0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,   /* 0x2c is 2b for 300 */
++   0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,
++   0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xa2,
++   0xff},
++  {0x00,0x13,0x15,0x17,0x02,0x04,0x06,0x07,
++   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
++   0x01,0x00,0x03,0x00},
++  {0x00,0x00,0x00,0x00,0x00,0x30,0x0f,0x00,
++   0xff}
++ },
++/* 0x06: MD_6 */
++ {
++  0x50,0x18,0x08,0x4000,
++  {0x01,0x01,0x00,0x06},
++  0x63,
++  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,   /* 55,81 is 54,80 for 300 */
++   0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,
++   0x9c,0x8e,0x8f,0x28,0x00,0x96,0xb9,0xc2,
++   0xff},
++  {0x00,0x17,0x17,0x17,0x17,0x17,0x17,0x17,
++   0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,
++   0x01,0x00,0x01,0x00},
++  {0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x00,
++   0xff}
++ },
++/* 0x07: MD_7 */
++ {
++  0x50,0x18,0x0e,0x1000,
++  {0x00,0x03,0x00,0x03},
++  0xa6,
++  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
++   0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
++   0x83,0x85,0x5d,0x28,0x0d,0x63,0xba,0xa3,
++   0xff},
++  {0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
++   0x10,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
++   0x0e,0x00,0x0f,0x08},
++  {0x00,0x00,0x00,0x00,0x00,0x10,0x0a,0x00,
++   0xff}
++ },
++/* 0x08: MDA_DAC */
++ {
++  0x00,0x00,0x00,0x0000,
++  {0x00,0x00,0x00,0x15},
++  0x15,
++  {0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
++   0x15,0x15,0x15,0x15,0x15,0x15,0x3f,0x3f,
++   0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x00,0x00,
++   0x00},
++  {0x00,0x00,0x00,0x00,0x00,0x15,0x15,0x15,
++   0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
++   0x15,0x15,0x15,0x15},
++  {0x15,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,
++   0x3f}
++ },
++/* 0x09: CGA_DAC */
++ {
++  0x00,0x10,0x04,0x0114,
++  {0x11,0x09,0x15,0x00},
++  0x10,
++  {0x04,0x14,0x01,0x11,0x09,0x15,0x2a,0x3a,
++   0x2e,0x3e,0x2b,0x3b,0x2f,0x3f,0x2a,0x3a,
++   0x2e,0x3e,0x2b,0x3b,0x2f,0x3f,0x00,0x10,
++   0x04},
++  {0x14,0x01,0x11,0x09,0x15,0x00,0x10,0x04,
++   0x14,0x01,0x11,0x09,0x15,0x2a,0x3a,0x2e,
++   0x3e,0x2b,0x3b,0x2f},
++  {0x3f,0x2a,0x3a,0x2e,0x3e,0x2b,0x3b,0x2f,
++   0x3f}
++ },
++/* 0x0a: EGA_DAC */
++ {
++  0x00,0x10,0x04,0x0114,
++  {0x11,0x05,0x15,0x20},
++  0x30,
++  {0x24,0x34,0x21,0x31,0x25,0x35,0x08,0x18,
++   0x0c,0x1c,0x09,0x19,0x0d,0x1d,0x28,0x38,
++   0x2c,0x3c,0x29,0x39,0x2d,0x3d,0x02,0x12,
++   0x06},
++  {0x16,0x03,0x13,0x07,0x17,0x22,0x32,0x26,
++   0x36,0x23,0x33,0x27,0x37,0x0a,0x1a,0x0e,
++   0x1e,0x0b,0x1b,0x0f},
++  {0x1f,0x2a,0x3a,0x2e,0x3e,0x2b,0x3b,0x2f,
++   0x3f}
++ },
++/* 0x0b: VGA_DAC */
++ {
++  0x00,0x10,0x04,0x0114,
++  {0x11,0x09,0x15,0x2a},
++  0x3a,
++  {0x2e,0x3e,0x2b,0x3b,0x2f,0x3f,0x00,0x05,
++   0x08,0x0b,0x0e,0x11,0x14,0x18,0x1c,0x20,
++   0x24,0x28,0x2d,0x32,0x38,0x3f,0x00,0x10,
++   0x1f},
++  {0x2f,0x3f,0x1f,0x27,0x2f,0x37,0x3f,0x2d,
++   0x31,0x36,0x3a,0x3f,0x00,0x07,0x0e,0x15,
++   0x1c,0x0e,0x11,0x15},
++  {0x18,0x1c,0x14,0x16,0x18,0x1a,0x1c,0x00,
++   0x04}
++ },
++/* 0x0c */
++ {
++  0x08,0x0c,0x10,0x0a08,
++  {0x0c,0x0e,0x10,0x0b},
++  0x0c,
++  {0x0d,0x0f,0x10,0x10,0x01,0x08,0x00,0x00,
++   0x00,0x00,0x01,0x00,0x02,0x02,0x01,0x00,
++   0x04,0x04,0x01,0x00,0x05,0x02,0x05,0x00,
++   0x06},
++  {0x01,0x06,0x05,0x06,0x00,0x08,0x01,0x08,
++   0x00,0x07,0x02,0x07,0x06,0x07,0x00,0x00,
++   0x00,0x00,0x00,0x00},
++  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++   0x00}
++ },
++/* 0x0d: MD_D */
++ {
++  0x28,0x18,0x08,0x2000,
++  {0x09,0x0f,0x00,0x06},
++  0x63,
++  {0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,     /* 2c is 2b for 300 */
++   0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
++   0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xe3,
++   0xff},
++  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
++   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
++   0x01,0x00,0x0f,0x00},
++  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
++   0xff}
++ },
++/* 0x0e: MD_E */
++ {
++  0x50,0x18,0x08,0x4000,
++  {0x01,0x0f,0x00,0x06},
++  0x63,
++  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,     /* 55,81 is 54,80 for 300 */
++   0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
++   0x9c,0x8e,0x8f,0x28,0x00,0x96,0xb9,0xe3,
++   0xff},
++  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
++   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
++   0x01,0x00,0x0f,0x00},
++  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
++   0xff}
++ },
++/* 0x0f: ExtVGATable - modes > 0x13 */
++ {
++  0x00,0x00,0x00,0x0000,
++  {0x01,0x0f,0x00,0x0e},
++  0x23,
++  {0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
++   0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
++   0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
++   0xff},
++  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
++   0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
++   0x01,0x00,0x00,0x00},
++  {0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
++   0xff}
++ },
++/* 0x10: ROM_SAVEPTR - totally different for 300 */
++ {
++  0x9f,0x3b,0x00,0x00c0,
++  {0x00,0x00,0x00,0x00},
++  0x00,
++  {0x00,0x00,0x00,0x00,0x00,0x00,0xbb,0x3f,
++   0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
++   0x00,0x00,0x1a,0x00,0xac,0x3e,0x00,0xc0,
++   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}
++ },
++/* 0x11: MD_F */
++ {
++  0x50,0x18,0x0e,0x8000,
++  {0x01,0x0f,0x00,0x06},
++  0xa2,
++  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,    /* 55,81 is 54,80 on 300 */
++   0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
++   0x82,0x84,0x5d,0x28,0x0f,0x63,0xba,0xe3,    /* 82,84 is 83,85 on 300 */
++   0xff},
++  {0x00,0x08,0x00,0x00,0x18,0x18,0x00,0x00,
++   0x00,0x08,0x00,0x00,0x00,0x18,0x00,0x00,
++   0x0b,0x00,0x05,0x00},
++  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x05,
++   0xff}
++ },
++/* 0x12: MD_10 */
++ {
++  0x50,0x18,0x0e,0x8000,
++  {0x01,0x0f,0x00,0x06},
++  0xa3,
++  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,    /* 55,81 is 54,80 on 300 */
++   0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
++   0x82,0x84,0x5d,0x28,0x0f,0x63,0xba,0xe3,    /* 82,84 is 83,85 on 300 */
++   0xff},
++  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
++   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
++   0x01,0x00,0x0f,0x00},
++  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
++   0xff}
++ },
++/* 0x13: MD_0_350 */
++ {
++  0x28,0x18,0x0e,0x0800,
++  {0x09,0x03,0x00,0x02},
++  0xa3,
++  {0x2d,0x27,0x28,0x90,0x2b,0xb1,0xbf,0x1f,    /* b1 is a0 on 300 */
++   0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
++   0x83,0x85,0x5d,0x14,0x1f,0x63,0xba,0xa3,
++   0xff},
++  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
++   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
++   0x08,0x00,0x0f,0x00},
++  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
++   0xff}
++ },
++/* 0x14: MD_1_350 */
++ {
++  0x28,0x18,0x0e,0x0800,
++  {0x09,0x03,0x00,0x02},
++  0xa3,
++  {0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f,
++   0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
++   0x83,0x85,0x5d,0x14,0x1f,0x63,0xba,0xa3,
++   0xff},
++  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
++   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
++   0x08,0x00,0x0f,0x00},
++  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
++   0xff}
++ },
++/* 0x15: MD_2_350 */
++ {
++  0x50,0x18,0x0e,0x1000,
++  {0x01,0x03,0x00,0x02},
++  0xa3,
++  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
++   0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
++   0x83,0x85,0x5d,0x28,0x1f,0x63,0xba,0xa3,
++   0xff},
++  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
++   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
++   0x08,0x00,0x0f,0x00},
++  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
++   0xff}
++ },
++/* 0x16: MD_3_350 - mode 0x03 - 1 */
++ {
++  0x50,0x18,0x0e,0x1000,
++  {0x01,0x03,0x00,0x02},
++  0xa3,
++  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
++   0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
++   0x83,0x85,0x5d,0x28,0x1f,0x63,0xba,0xa3,
++   0xff},
++  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
++   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
++   0x08,0x00,0x0f,0x00},
++  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
++   0xff}
++ },
++/* 0x17: MD_0_1_400 */
++ {
++  0x28,0x18,0x10,0x0800,
++  {0x08,0x03,0x00,0x02},
++  0x67,
++  {0x2d,0x27,0x28,0x90,0x2b,0xb1,0xbf,0x1f,    /* b1 is a0 on 300 */
++   0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,
++   0x9c,0x8e,0x8f,0x14,0x1f,0x96,0xb9,0xa3,
++   0xff},
++  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
++   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
++   0x0c,0x00,0x0f,0x08},
++  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
++   0xff}
++ },
++/* 0x18: MD_2_3_400 - mode 0x03 - 2 */
++ {
++  0x50,0x18,0x10,0x1000,
++  {0x00,0x03,0x00,0x02},
++  0x67,
++  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
++   0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,
++   0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,
++   0xff},
++  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
++   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
++   0x0c,0x00,0x0f,0x08},
++  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
++   0xff}
++ },
++/* 0x19: MD_7_400 */
++ {
++  0x50,0x18,0x10,0x1000,
++  {0x00,0x03,0x00,0x02},
++  0x66,
++  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
++   0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,
++   0x9c,0x8e,0x8f,0x28,0x0f,0x96,0xb9,0xa3,
++   0xff},
++  {0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
++   0x10,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
++   0x0e,0x00,0x0f,0x08},
++  {0x00,0x00,0x00,0x00,0x00,0x10,0x0a,0x00,
++   0xff}
++ },
++/* 0x1a: MD_11 */
++ {
++  0x50,0x1d,0x10,0xa000,
++  {0x01,0x0f,0x00,0x06},
++  0xe3,
++  {0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e,    /* 55,81 is 54,80 on 300 */
++   0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
++   0xe9,0x8b,0xdf,0x28,0x00,0xe7,0x04,0xc3,    /* e9,8b is ea,8c on 300 */
++   0xff},
++  {0x00,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,
++   0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,
++   0x01,0x00,0x0f,0x00},
++  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x01,
++   0xff}
++ },
++/* 0x1b: ExtEGATable - Modes <= 0x02 */
++ {
++  0x50,0x1d,0x10,0xa000,
++  {0x01,0x0f,0x00,0x06},
++  0xe3,
++  {0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e,    /* 55,81 is 54,80 on 300 */
++   0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
++   0xe9,0x8b,0xdf,0x28,0x00,0xe7,0x04,0xe3,    /* e9,8b is ea,8c on 300 */
++   0xff},
++  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
++   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
++   0x01,0x00,0x0f,0x00},
++  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
++   0xff}
++ },
++/* 0x1c: MD_13 */
++ {
++  0x28,0x18,0x08,0x2000,
++  {0x01,0x0f,0x00,0x0e},
++  0x63,
++  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,    /* 55,81 is 54,80 on 300 */
++   0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,
++   0x9c,0x8e,0x8f,0x28,0x40,0x96,0xb9,0xa3,
++   0xff},
++  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
++   0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
++   0x41,0x00,0x0f,0x00},
++  {0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
++   0xff}
++ }
++};
++
++static const UCHAR 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,
++      0x0c,0x50,0x00,0x97,0x00,0xda,0x4a,0x17,
++      0x7d,0x05,0x4b,0x00,0x00,0xe2,0x00,0x02,
++      0x03,0x0a,0x65,0x9d,0x08,0x92,0x8f,0x40,
++      0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x50,
++      0x00,0x40,0x44,0x00,0xdb,0x02,0x3b,0x00
++};
++
++static const UCHAR 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,
++      0x70,0x50,0x00,0x9b,0x00,0xd9,0x5d,0x17,
++      0x7d,0x05,0x45,0x00,0x00,0xe8,0x00,0x02,
++      0x0d,0x00,0x68,0xb0,0x0b,0x92,0x8f,0x40,
++      0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x63,
++      0x00,0x40,0x3e,0x00,0xe1,0x02,0x28,0x00
++};
++
++static const UCHAR 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,
++      0x2a,0xde,0x2a,0x44,0x40,0x2a,0x44,0x40,
++      0x8e,0x8e,0x82,0x07,0x0b,0x92,0x0f,0x40,
++      0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x3d,
++      0x63,0x4f,0x27,0x00,0xfc,0xff,0x6a,0x00
++};
++
++static const UCHAR 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,
++      0x11,0x15,0x11,0xcf,0x10,0x11,0xcf,0x10,
++      0x35,0x35,0x3b,0x69,0x1d,0x92,0x0f,0x40,
++      0x60,0x80,0x14,0x90,0x8c,0x60,0x04,0x86,
++      0xaf,0x5d,0x0e,0x00,0xfc,0xff,0x2d,0x00
++};
++
++static const UCHAR 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,
++      0x2a,0xde,0x2a,0x44,0x40,0x2a,0x44,0x40,
++      0x8e,0x8e,0x82,0x07,0x0b,0x92,0x0f,0x40,
++      0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x3d,
++      0x63,0x4f,0x27,0x00,0xfc,0xff,0x6a,0x00
++};
++
++static const UCHAR 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,
++      0x14,0x78,0x14,0x08,0x20,0x14,0x08,0x20,
++      0xc8,0xc8,0x3b,0xd2,0x26,0x92,0x0f,0x40,
++        0x60,0x80,0x14,0x90,0x8c,0x60,0x04,0x96,
++      0x72,0x5c,0x11,0x00,0xfc,0xff,0x32,0x00
++};
++
++static const UCHAR 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,
++      0x56,0x36,0x4f,0x6e,0x3f,0x80,0x00,0x80,
++      0x4f,0x7f,0x03,0xa8,0x7d,0x20,0x1a,0xa9,
++      0x14,0x05,0x03,0x7e,0x64,0x31,0x14,0x75,
++      0x18,0x05,0x18,0x05,0x4c,0xa8,0x01
++};
++
++static const UCHAR 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,
++      0x56,0x36,0x4f,0x6e,0x3f,0x80,0x00,0x80,
++      0x67,0x36,0x01,0x47,0x0e,0x10,0xbe,0xb4,
++      0x01,0x05,0x03,0x7e,0x65,0x31,0x14,0x75,
++      0x18,0x05,0x18,0x05,0x4c,0xa8,0x01
++};
++
++static const UCHAR 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,
++      0x56,0x36,0x4f,0x6e,0x3f,0x80,0x00,0x80,
++      0x93,0x3c,0x01,0x50,0x2f,0x10,0xf4,0xca,
++      0x01,0x05,0x03,0x7e,0x65,0x31,0x14,0x75,
++      0x18,0x05,0x18,0x05,0x4c,0xa8,0x01
++};
++
++static const UCHAR SiS_NTSCPhase[]    = {0x21,0xed,0xba,0x08};  /* Was {0x21,0xed,0x8a,0x08}; */
++static const UCHAR SiS_PALPhase[]     = {0x2a,0x05,0xe3,0x00};  /* Was {0x2a,0x05,0xd3,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 SiS_TVDataStruct  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}
++};
++
++static const SiS_TVDataStruct  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 */
++ {    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 */
++};
++
++static const SiS_TVDataStruct  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}
++};
++
++static const SiS_TVDataStruct  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  */
++ {  143,  76, 836, 523,1270, 440,   0, 128,   0,0xee,0x0c,0x22,0x08},    /* 720x480 - BETTER (from 300 series) */
++/*{   2,   1, 858, 503,1270, 480,   0, 128,   0,0xee,0x0c,0x22,0x08},*/  /* 720x480  (old, from 650) */
++ {    1,   1,1100, 811,1412, 440,   0, 128,   0,0xee,0x0c,0x22,0x08}     /* 1024x768 CORRECTED */
++/*{  65,  64,1056, 791,1270, 480, 638,   0,   0,0xEE,0x0C,0x22,0x08} */  /* 1024x768 */
++#if 0  /* 300 series was: */
++ {  143,  65, 858, 443,1270, 440, 171,   0, 171,0xf1,0x04,0x1f,0x18},
++ {   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},
++ {  143, 120,1056, 643,1270, 440,   0, 128,   0,0xf4,0x10,0x1c,0x00},
++ {  143,  76, 836, 523,1270, 440,   0, 128,   0,0xee,0x0c,0x22,0x08},
++ {   65,  64,1056, 791,1270, 480, 638,   0,   0,0xf1,0x04,0x1f,0x18}
++#endif
++};
++
++
++static const SiS_TVDataStruct  SiS_St2HiTVData[]=
++{
++ {    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, 0x3e8,0x233,0x311,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}
++};
++
++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},
++ {    3,   1, 0x348,0x1e3,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,0x670,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  */
++};
++
++static const UCHAR SiS_OutputSelect = 0x40;
++
++static const UCHAR SiS_SoftSetting  = 0x30;   /* RAM setting */
++
++static const SiS_LCDDataStruct  SiS_LCD1280x960Data[] =
++{
++      {    9,   2, 800, 500,1800,1000},
++      {    9,   2, 800, 500,1800,1000},
++      {    4,   1, 900, 500,1800,1000},
++      {    4,   1, 900, 500,1800,1000},
++      {    9,   2, 800, 500,1800,1000},
++      {   30,  11,1056, 625,1800,1000},
++      {    5,   3,1350, 800,1800,1000},
++      {    1,   1,1576,1050,1576,1050},
++      {    1,   1,1800,1000,1800,1000}
++};
++
++static const SiS_LCDDataStruct  SiS_StLCD1280x768Data[] =
++{
++      { 211,  100, 2100,  408, 1688,  802 }, /* These values are *wrong* */
++      { 211,   64, 1536,  358, 1688,  802 }, /* (which is why they aren't used yet) */
++      { 211,  100, 2100,  408, 1688,  802 },
++      { 211,   64, 1536,  358, 1688,  802 },
++      { 211,   48,  840,  488, 1688,  802 },
++      { 211,   72, 1008,  609, 1688,  802 },
++      { 211,  128, 1400,  776, 1688,  802 },
++      { 211,  205, 1680, 1041, 1688,  802 },
++      { 1,      1, 1688,  802, 1688,  802 }  /* That's the only one that *might* be correct */
++};
++
++static const SiS_LCDDataStruct  SiS_ExtLCD1280x768Data[] =
++{
++      { 211,  100, 2100,  408, 1688,  802 }, /* These values are *wrong* */
++      { 211,   64, 1536,  358, 1688,  802 }, /* (which is why they aren't used yet) */
++      { 211,  100, 2100,  408, 1688,  802 },
++      { 211,   64, 1536,  358, 1688,  802 },
++      { 211,   48,  840,  488, 1688,  802 },
++      { 211,   72, 1008,  609, 1688,  802 },
++      { 211,  128, 1400,  776, 1688,  802 },
++      { 211,  205, 1680, 1041, 1688,  802 },
++      { 1,      1, 1688,  802, 1688,  802 }  /* That's the only one that *might* be correct */
++};
++
++static const SiS_LCDDataStruct  SiS_NoScaleData1280x768[] =
++{  /* All values guessed */
++        { 1, 1, 1688,  802, 1688,  802},
++      { 1, 1, 1688,  802, 1688,  802},
++      { 1, 1, 1688,  802, 1688,  802},
++      { 1, 1, 1688,  802, 1688,  802},
++      { 1, 1, 1688,  802, 1688,  802},
++      { 1, 1, 1688,  802, 1688,  802},
++      { 1, 1, 1688,  802, 1688,  802},
++      { 1, 1, 1688,  802, 1688,  802},
++      { 1, 1, 1688,  802, 1688,  802}
++};
++
++static const SiS_LCDDataStruct  SiS_StLCD1400x1050Data[] =
++{
++      { 211,  100, 2100,  408, 1688, 1066 },
++      { 211,   64, 1536,  358, 1688, 1066 },
++      { 211,  100, 2100,  408, 1688, 1066 },
++      { 211,   64, 1536,  358, 1688, 1066 },
++      { 211,   48,  840,  488, 1688, 1066 },
++      { 211,   72, 1008,  609, 1688, 1066 },
++      { 211,  128, 1400,  776, 1688, 1066 },
++      { 211,  205, 1680, 1041, 1688, 1066 },
++      {   1,    1, 1688, 1066, 1688, 1066 }
++};
++
++static const SiS_LCDDataStruct  SiS_ExtLCD1400x1050Data[] =
++{
++      { 211,  100, 2100,  408, 1688, 1066 },
++      { 211,   64, 1536,  358, 1688, 1066 },
++      { 211,  100, 2100,  408, 1688, 1066 },
++      { 211,   64, 1536,  358, 1688, 1066 },
++      { 211,   48,  840,  488, 1688, 1066 },
++      { 211,   72, 1008,  609, 1688, 1066 },
++      { 211,  128, 1400,  776, 1688, 1066 },
++      { 211,  205, 1680, 1041, 1688, 1066 },
++      {   1,    1, 1688, 1066, 1688, 1066 }
++};
++
++static const SiS_LCDDataStruct  SiS_NoScaleData1400x1050[] =
++{
++      { 1, 1, 1688, 1066, 1688, 1066 },
++      { 1, 1, 1688, 1066, 1688, 1066 },
++      { 1, 1, 1688, 1066, 1688, 1066 },
++      { 1, 1, 1688, 1066, 1688, 1066 },
++      { 1, 1, 1688, 1066, 1688, 1066 },
++      { 1, 1, 1688, 1066, 1688, 1066 },
++      { 1, 1, 1688, 1066, 1688, 1066 },
++      { 1, 1, 1688, 1066, 1688, 1066 },
++      { 1, 1, 1688, 1066, 1688, 1066 }
++};
++
++static const SiS_LCDDataStruct  SiS_StLCD1600x1200Data[] =
++{
++      {27,  4, 800, 500, 2160, 1250 },
++      {27,  4, 800, 500, 2160, 1250 },
++      { 6,  1, 900, 500, 2160, 1250 },
++      { 6,  1, 900, 500, 2160, 1250 },
++      {27,  1, 800, 500, 2160, 1250 },
++      { 4,  1,1080, 625, 2160, 1250 },
++      { 5,  2,1350, 800, 2160, 1250 },
++      {135,88,1600,1100, 2160, 1250 },
++      {135,88,1600,1100, 2160, 1250 },
++      { 1,  1,2160,1250, 2160, 1250 }
++};
++
++static const SiS_LCDDataStruct  SiS_ExtLCD1600x1200Data[] =
++{
++      {27, 4, 800, 500, 2160, 1250 },
++      {27, 4, 800, 500, 2160, 1250 },
++      { 6, 1, 900, 500, 2160, 1250 },
++      { 6, 1, 900, 500, 2160, 1250 },
++      {27, 1, 800, 500, 2160, 1250 },
++      { 4, 1,1080, 625, 2160, 1250 },
++      { 5, 2,1350, 800, 2160, 1250 },
++      {27,16,1500,1064, 2160, 1250 },
++      {27,16,1500,1064, 2160, 1250 },
++      { 1, 1,2160,1250, 2160, 1250 }
++};
++
++static const SiS_LCDDataStruct  SiS_NoScaleData1600x1200[] =
++{
++        {1,  1, 2160, 1250, 2048, 1250},
++      {1,  1, 2160, 1250, 2048, 1250},
++      {1,  1, 2160, 1250, 2048, 1250},
++      {1,  1, 2160, 1250, 2048, 1250},
++      {1,  1, 2160, 1250, 2048, 1250},
++      {1,  1, 2160, 1250, 2048, 1250},
++      {1,  1, 2160, 1250, 2048, 1250},
++      {1,  1, 2160, 1250, 2048, 1250},
++      {1,  1, 2160, 1250, 2048, 1250},
++      {1,  1, 2160, 1250, 2048, 1250},
++};
++
++static const SiS_LCDDataStruct  SiS_NoScaleData[] =
++{
++      { 1, 1, 800, 449, 800, 449 },
++      { 1, 1, 800, 449, 800, 449 },
++      { 1, 1, 900, 449, 900, 449 },
++      { 1, 1, 900, 449, 900, 449 },
++      { 1, 1, 800, 525, 800, 525 },
++      { 1, 1,1056, 628,1056, 628 },
++      { 1, 1,1344, 806,1344, 806 },
++      { 1, 1,1688,1066,1688,1066 },
++        { 1, 1,1688, 802,1688, 802 },  /* 1280x768: 802 was 806 in both cases */
++        { 1, 1,2160,1250,2160,1250 },  /* 1600x1200 */
++      { 1, 1,1800,1000,1800,1000 }   /* 1280x960 */
++};
++
++static const SiS_LVDSDataStruct  SiS_LVDS320x480Data_1[]=
++{
++      { 848, 433, 400, 525},
++      { 848, 389, 400, 525},
++      { 848, 433, 400, 525},
++      { 848, 389, 400, 525},
++      { 848, 518, 400, 525},
++      {1056, 628, 400, 525},
++      { 400, 525, 400, 525},
++      { 800, 449,1000, 644},
++      { 800, 525,1000, 635}
++};
++
++static const SiS_LVDSDataStruct  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},
++      { 800, 449,1000, 644},
++      { 800, 525,1000, 635}
++};
++
++static const SiS_LVDSDataStruct  SiS_LVDS800x600Data_2[]=
++{
++      {1056, 628,1056, 628},
++      {1056, 628,1056, 628},
++      {1056, 628,1056, 628},
++      {1056, 628,1056, 628},
++      {1056, 628,1056, 628},
++      {1056, 628,1056, 628},
++      {1056, 628,1056, 628},
++      { 800, 449,1000, 644},
++      { 800, 525,1000, 635}
++};
++
++
++
++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},
++      {1688,1066,1688,1066},
++      {1688,1066,1688,1066},
++      {1688,1066,1688,1066},
++      {1688,1066,1688,1066},
++      {1688,1066,1688,1066},
++      {1688,1066,1688,1066},
++      {1688,1066,1688,1066}
++};
++
++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 */
++      { 800, 449,1280, 801},
++      { 800, 525,1280, 813}
++};
++
++static const SiS_LVDSDataStruct  SiS_LVDS1024x768Data_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},
++      { 800, 449,1280, 801},
++      { 800, 525,1280, 813}
++};
++
++/* Custom data for Barco iQ R300 */
++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 R300 */
++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 */
++};
++
++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 */
++      {1050, 638,1344, 806},   /* 800x600 */
++      {1344, 806,1344, 806},   /* 1024x768 */
++};
++
++static const SiS_LVDSDataStruct  SiS_LVDSBARCO1024Data_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},
++};
++
++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},
++      {1688,1066, 1688,1066},
++      {1688,1066, 1688,1066},
++      {1688,1066, 1688,1066},
++      {1688,1066, 1688,1066},
++      {1688,1066, 1688,1066},
++      {1688,1066, 1688,1066},
++      {1688,1066, 1688,1066},
++      {1688,1066, 1688,1066},
++};
++
++static const SiS_LVDSDataStruct  SiS_LVDS1600x1200Data_1[]=
++{
++        {1088, 450, 2048,1250},
++      {1088, 400, 2048,1250},
++      {1088, 450, 2048,1250},
++      {1088, 400, 2048,1250},
++      {1088, 530, 2048,1250},
++      {1248, 650, 2048,1250},
++      {1472, 818, 2048,1250},
++      {1728,1066, 2048,1250},
++      {1848,1066, 2048,1250},
++      {2048,1250, 2048,1250}
++};
++
++static const SiS_LVDSDataStruct  SiS_LVDS1600x1200Data_2[]=
++{
++        {2048,1250, 2048,1250},
++      {2048,1250, 2048,1250},
++      {2048,1250, 2048,1250},
++      {2048,1250, 2048,1250},
++      {2048,1250, 2048,1250},
++      {2048,1250, 2048,1250},
++      {2048,1250, 2048,1250},
++      {2048,1250, 2048,1250},
++      {2048,1250, 2048,1250},
++      {2048,1250, 2048,1250}
++};
++
++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},
++      {1408, 806, 1408, 806},
++      {1408, 806, 1408, 806},
++      {1408, 806, 1408, 806},
++      {1408, 806, 1408, 806},
++      {1408, 806, 1408, 806},
++      {1408, 806, 1408, 806},
++      {1408, 806, 1408, 806},
++      {1408, 806, 1408, 806}
++};
++
++static const SiS_LVDSDataStruct  SiS_LVDS1024x600Data_1[] =
++{
++      {840, 604,1344, 800},
++      {840, 560,1344, 800},
++      {840, 604,1344, 800},
++      {840, 560,1344, 800},
++      {840, 689,1344, 800},
++      {1050, 800,1344, 800},
++      {1344, 800,1344, 800},
++      {800, 449,1280, 789},
++      {800, 525,1280, 785}
++};
++
++static const SiS_LVDSDataStruct  SiS_LVDS1024x600Data_2[] =
++{
++      {1344, 800,1344, 800},
++      {1344, 800,1344, 800},
++      {1344, 800,1344, 800},
++      {1344, 800,1344, 800},
++      {1344, 800,1344, 800},
++      {1344, 800,1344, 800},
++      {1344, 800,1344, 800},
++      { 800, 449,1280, 801},
++      { 800, 525,1280, 813}
++};
++
++static const SiS_LVDSDataStruct  SiS_LVDS1152x768Data_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_LVDS1152x768Data_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},
++      { 800, 449,1280, 801},
++      { 800, 525,1280, 813}
++};
++
++/* TW: 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   */
++      {1344,1066, 1344,1066},  /* 1280x1024  */  /* INSERTED ! */
++      {1688, 806, 1688, 806},  /* 1280x768   */
++      /* No other panels ! */
++};
++
++static const SiS_LVDSDataStruct  SiS_LVDS640x480Data_1[]=
++{
++      { 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 */
++};
++
++/* FSTN 320x240 */
++static const SiS_LVDSDataStruct  SiS_LVDS640x480Data_2[]=
++{
++      { 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 */
++};
++
++
++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},
++      {1344, 806,1344, 806},
++      {1344, 806,1344, 806},
++      {1344, 806,1344, 806},
++      {1344, 806,1344, 806},
++      {1344, 806,1344, 806},
++      {1344, 806,1344, 806},
++      { 800, 449,1280, 801},
++      { 800, 525,1280, 813}
++};
++
++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 */
++};
++
++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 */
++};
++
++/* LCDA */
++
++static const SiS_LVDSDataStruct  SiS_LCDA1400x1050Data_1[]=
++{     /* TW: Might be temporary (invalid) data */
++        { 928, 416, 1688,1066},
++      { 928, 366, 1688,1066},
++      {1008, 416, 1688,1066},
++      {1008, 366, 1688,1066},
++      {1200, 530, 1688,1066},
++      {1088, 616, 1688,1066},
++      {1312, 784, 1688,1066},
++      {1568,1040, 1688,1066},
++      {1688,1066, 1688,1066}
++};
++
++static const SiS_LVDSDataStruct  SiS_LCDA1400x1050Data_2[]=
++{     /* TW: Temporary data. Not valid */
++      {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},
++      { 800, 449,1280, 801},
++      { 800, 525,1280, 813}
++};
++
++static const SiS_LVDSDataStruct  SiS_LCDA1600x1200Data_1[]=
++{     /* TW: Temporary data. Not valid */
++      {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},
++      { 800, 449,1280, 801},
++      { 800, 525,1280, 813}
++};
++
++static const SiS_LVDSDataStruct  SiS_LCDA1600x1200Data_2[]=
++{     /* TW: Temporary data. Not valid */
++      {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, 0, 0},
++      {0, 0, 0, 0},
++      {0, 0, 0, 0},
++      {0, 0, 0, 0},
++      {0, 0, 0, 0}
++};
++
++static const SiS_LVDSDataStruct  SiS_CHTVUNTSCData[]=
++{
++      { 840, 600, 840, 600},
++      { 840, 600, 840, 600},
++      { 840, 600, 840, 600},
++      { 840, 600, 840, 600},
++      { 784, 600, 784, 600},
++      {1064, 750,1064, 750},
++        {1160, 945,1160, 945}
++};
++
++static const SiS_LVDSDataStruct  SiS_CHTVONTSCData[]=
++{
++      { 840, 525, 840, 525},
++      { 840, 525, 840, 525},
++      { 840, 525, 840, 525},
++      { 840, 525, 840, 525},
++      { 784, 525, 784, 525},
++      {1040, 700,1040, 700},
++        {1160, 840,1160, 840}
++};
++
++static const SiS_LVDSDesStruct SiS_PanelType1076_1[]=
++{  /* 1024x768 */
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0}
++};
++
++static const SiS_LVDSDesStruct SiS_PanelType1076_2[]=
++{  /* 1024x768 */
++      { 1184, 622 },
++      { 1184, 597 },
++      { 1184, 622 },
++      { 1184, 597 },
++      { 1152, 622 },
++      { 1232, 722 },
++      {    0, 0   },
++      {    0, 794 },
++      {    0, 0   }
++};
++
++static const SiS_LVDSDesStruct SiS_PanelType1210_1[]=
++{  /* 1280x1024 */
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0}
++};
++
++static const SiS_LVDSDesStruct SiS_PanelType1210_2[]=
++{  /* 1280x1024 */
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0}
++};
++
++static const SiS_LVDSDesStruct SiS_PanelType1296_1[]=
++{  /* 1400x1050 */
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0}
++};
++
++static const SiS_LVDSDesStruct SiS_PanelType1296_2[]=
++{  /* 1400x1050 - looks heavily invalid */
++      { 808 , 740},
++      { 0   , 715},
++      { 632 , 740},
++      { 632 , 715},
++      { 1307, 780},
++      { 1387,1157},
++      { 1499, 924},
++      { 1627,1052},
++      { 0 , 0}
++};
++
++static const SiS_LVDSDesStruct SiS_PanelType1600_1[]=
++{  /* 1600x1200 */
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0}
++};
++
++static const SiS_LVDSDesStruct SiS_PanelType1600_2[]=
++{  /* 1600x1200 - BIOS looks heavily invalid, not copied */
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0}
++};
++
++static const SiS_LVDSDesStruct  SiS_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  SiS_PanelTypeNS_2[] =
++{
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0},
++      { 0 , 0}
++};
++
++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}
++};
++
++static const SiS_LVDSCRT1DataStruct  SiS_LVDSCRT1320x480_1[] =
++{
++ {{0x65,0x4f,0x89,0x56,0x83,0xaa,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,0x54,0x9f,0xc4,0x1f,
++   0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
++   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 }},
++ {{0x2d,0x27,0x90,0x2c,0x80,0x0b,0x3e,
++   0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00,
++   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[] =
++{
++ {{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}},
++ {{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,
++   0x00}},
++ {{0xab,0x60,0x9f,0x80,0x04,0x24,0xbb,
++   0x3b,0x8d,0xc2,0xc1,0x00,0x00,0x02,
++   0x00}},
++ {{0xab,0x60,0x9f,0x80,0x04,0x24,0xbb,
++   0x54,0x86,0xdb,0xda,0x00,0x00,0x02,
++   0x00}},
++ {{0xab,0x60,0x9f,0x80,0x04,0x24,0xbb,
++   0x3b,0x8d,0xc2,0xc1,0x00,0x00,0x02,
++   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,
++   0x01}}
++};
++
++static const SiS_LVDSCRT1DataStruct  SiS_LVDSCRT11280x768_2_H[] =
++{
++ {{0x83,0x38,0x97,0x58,0x9c,0x24,0xbb,
++   0x54,0x86,0xdb,0xda,0x00,0x00,0x01,
++   0x00}},
++ {{0x83,0x38,0x97,0x58,0x9c,0x24,0xbb,
++   0x3b,0x8d,0xc2,0xc1,0x00,0x00,0x01,
++   0x00}},
++ {{0x83,0x38,0x97,0x58,0x9c,0x24,0xbb,
++   0x54,0x86,0xdb,0xda,0x00,0x00,0x01,
++   0x00}},
++ {{0x83,0x38,0x97,0x58,0x9c,0x24,0xbb,
++   0x3b,0x8d,0xc2,0xc1,0x00,0x00,0x01,
++   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}}
++};
++
++static const SiS_LVDSCRT1DataStruct  SiS_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  SiS_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  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[] =
++{
++ {{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}},
++ {{0x2d,0x27,0x90,0x2c,0x80,0x0b,0x3e,
++   0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00,
++   0x00}}
++};
++
++static const SiS_LVDSCRT1DataStruct  SiS_LVDSCRT1640x480_2_H[] =
++{
++ {{0x65,0x4f,0x89,0x56,0x83,0xaa,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,0x54,0x9f,0xc4,0x1f,
++   0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
++   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}},
++ {{0x2d,0x27,0x90,0x2c,0x80,0x0b,0x3e,
++   0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00,
++   0x00}}
++};
++
++static const SiS_LVDSCRT1DataStruct  SiS_LVDSCRT1640x480_3[] =
++{
++ {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e,
++   0xe9,0x8b,0xdf,0x04,0x00,0x00,0x05,
++   0x00}},
++ {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e,
++   0xe9,0x8b,0xdf,0x04,0x00,0x00,0x05,
++   0x00}},
++ {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e,
++   0xe9,0x8b,0xdf,0x04,0x00,0x00,0x05,
++   0x00}},
++ {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e,
++   0xe9,0x8b,0xdf,0x04,0x00,0x00,0x05,
++   0x00}},
++ {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e,
++   0xe9,0x8b,0xdf,0x04,0x00,0x00,0x05,
++   0x00}},
++ {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0,
++   0x58,0x8c,0x57,0x73,0x20,0x00,0x06,
++   0x01}},
++ {{0x2d,0x27,0x90,0x2c,0x80,0x0b,0x3e,
++   0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00,
++   0x00}}
++};
++
++static const SiS_LVDSCRT1DataStruct  SiS_LVDSCRT1640x480_3_H[] =
++{
++ {{0x65,0x4f,0x89,0x56,0x83,0xaa,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,0x54,0x9f,0xc4,0x1f,
++   0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
++   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}},
++ {{0x2d,0x27,0x90,0x2c,0x80,0x0b,0x3e,
++   0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00,
++   0x00}}
++};
++
++#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 *plasmaname;
++   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 }
++};
++
++static const SiS_PlasmaTables SiS_PlasmaTable[] = {
++#if 0  /* Product IDs missing */
++   { 0x38a3, 4,
++     { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
++     "NEC PlasmaSync 42VP4/42VP4D/42VP4G/42VP4DG",
++     14,   /* All DVI, except 0, 7, 13; 3, 15, 16 unknown */
++     { 0|0x40, 1|0xc0, 2|0xc0, 3|0xc0, 4|0xc0, 7|0x40, 9|0xc0,10|0xc0,11|0xc0,12|0xc0,
++      13|0x40,14|0xc0,15|0xc0,16|0xc0, 0     , 0     , 0     , 0     , 0     , 0 }
++   },
++   { 0x38a3, 3,
++     { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
++     "NEC PlasmaSync 42PD1/50PD1/50PD2",
++     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",
++     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",
++     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",
++     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",
++     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       }
++   },
++#endif
++   { 0x38a3, 4,
++     { 0xa482, 0xa483, 0x0000, 0x0000, 0x0000 },
++     "NEC PlasmaSync 42MP3/42MP4/50MP2/61MP1",
++     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",
++     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",
++     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",
++     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",
++     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",
++     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       }
++   },
++   { 0x0000 }
++};
++
+ void     SiS_SetReg1(USHORT, USHORT, USHORT);
+ void     SiS_SetReg2(SiS_Private *, USHORT, USHORT, USHORT);
+ void     SiS_SetReg3(USHORT, USHORT);
+@@ -158,6 +2397,7 @@ void     SiS_SetMemoryClock(SiS_Private 
+ void     SiS_SetDRAMModeRegister(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+ BOOLEAN  SiS_SearchVBModeID(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT *ModeNo);
+ void     SiS_IsLowResolution(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
++void     SiS_GetSysFlags(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+ #ifdef SIS300
+ void     SiS_SetDRAMSize_300(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+@@ -192,12 +2432,15 @@ void     SiS_VerifyMclk(SiS_Private *SiS
+ void     SiS_HandleCRT1(SiS_Private *SiS_Pr);
+ void     SiS_Handle301B_1400x1050(SiS_Private *SiS_Pr, USHORT ModeNo);
+-void     SiS_SetEnableDstn(SiS_Private *SiS_Pr);
++void     SiS_SetEnableDstn(SiS_Private *SiS_Pr, int enable);
++void     SiS_SetEnableFstn(SiS_Private *SiS_Pr, int enable);
+ void     SiS_Delay15us(SiS_Private *SiS_Pr);
+ BOOLEAN  SiS_SearchModeID(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT *ModeNo,USHORT *ModeIdIndex);
+ BOOLEAN  SiS_CheckMemorySize(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                              USHORT ModeNo,USHORT ModeIdIndex);
+ UCHAR    SiS_GetModePtr(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT ModeNo,USHORT ModeIdIndex);
++void     SiS_WhatTheHellIsThis(SiS_Private *SiS_Pr,PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr);
++void     SiS_StrangeStuff(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+ void     SiS_SetSeqRegs(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT StandTableIndex);
+ void     SiS_SetMiscRegs(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT StandTableIndex);
+ void     SiS_SetCRTCRegs(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
+@@ -267,26 +2510,26 @@ void            SiS_SetPitchCRT1(SiS_Private *S
+ void          SiS_SetPitchCRT2(SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, UShort BaseAddr);
+ 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 unsigned char SiS_GetSetBIOSScratch(ScrnInfoPtr pScrn, USHORT offset, unsigned char value);
+ extern unsigned char SiS_GetSetModeID(ScrnInfoPtr pScrn, unsigned char id);
+-extern USHORT              SiS_CalcModeIndex(ScrnInfoPtr pScrn, DisplayModePtr mode);
++extern USHORT              SiS_CalcModeIndex(ScrnInfoPtr pScrn, DisplayModePtr mode, BOOLEAN hcm);
+ #endif
+ extern USHORT    SiS_GetOffset(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                        USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+ extern USHORT    SiS_GetColorDepth(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+ extern void      SiS_DisableBridge(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+-extern BOOLEAN   SiS_SetCRT2Group301(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
+-                                     PSIS_HW_DEVICE_INFO HwDeviceExtension);
+-extern void      SiS_PresetScratchregister(SiS_Private *SiS_Pr, USHORT SiS_P3d4,
+-                                           PSIS_HW_DEVICE_INFO HwDeviceExtension);
++extern BOOLEAN   SiS_SetCRT2Group(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
++                                  PSIS_HW_DEVICE_INFO HwDeviceExtension);
+ extern void      SiS_UnLockCRT2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr);
+ extern void      SiS_LockCRT2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr);
+ extern BOOLEAN   SiS_BridgeIsOn(SiS_Private *SiS_Pr, USHORT BaseAddr);
+ extern BOOLEAN   SiS_BridgeIsEnable(SiS_Private *SiS_Pr, USHORT BaseAddr,PSIS_HW_DEVICE_INFO );
+ extern void      SiS_GetVBInfo(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
+                                USHORT ModeIdIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension, int chkcrt2mode);
+-extern BOOLEAN   SiS_GetLCDResInfo(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,
++extern void      SiS_GetLCDResInfo(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,
+                                    USHORT ModeIdIndex, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+ extern void      SiS_SetHiVision(SiS_Private *SiS_Pr, USHORT BaseAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+ extern USHORT    SiS_GetRatePtrCRT2(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT ModeNo,USHORT ModeIdIndex,
+@@ -321,10 +2564,12 @@ int    sisfb_mode_rate_to_dclock(SiS_Pri
+                             unsigned char modeno, unsigned char rateindex);
+ int    sisfb_mode_rate_to_ddata(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                        unsigned char modeno, unsigned char rateindex,
+-                       ULONG *left_margin, ULONG *right_margin, 
++                       ULONG *left_margin, ULONG *right_margin,
+                        ULONG *upper_margin, ULONG *lower_margin,
+                        ULONG *hsync_len, ULONG *vsync_len,
+                        ULONG *sync, ULONG *vmode);
++BOOLEAN sisfb_gettotalfrommode(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
++                     unsigned char modeno, int *htotal, int *vtotal, unsigned char rateindex);
+ #endif
+ #endif
+--- linux-2.6.0-test6/drivers/video/sis/oem300.h       2003-06-14 12:18:05.000000000 -0700
++++ 25/drivers/video/sis/oem300.h      2003-10-05 00:34:22.000000000 -0700
+@@ -1,5 +1,37 @@
+-
+-/* OEM Data for 300 series */
++/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/sis/oem300.h.c,v 1.0 2001/11/30 12:12:01 eich Exp $ */
++/*
++ * OEM Data for 300 series
++ *
++ * Copyright 2002, 2003 by Thomas Winischhofer, Vienna, Austria
++ *
++ * If distributed as part of the linux kernel, the contents of this file
++ * is entirely covered by the GPL.
++ *
++ * Otherwise, the following terms apply:
++ *
++ * Permission to use, copy, modify, distribute, and sell this software and its
++ * documentation for any purpose is hereby granted without fee, provided that
++ * the above copyright notice appear in all copies and that both that
++ * copyright notice and this permission notice appear in supporting
++ * documentation, and that the name of the copyright holder not be used in
++ * advertising or publicity pertaining to distribution of the software without
++ * specific, written prior permission.  The copyright holder makes no representations
++ * about the suitability of this software for any purpose.  It is provided
++ * "as is" without express or implied warranty.
++ *
++ * THE COPYRIGHT HOLDER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
++ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
++ * EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR
++ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
++ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
++ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ *
++ * Author:    Thomas Winischhofer <thomas@winischhofer.net>
++ *
++ * Based on code by Silicon Intergrated Systems
++ *
++ */
+ const UCHAR SiS300_OEMTVDelay301[8][4] =
+ {
+@@ -680,325 +712,147 @@ const UCHAR SiS300_Filter2[10][9][7] =
+     }
+ };
+-const UCHAR SiS300_LCDHData[24][11][5] = {
++/* Custom data for Barco iQ Pro R300 */
++const UCHAR barco_p1[2][9][7][3] = {
+     {
+-        {0x67,0x91,0x84,0x5e,0x00},
+-      {0x67,0x91,0x84,0x5e,0x00},
+-      {0x67,0x91,0x84,0x5e,0x00},
+-      {0x67,0x91,0x84,0x5e,0x00},
+-      {0x67,0x91,0x84,0x5e,0x00},
+-      {0x67,0x91,0x84,0x5e,0x00},
+-      {0x67,0x91,0x84,0x5e,0x00},
+-      {0x65,0xef,0x83,0x5c,0x00},
+-      {0x65,0xef,0x83,0x5c,0x00},
+-      {0x8a,0x14,0x00,0x80,0x00},
+-      {0x8a,0x14,0x00,0x80,0x00}
+-    },
+-    {
+-        {0x4e,0x18,0x90,0x38,0x00},
+-      {0x4e,0x18,0x90,0x38,0x00},
+-      {0x8e,0x18,0x28,0x78,0x00},
+-      {0x8e,0x18,0x28,0x78,0x00},
+-      {0x8e,0x18,0x28,0x78,0x00},
+-      {0x4e,0x18,0x90,0x38,0x00},
+-      {0x4e,0x18,0x90,0x38,0x00},
+-      {0x67,0x11,0x9a,0x56,0x00},
+-        {0x67,0x11,0x9a,0x56,0x00},
+-      {0x8a,0x14,0x00,0x80,0x00},
+-      {0x8a,0x14,0x00,0x80,0x00}
+-    },
+-    {
+-        {0x67,0x91,0x84,0x5e,0x00},
+-      {0x67,0x91,0x84,0x5e,0x00},
+-      {0x67,0x91,0x84,0x5e,0x00},
+-      {0x67,0x91,0x84,0x5e,0x00},
+-      {0x67,0x91,0x84,0x5e,0x00},
+-      {0x67,0x91,0x84,0x5e,0x00},
+-      {0x67,0x91,0x84,0x5e,0x00},
+-      {0x65,0xef,0x83,0x5c,0x00},
+-      {0x65,0xef,0x83,0x5c,0x00},
+-      {0x8a,0x14,0x00,0x80,0x00},
+-      {0x8a,0x14,0x00,0x80,0x00}
+-    },
+-    {
+-      {0x4e,0x18,0x90,0x38,0x00},
+-      {0x4e,0x18,0x90,0x38,0x00},
+-      {0x8e,0x18,0x28,0x78,0x00},
+-      {0x8e,0x18,0x28,0x78,0x00},
+-      {0x8e,0x18,0x28,0x78,0x00},
+-      {0x4e,0x18,0x90,0x38,0x00},
+-      {0x4e,0x18,0x90,0x38,0x00},
+-      {0x67,0x11,0x9a,0x56,0x00},
+-      {0x67,0x11,0x9a,0x56,0x00},
+-      {0x8a,0x14,0x00,0x80,0x00},
+-      {0x8a,0x14,0x00,0x80,0x00}
+-    },
+-    {
+-      {0x67,0x91,0x84,0x5e,0x00},
+-      {0x67,0x91,0x84,0x5e,0x00},
+-      {0x67,0x91,0x84,0x5e,0x00},
+-      {0x67,0x91,0x84,0x5e,0x00},
+-      {0x67,0x91,0x84,0x5e,0x00},
+-      {0x67,0x91,0x84,0x5e,0x00},
+-      {0x67,0x91,0x84,0x5e,0x00},
+-      {0x65,0xef,0x83,0x5c,0x00},
+-      {0x65,0xef,0x83,0x5c,0x00},
+-      {0x8a,0x14,0x00,0x80,0x00},
+-      {0x8a,0x14,0x00,0x80,0x00}
+-    },
+-    {
+-        {0x4E,0x18,0x90,0x38,0x00},
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x8E,0x18,0x28,0x78,0x00},
+-      {0x8E,0x18,0x28,0x78,0x00},
+-      {0x8E,0x18,0x28,0x78,0x00},
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x67,0x11,0x9A,0x56,0x00},
+-      {0x67,0x11,0x9A,0x56,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00}
+-    },
+-    {
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x65,0xEF,0x83,0x5C,0x00},
+-      {0x65,0xEF,0x83,0x5C,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00}
+-    },
+-    {
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x8E,0x18,0x28,0x78,0x00},
+-      {0x8E,0x18,0x28,0x78,0x00},
+-      {0x8E,0x18,0x28,0x78,0x00},
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x67,0x11,0x9A,0x56,0x00},
+-      {0x67,0x11,0x9A,0x56,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00}
+-    },
+-    {
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x65,0xEF,0x83,0x5C,0x00},
+-      {0x65,0xEF,0x83,0x5C,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00}
+-    },
+-    {
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x8E,0x18,0x28,0x78,0x00},
+-      {0x8E,0x18,0x28,0x78,0x00},
+-      {0x8E,0x18,0x28,0x78,0x00},
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x67,0x11,0x9A,0x56,0x00},
+-      {0x67,0x11,0x9A,0x56,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00}
+-    },
+-    {
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x65,0xEF,0x83,0x5C,0x00},
+-      {0x65,0xEF,0x83,0x5C,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00}
+-    },
+-    {
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x8E,0x18,0x28,0x78,0x00},
+-      {0x8E,0x18,0x28,0x78,0x00},
+-      {0x8E,0x18,0x28,0x78,0x00},
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x67,0x11,0x9A,0x56,0x00},
+-      {0x67,0x11,0x9A,0x56,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00}
+-    },
+-    {
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x65,0xEF,0x83,0x5C,0x00},
+-      {0x65,0xEF,0x83,0x5C,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00}
+-    },
+-    {
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x8E,0x18,0x28,0x78,0x00},
+-      {0x8E,0x18,0x28,0x78,0x00},
+-      {0x8E,0x18,0x28,0x78,0x00},
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x67,0x11,0x9A,0x56,0x00},
+-      {0x67,0x11,0x9A,0x56,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00}
+-    },
+-    {
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x65,0xEF,0x83,0x5C,0x00},
+-      {0x65,0xEF,0x83,0x5C,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00}
+-    },
+-    {
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x8E,0x18,0x28,0x78,0x00},
+-      {0x8E,0x18,0x28,0x78,0x00},
+-      {0x8E,0x18,0x28,0x78,0x00},
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x67,0x11,0x9A,0x56,0x00},
+-      {0x67,0x11,0x9A,0x56,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00}
+-    },
+-    {
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x65,0xEF,0x83,0x5C,0x00},
+-      {0x65,0xEF,0x83,0x5C,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00}
+-    },
+-    {
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x8E,0x18,0x28,0x78,0x00},
+-      {0x8E,0x18,0x28,0x78,0x00},
+-      {0x8E,0x18,0x28,0x78,0x00},
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x67,0x11,0x9A,0x56,0x00},
+-      {0x67,0x11,0x9A,0x56,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00}
+-    },
+-    {
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x65,0xEF,0x83,0x5C,0x00},
+-      {0x65,0xEF,0x83,0x5C,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00}
+-    },
+-    {
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x8E,0x18,0x28,0x78,0x00},
+-      {0x8E,0x18,0x28,0x78,0x00},
+-      {0x8E,0x18,0x28,0x78,0x00},
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x67,0x11,0x9A,0x56,0x00},
+-      {0x67,0x11,0x9A,0x56,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00}
+-    },
+-    {
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x65,0xEF,0x83,0x5C,0x00},
+-      {0x65,0xEF,0x83,0x5C,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00}
+-    },
+-    {
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x8E,0x18,0x28,0x78,0x00},
+-      {0x8E,0x18,0x28,0x78,0x00},
+-      {0x8E,0x18,0x28,0x78,0x00},
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x67,0x11,0x9A,0x56,0x00},
+-      {0x67,0x11,0x9A,0x56,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00}
+-    },
+-    {
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x67,0x91,0x84,0x5E,0x00},
+-      {0x65,0xEF,0x83,0x5C,0x00},
+-      {0x65,0xEF,0x83,0x5C,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00}
+-    },
+-    {
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x8E,0x18,0x28,0x78,0x00},
+-      {0x8E,0x18,0x28,0x78,0x00},
+-      {0x8E,0x18,0x28,0x78,0x00},
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x4E,0x18,0x90,0x38,0x00},
+-      {0x67,0x11,0x9A,0x56,0x00},
+-      {0x67,0x11,0x9A,0x56,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00},
+-      {0x8A,0x14,0x00,0x80,0x00}
++      {  { 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 }
++      }
+     }
+ };
+-#if 0
+-const UCHAR SiS300_LCDVData[24][11][6] = {
+-    {
+-        {
+-    },
+-};
+-#endif
++
++
++
++
++
+--- linux-2.6.0-test6/drivers/video/sis/oem310.h       2003-06-14 12:17:55.000000000 -0700
++++ 25/drivers/video/sis/oem310.h      2003-10-05 00:34:22.000000000 -0700
+@@ -1,5 +1,37 @@
+-
+-/* OEM Data for 310/325/330 series */
++/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/sis/oem300.h.c,v 1.0 2001/11/30 12:12:01 eich Exp $ */
++/*
++ * OEM Data for 315/330 series
++ *
++ * Copyright 2002, 2003 by Thomas Winischhofer, Vienna, Austria
++ *
++ * If distributed as part of the linux kernel, the contents of this file
++ * is entirely covered by the GPL.
++ *
++ * Otherwise, the following terms apply:
++ *
++ * Permission to use, copy, modify, distribute, and sell this software and its
++ * documentation for any purpose is hereby granted without fee, provided that
++ * the above copyright notice appear in all copies and that both that
++ * copyright notice and this permission notice appear in supporting
++ * documentation, and that the name of the copyright holder not be used in
++ * advertising or publicity pertaining to distribution of the software without
++ * specific, written prior permission.  The copyright holder makes no representations
++ * about the suitability of this software for any purpose.  It is provided
++ * "as is" without express or implied warranty.
++ *
++ * THE COPYRIGHT HOLDER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
++ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
++ * EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR
++ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
++ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
++ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ *
++ * Author:    Thomas Winischhofer <thomas@winischhofer.net>
++ *
++ * Based on code by Silicon Intergrated Systems
++ *
++ */
+ const UCHAR SiS310_LCDDelayCompensation_301[] =               /* 301 */
+ {
+@@ -100,7 +132,7 @@ const UCHAR SiS310_LCDDelayCompensation_
+ const UCHAR SiS310_LCDDelayCompensation_651301LV[] =    /* M650/651 301LV */
+ {
+-                 0x33,0x33,0x33,    /*   800x600 (guessed) */
++                 0x33,0x33,0x33,    /*   800x600 (guessed) - new: PanelType, not PanelRes ! */
+                0x33,0x33,0x33,    /*  1024x768 */
+                0x33,0x33,0x33,    /* 1280x1024 */
+                0x33,0x33,0x33,    /*   640x480 (unknown) */
+@@ -361,5 +393,55 @@ const UCHAR SiS310_TVPhaseIncr2[3][2][4]
+  }
+ };
++/* OEM data for Compaq Presario 3045US */
++static const SiS_LCDDataStruct  SiS310_ExtCompaq1280x1024Data[] =
++{
++      {  211,  60,1024, 501,1688,1066},
++      {  211,  60,1024, 508,1688,1066},
++      {  211,  60,1024, 501,1688,1066},
++      {  211,  60,1024, 508,1688,1066},
++      {   32,  15,1696, 501,1696,1066},
++      {  212,  75,1024, 621,1696,1066},
++      {    4,   3,1696, 810,1696,1066},
++      {    1,   1,1696,1066,1696,1066}
++};
++
++static const SiS_Part2PortTblStruct SiS310_CRT2Part2_Compaq1280x1024_1[] =
++{
++ {{0x3F,0x1B,0xD0,0xF0,0xB0,0xB8,0x23,0x0A,0x07,0x14,0x8A,0x12}},
++ {{0x35,0x1B,0xA0,0xC0,0x80,0xB8,0x23,0x0A,0x07,0x14,0x8A,0x12}},
++ {{0x3F,0x1B,0xD0,0xF0,0xB0,0xB8,0x23,0x0A,0x07,0x14,0x8A,0x12}},
++ {{0x3F,0x1B,0xD0,0xF0,0xB0,0xB8,0x23,0x0A,0x07,0x14,0x8A,0x12}},
++ {{0x45,0x1C,0x20,0x3F,0xFF,0xB8,0x23,0x0A,0x07,0x14,0x8A,0x12}},
++ {{0x49,0x1C,0x40,0x7F,0xFF,0xAD,0x23,0x0A,0x07,0xF3,0x8A,0x12}},
++ {{0x4C,0x1C,0x18,0x2F,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}},
++ {{0x48,0x1C,0x15,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}}
++};
++
++static const SiS_Part2PortTblStruct SiS310_CRT2Part2_Compaq1280x1024_2[] =
++{
++ {{0x2B,0x12,0xD9,0xE5,0xD5,0x2C,0x23,0x98,0x27,0x3E,0x08,0x42}},
++ {{0x22,0x12,0xC0,0xCC,0xBC,0x2C,0x23,0x98,0x27,0x3E,0x08,0x42}},
++ {{0x2B,0x12,0xD9,0xE5,0xD5,0x2C,0x23,0x98,0x27,0x3E,0x08,0x42}},
++ {{0x22,0x12,0xC0,0xCC,0xBC,0x2C,0x23,0x98,0x27,0x3E,0x08,0x42}},
++ {{0x33,0x13,0x01,0x0D,0xFD,0x2C,0x23,0x98,0x27,0x3E,0x08,0x42}},
++ {{0x3F,0x1B,0x3D,0x49,0x39,0x54,0x23,0xC0,0x27,0x66,0x30,0x42}},
++ {{0x33,0x1B,0x91,0x9D,0x8D,0x8C,0x23,0xF8,0x27,0x9E,0x68,0x42}},
++ {{0x43,0x24,0x11,0x1D,0x0D,0xCC,0x23,0x38,0x37,0xDE,0xA8,0x42}},
++ {{0x43,0x24,0x21,0x29,0x19,0xEA,0x23,0x0A,0x07,0x32,0xC6,0x42}}
++};
++
++static const SiS_Part2PortTblStruct SiS310_CRT2Part2_Compaq1280x1024_3[] =
++{
++ {{0x47,0x1C,0x14,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}},
++ {{0x47,0x1C,0x14,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}},
++ {{0x47,0x1C,0x14,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}},
++ {{0x47,0x1C,0x14,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}},
++ {{0x47,0x1C,0x14,0x29,0xFF,0xBE,0x23,0x0A,0x07,0x26,0x8A,0x42}},
++ {{0x47,0x1C,0x14,0x29,0xFF,0xBE,0x23,0x0A,0x07,0x26,0x8A,0x42}},
++ {{0x47,0x1C,0x14,0x29,0xFF,0xBE,0x23,0x0A,0x07,0x26,0x8A,0x42}},
++ {{0x47,0x1C,0x14,0x29,0xFF,0xBE,0x23,0x0A,0x07,0x26,0x8A,0x42}}
++};
++
+--- linux-2.6.0-test6/drivers/video/sis/osdef.h        2003-06-14 12:17:56.000000000 -0700
++++ 25/drivers/video/sis/osdef.h       2003-10-05 00:34:22.000000000 -0700
+@@ -1,79 +1,43 @@
+-/* #define WINCE_HEADER */
+-/* #define WIN2000 */
+-/* #define TC */
++
++/* OS depending defines */
++
++/* The choices are: */
++
+ #define LINUX_KERNEL     /* Kernel framebuffer */
+ /* #define LINUX_XF86 */   /* XFree86 */
+ /**********************************************************************/
+-#ifdef LINUX_KERNEL
+-      #include <linux/config.h>
+-      #include <linux/version.h>
+-      #ifdef CONFIG_FB_SIS_300
+-              #define SIS300
+-      #endif
+-
+-      #ifdef CONFIG_FB_SIS_315
+-              #define SIS315H
+-      #endif
+-      #if 1
+-              #define SISFBACCEL      /* Include 2D acceleration */
+-      #endif
+-      #if 1
+-              #define SISFB_PAN       /* Include Y-Panning code */
+-      #endif
+-#else
+-/*    #define SIS300*/
+-      #define SIS315H
+-#endif
+-#ifdef LINUX_XF86
+-      #define SIS300
+-      /* #define SIS315H */ /* TW: done above */
+-#endif
++#ifdef LINUX_KERNEL  /* -------------------------- */
++#include <linux/config.h>
++#include <linux/version.h>
+-/**********************************************************************/
+-#ifdef TC
+-#endif
+-#ifdef WIN2000
+-#endif
+-#ifdef WINCE_HEADER
+-#endif
+-#ifdef LINUX_XF86
++#ifdef CONFIG_FB_SIS_300
++#define SIS300
+ #endif
+-#ifdef LINUX_KERNEL
+-#endif
+-/**********************************************************************/
+-#ifdef TC
+-#define SiS_SetMemory(MemoryAddress,MemorySize,value) memset(MemoryAddress, value, MemorySize);
+-#endif
+-#ifdef WIN2000
+-#define SiS_SetMemory(MemoryAddress,MemorySize,value) MemFill((PVOID) MemoryAddress,(ULONG) MemorySize,(UCHAR) value);
++
++#ifdef CONFIG_FB_SIS_315
++#define SIS315H
+ #endif
+-#ifdef WINCE_HEADER
+-#define SiS_SetMemory(MemoryAddress,MemorySize,value) memset(MemoryAddress, value, MemorySize);
++
++#if 1
++#define SISFBACCEL    /* Include 2D acceleration */
+ #endif
+-#ifdef LINUX_XF86
+-#define SiS_SetMemory(MemoryAddress,MemorySize,value) memset(MemoryAddress, value, MemorySize)
++
+ #endif
+-#ifdef LINUX_KERNEL
+-#define SiS_SetMemory(MemoryAddress,MemorySize,value) memset(MemoryAddress, value, MemorySize)
++
++#ifdef LINUX_XF86 /* ----------------------------- */
++#define SIS300
++#define SIS315H
+ #endif
+-/**********************************************************************/
+ /**********************************************************************/
+-
+-#ifdef TC
+-#define SiS_MemoryCopy(Destination,Soruce,Length) memmove(Destination, Soruce, Length);
+-#endif
+-#ifdef WIN2000
+-#define SiS_MemoryCopy(Destination,Soruce,Length)  /*VideoPortMoveMemory((PUCHAR)Destination , Soruce,length);*/
+-#endif
+-#ifdef WINCE_HEADER
+-#define SiS_MemoryCopy(Destination,Soruce,Length) memmove(Destination, Soruce, Length);
+-#endif
+ #ifdef LINUX_XF86
++#define SiS_SetMemory(MemoryAddress,MemorySize,value) memset(MemoryAddress, value, MemorySize)
+ #define SiS_MemoryCopy(Destination,Soruce,Length) memcpy(Destination,Soruce,Length)
+ #endif
++
+ #ifdef LINUX_KERNEL
++#define SiS_SetMemory(MemoryAddress,MemorySize,value) memset(MemoryAddress, value, MemorySize)
+ #define SiS_MemoryCopy(Destination,Soruce,Length) memcpy(Destination,Soruce,Length)
+ #endif
+@@ -104,19 +68,6 @@
+ #endif /* InPortLong */
+ /**********************************************************************/
+-/*  TC                                                                */
+-/**********************************************************************/
+-
+-#ifdef TC
+-#define OutPortByte(p,v) outp((unsigned short)(p),(unsigned char)(v))
+-#define OutPortWord(p,v) outp((unsigned short)(p),(unsigned short)(v))
+-#define OutPortLong(p,v) outp((unsigned short)(p),(unsigned long)(v))
+-#define InPortByte(p)    inp((unsigned short)(p))
+-#define InPortWord(p)    inp((unsigned short)(p))
+-#define InPortLong(p)    ((inp((unsigned short)(p+2))<<16) | inp((unsigned short)(p)))
+-#endif
+-
+-/**********************************************************************/
+ /*  LINUX XF86                                                        */
+ /**********************************************************************/
+@@ -142,29 +93,4 @@
+ #define InPortLong(p)    inl((u16)(p))
+ #endif
+-/**********************************************************************/
+-/*  WIN 2000                                                          */
+-/**********************************************************************/
+-
+-#ifdef WIN2000
+-#define OutPortByte(p,v) VideoPortWritePortUchar ((PUCHAR) (p), (UCHAR) (v))
+-#define OutPortWord(p,v) VideoPortWritePortUshort((PUSHORT) (p), (USHORT) (v))
+-#define OutPortLong(p,v) VideoPortWritePortUlong ((PULONG) (p), (ULONG) (v))
+-#define InPortByte(p)    VideoPortReadPortUchar  ((PUCHAR) (p))
+-#define InPortWord(p)    VideoPortReadPortUshort ((PUSHORT) (p))
+-#define InPortLong(p)    VideoPortReadPortUlong  ((PULONG) (p))
+-#endif
+-
+-/**********************************************************************/
+-/*  WIN CE                                                            */
+-/**********************************************************************/
+-
+-#ifdef WINCE_HEADER
+-#define OutPortByte(p,v) WRITE_PORT_UCHAR ((PUCHAR) (p), (UCHAR) (v))
+-#define OutPortWord(p,v) WRITE_PORT_USHORT((PUSHORT) (p), (USHORT) (v))
+-#define OutPortLong(p,v) WRITE_PORT_ULONG ((PULONG) (p), (ULONG) (v))
+-#define InPortByte(p)    READ_PORT_UCHAR  ((PUCHAR) (p))
+-#define InPortWord(p)    READ_PORT_USHORT ((PUSHORT) (p))
+-#define InPortLong(p)    READ_PORT_ULONG  ((PULONG) (p))
+-#endif
+--- linux-2.6.0-test6/drivers/video/sis/sis_accel.c    2003-06-14 12:18:52.000000000 -0700
++++ 25/drivers/video/sis/sis_accel.c   2003-10-05 00:34:22.000000000 -0700
+@@ -1,5 +1,5 @@
+ /*
+- * SiS 300/630/730/540/315/550/650/740 frame buffer driver
++ * SiS 300/630/730/540/315/550/650/740/330/660 frame buffer driver
+  * for Linux kernels 2.4.x and 2.5.x
+  *
+  * 2D acceleration part
+@@ -211,7 +211,7 @@ SiS300SubsequentSolidFillRect(int x, int
+       SiS300DoCMD
+ }
+-/* 310/325 series ------------------------------------------------ */
++/* 315 series ---------------------------------------------------- */
+ static void
+ SiS310SetupForScreenToScreenCopy(int xdir, int ydir, int rop,
+@@ -230,7 +230,7 @@ SiS310SetupForScreenToScreenCopy(int xdi
+               /* SiSSetupCMDFlag(BITBLT | SRCVIDEO) */
+       }
+       SiS310SetupCMDFlag(ivideo.SiS310_AccelDepth)
+-      /* TW: The 310/325 series is smart enough to know the direction */
++      /* The 315 series is smart enough to know the direction */
+ }
+ static void
+@@ -328,11 +328,13 @@ void sisfb_syncaccel(void)
+     }
+ }
+-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)  /* --- KERNEL 2.5.34 and later --- */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)  /* --------------- 2.5 --------------- */
+ int fbcon_sis_sync(struct fb_info *info)
+ {
+-   if(!sisfb_accel) return 0;
++   if(!ivideo.accel)
++      return 0;
++
+    CRITFLAGS
+    if(sisvga_engine == SIS_300_VGA) {
+       SiS300Sync();
+@@ -352,7 +354,7 @@ void fbcon_sis_fillrect(struct fb_info *
+    if(!rect->width || !rect->height)
+       return;
+-   if(!sisfb_accel) {
++   if(!ivideo.accel) {
+       cfb_fillrect(info, rect);
+       return;
+    }
+@@ -388,7 +390,7 @@ void fbcon_sis_copyarea(struct fb_info *
+    CRITFLAGS
+    TWDEBUG("Inside sis_copyarea");
+-   if(!sisfb_accel) {
++   if(!ivideo.accel) {
+       cfb_copyarea(info, area);
+       return;
+    }
+@@ -418,7 +420,7 @@ void fbcon_sis_copyarea(struct fb_info *
+ #endif
+-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)  /* ------ KERNEL <2.5.34 ------ */
++#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)
+@@ -591,38 +593,38 @@ void fbcon_sis_revc(struct display *p, i
+ #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)
++      .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)
++      .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)
++      .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
+--- linux-2.6.0-test6/drivers/video/sis/sis_accel.h    2003-06-14 12:18:08.000000000 -0700
++++ 25/drivers/video/sis/sis_accel.h   2003-10-05 00:34:22.000000000 -0700
+@@ -47,7 +47,7 @@
+ #define TRAPAZOID_FILL          0x00000005  /* Fill trapezoid */
+ #define TRANSPARENT_BITBLT      0x00000006  /* Transparent Blit */
+-/* Additional engine commands for 310/325 */
++/* Additional engine commands for 315 */
+ #define ALPHA_BLEND           0x00000007  /* Alpha blend ? */
+ #define A3D_FUNCTION          0x00000008  /* 3D command ? */
+ #define       CLEAR_Z_BUFFER          0x00000009  /* ? */
+@@ -90,11 +90,11 @@
+ #define NO_RESET_COUNTER        0x00400000
+ #define NO_LAST_PIXEL           0x00200000
+-/* Subfunctions for Color/Enhanced Color Expansion (310/325 only) */
++/* Subfunctions for Color/Enhanced Color Expansion (315 only) */
+ #define COLOR_TO_MONO         0x00100000
+ #define AA_TEXT                       0x00200000
+-/* Some general registers for 310/325 series */
++/* Some general registers for 315 series */
+ #define SRC_ADDR              0x8200
+ #define SRC_PITCH             0x8204
+ #define AGP_BASE              0x8206 /* color-depth dependent value */
+@@ -326,7 +326,7 @@ int     CmdQueLen;
+-/* ----------- SiS 310/325 series --------------- */
++/* -------------- SiS 315 series --------------- */
+ /* Q_STATUS:
+    bit 31 = 1: All engines idle and all queues empty
+@@ -342,16 +342,27 @@ int     CmdQueLen;
+    bits 7:0:   2D counter 1
+    Where is the command queue length (current amount of commands the queue
+-   can accept) on the 310/325 series? (The current implementation is taken
+-   from 300 series and certainly wrong...)
++   can accept) on the 315 series?
+ */
+ /* TW: FIXME: CmdQueLen is... where....? */
++/* We assume a length of 4 bytes per command; since 512K of
++ * of RAM are allocated, the number of commands is easily
++ * calculated (assuming that there is no 3D support yet)
++ * We calculate it very cautiously (128K only) and let the
++ * rest to the (never?)-to-come (?) 3D engine. (The 3D engine
++ * can use a similar technique, using the remaining 384K,
++ * hence a queue overflow is avoided)
++ * UPDATE: This technique causes a terrible system latency
++ * on integrated chipsets. Disable the queue handling for
++ * now.
++ */
+ #define SiS310Idle \
+   { \
+   while( (MMIO_IN16(ivideo.mmio_vbase, Q_STATUS+2) & 0x8000) != 0x8000){}; \
+   while( (MMIO_IN16(ivideo.mmio_vbase, Q_STATUS+2) & 0x8000) != 0x8000){}; \
+-  CmdQueLen=MMIO_IN16(ivideo.mmio_vbase, Q_STATUS); \
++  CmdQueLen = 0; \
++  /*CmdQueLen = ((128 * 1024) / 4) - 64; */ \
+   }
+ #define SiS310SetupSRCBase(base) \
+--- linux-2.6.0-test6/drivers/video/sis/sis_main.c     2003-06-14 12:18:25.000000000 -0700
++++ 25/drivers/video/sis/sis_main.c    2003-10-05 00:34:22.000000000 -0700
+@@ -1,25 +1,20 @@
+ /*
+- * SiS 300/630/730/540/315/550/650/740 frame buffer device
++ * SiS 300/630/730/540/315/550/650/740/330/660/760 frame buffer driver
+  * for Linux kernels 2.4.x and 2.5.x
+  *
+- * Partly based on the VBE 2.0 compliant graphic boards framebuffer driver,
++ * (C) 1999 Silicon Integrated Systems, Inc.
++ * (C) 2001-2003 Thomas Winischhofer, Vienna, Austria.
++ *
++ * Author:    Thomas Winischhofer <thomas@winischhofer.net>
++ *
++ * Author of code base:
++ *            SiS (www.sis.com.tw)
++ *
++ * See http://www.winischhofer.net/ for more information and updates
++ *
++ * Originally based on the VBE 2.0 compliant graphic boards framebuffer driver,
+  * which is (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+  *
+- * Authors:           SiS (www.sis.com.tw)
+- *            (Various others)
+- *            Thomas Winischhofer <thomas@winischhofer.net>:
+- *                    - SiS Xabre (330) support
+- *                    - many fixes and enhancements for all chipset series,
+- *                    - extended bridge handling, TV output for Chrontel 7005
+- *                      - 650/LVDS support (for LCD panels up to 1600x1200)
+- *                      - 650/740/Chrontel 7019 support
+- *                      - 30xB/30xLV LCD, TV and VGA2 support
+- *                    - memory queue handling enhancements,
+- *                      - 2D acceleration and y-panning,
+- *                      - portation to 2.5 API
+- *                    - etc.
+- *                    (see http://www.winischhofer.net/
+- *                    for more information and updates)
+  */
+ #include <linux/config.h>
+@@ -43,6 +38,8 @@
+ #include <linux/fs.h>
+ #include <linux/agp_backend.h>
+ #include <linux/types.h>
++#include <linux/vmalloc.h>
++#include <asm/uaccess.h>
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+ #include <linux/spinlock.h>
+@@ -79,6 +76,12 @@
+ #endif
+ #endif
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,69)
++#error "This version of sisfb requires at least 2.5.69"
++#endif
++#endif
++
+ /* -------------------- Macro definitions ---------------------------- */
+ #undef SISFBDEBUG     /* TW: no debugging */
+@@ -134,9 +137,19 @@ sisfb_query_VGA_config_space(PSIS_HW_DEV
+       if (!init) {
+               init = TRUE;
+-              pdev = pci_find_device(PCI_VENDOR_ID_SI, ivideo.chip_id, pdev);
+-              if (pdev)
+-                      valid_pdev = TRUE;
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,74)
++              pci_for_each_dev(pdev) {
++#else
++              while((pdev = pci_find_device(PCI_VENDOR_ID_SI, PCI_ANY_ID, pdev))) {
++#endif
++                      DPRINTK("sisfb: Current: 0x%x, target: 0x%x\n",
++                               pdev->device, ivideo.chip_id);
++                      if ((pdev->vendor == PCI_VENDOR_ID_SI)
++                                 && (pdev->device == ivideo.chip_id)) {
++                              valid_pdev = TRUE;
++                              break;
++                      }
++              }
+       }
+       if (!valid_pdev) {
+@@ -163,6 +176,7 @@ BOOLEAN sisfb_query_north_bridge_space(P
+       if (!init) {
+               init = TRUE;
+               switch (ivideo.chip) {
++#ifdef CONFIG_FB_SIS_300
+               case SIS_540:
+                       nbridge_id = PCI_DEVICE_ID_SI_540;
+                       break;
+@@ -172,23 +186,42 @@ BOOLEAN sisfb_query_north_bridge_space(P
+               case SIS_730:
+                       nbridge_id = PCI_DEVICE_ID_SI_730;
+                       break;
++#endif
++#ifdef CONFIG_FB_SIS_315
+               case SIS_550:
+                       nbridge_id = PCI_DEVICE_ID_SI_550;
+                       break;
+               case SIS_650:
+                       nbridge_id = PCI_DEVICE_ID_SI_650;
+                       break;
+-              case SIS_740:                   
++              case SIS_740:
+                       nbridge_id = PCI_DEVICE_ID_SI_740;
+                       break;
++              case SIS_660:
++                      nbridge_id = PCI_DEVICE_ID_SI_660;
++                      break;
++              case SIS_760:
++                      nbridge_id = PCI_DEVICE_ID_SI_760;
++                      break;
++#endif
+               default:
+                       nbridge_id = 0;
+                       break;
+               }
+-              pdev = pci_find_device(PCI_VENDOR_ID_SI, nbridge_id, pdev);
+-              if (pdev)
+-                      valid_pdev = TRUE;
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,74)
++              pci_for_each_dev(pdev) {
++#else
++              while((pdev = pci_find_device(PCI_VENDOR_ID_SI, PCI_ANY_ID, pdev))) {
++#endif
++                      DPRINTK("Current: 0x%x, target: 0x%x\n",
++                                      pdev->device, ivideo.chip_id);
++                      if ((pdev->vendor == PCI_VENDOR_ID_SI)
++                                      && (pdev->device == nbridge_id)) {
++                              valid_pdev = TRUE;
++                              break;
++                      }
++              }
+       }
+       if (!valid_pdev) {
+@@ -207,66 +240,291 @@ BOOLEAN sisfb_query_north_bridge_space(P
+ /* ------------------ Internal helper routines ----------------- */
+-static void sisfb_search_mode(const char *name)
++static BOOLEAN sisfb_verify_rate(struct sisfb_monitor *monitor, int mode_idx, int rate_idx, int rate)
+ {
+-      int i = 0, j = 0;
++      int htotal, vtotal;
++      unsigned int dclock, hsync;
+-      if(name == NULL) {
+-         printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
+-         sisfb_mode_idx = DEFAULT_MODE;
+-         return;
++      if(!monitor->datavalid) return TRUE;
++
++      if(mode_idx < 0) return FALSE;
++
++      if(rate < (monitor->vmin - 1)) return FALSE;
++      if(rate > (monitor->vmax + 1)) return FALSE;
++
++      if(sisfb_gettotalfrommode(&SiS_Pr, &sishw_ext, sisbios_mode[mode_idx].mode_no,
++                                &htotal, &vtotal, rate_idx)) {
++              dclock = (htotal * vtotal * rate) / 1000;
++              if(dclock > (monitor->dclockmax + 1000)) return FALSE;
++              hsync = dclock / htotal;
++              if(hsync < (monitor->hmin - 1)) return FALSE;
++              if(hsync > (monitor->hmax + 1)) return FALSE;
++        } else {
++              return FALSE;
+       }
+-              
+-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)               
+-        if (!strcmp(name, sisbios_mode[MODE_INDEX_NONE].name)) {
+-         printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
+-         sisfb_mode_idx = DEFAULT_MODE;
+-         return;
++      return TRUE;
++};
++
++static BOOLEAN sisfb_interpret_edid(struct sisfb_monitor *monitor, unsigned char *buffer)
++{
++      int i, j, xres, yres, refresh, index;
++      u32 emodes;
++
++      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) {
++         printk(KERN_DEBUG "sisfb: Bad EDID header\n");
++         return FALSE;
+       }
+-#endif                
+-      while(sisbios_mode[i].mode_no != 0) {
+-              if (!strcmp(name, sisbios_mode[i].name)) {
+-                      sisfb_mode_idx = i;
+-                      j = 1;
+-                      break;
+-              }
+-              i++;
++      if(buffer[0x12] != 0x01) {
++         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[0x13] >= 0x01) {
++         /* EDID V1 rev 1 and 2: Search for monitor descriptor
++          * to extract ranges
++          */
++          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 + 4] == 0x00) {
++                monitor->hmin = buffer[j + 7];
++                monitor->hmax = buffer[j + 8];
++                monitor->vmin = buffer[j + 5];
++                monitor->vmax = buffer[j + 6];
++                monitor->dclockmax = buffer[j + 9] * 10 * 1000;
++                monitor->datavalid = TRUE;
++                break;
++             }
++             j += 18;
++          }
++      }
++
++      if(!monitor->datavalid) {
++         /* Otherwise: Get a range from the list of supported
++          * Estabished Timings. This is not entirely accurate,
++          * because fixed frequency monitors are not supported
++          * that way.
++          */
++         monitor->hmin = 65535; monitor->hmax = 0;
++         monitor->vmin = 65535; monitor->vmax = 0;
++         monitor->dclockmax = 0;
++         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->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;
++               if(monitor->dclockmax < sisfb_ddcsmodes[i].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
++            }
++         }
++         index = 0x26;
++         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;
++            }
++            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) &&
++                     (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;
++                  }
++               }
++            }
++            index += 2;
++           }
++         if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) {
++            monitor->datavalid = TRUE;
++         }
++      }
++
++      return(monitor->datavalid);
++}
++
++static void sisfb_handle_ddc(struct sisfb_monitor *monitor, int crtno)
++{
++      USHORT        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((sisfb_crt1off) && (!crtno)) return;
++
++      temp = SiS_HandleDDC(&SiS_Pr, ivideo.vbflags, sisvga_engine, realcrtno, 0, &buffer[0]);
++      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) {
++            i = 3;  /* Number of retrys */
++            do {
++               temp = SiS_HandleDDC(&SiS_Pr, ivideo.vbflags, sisvga_engine,
++                                   realcrtno, 1, &buffer[0]);
++            } while((temp) && i--);
++              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->dclockmax / 1000);
++               } else {
++                  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);
++            }
++         } else {
++            printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n");
++         }
+       }
+-      if(!j) printk(KERN_INFO "sisfb: Invalid mode '%s'\n", name);
+ }
+-static void sisfb_search_vesamode(unsigned int vesamode)
++static void sisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet)
+ {
+       int i = 0, j = 0;
+       if(vesamode == 0) {
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)        
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+               sisfb_mode_idx = MODE_INDEX_NONE;
+ #else
+-              printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
++              if(!quiet)
++                 printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
+               sisfb_mode_idx = DEFAULT_MODE;
+-#endif                
++#endif
+               return;
+       }
+       vesamode &= 0x1dff;  /* Clean VESA mode number from other flags */
++      while(sisbios_mode[i++].mode_no != 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 == 0x50 ||
++                        sisbios_mode[i-1].mode_no == 0x56 ||
++                        sisbios_mode[i-1].mode_no == 0x53) continue;
++                  } else {
++                     if(sisbios_mode[i-1].mode_no == 0x5a ||
++                        sisbios_mode[i-1].mode_no == 0x5b) continue;
++                  }
++                  sisfb_mode_idx = i - 1;
++                  j = 1;
++                  break;
++              }
++      }
++      if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
++}
++
++static void sisfb_search_mode(char *name, BOOLEAN quiet)
++{
++      int i = 0;
++      unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
++      char strbuf[16], strbuf1[20];
++      char *nameptr = name;
++
++      if(name == NULL) {
++         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;
++      }
++#endif
++      if(strlen(name) <= 19) {
++         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;
++            ivideo.refresh_rate = 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) {
+-              if( (sisbios_mode[i].vesa_mode_no_1 == vesamode) ||
+-                  (sisbios_mode[i].vesa_mode_no_2 == vesamode) ) {
+-                      sisfb_mode_idx = i;
+-                      j = 1;
+-                      break;
++              if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
++                 if(sisfb_fstn) {
++                    if(sisbios_mode[i-1].mode_no == 0x50 ||
++                       sisbios_mode[i-1].mode_no == 0x56 ||
++                       sisbios_mode[i-1].mode_no == 0x53) continue;
++                 } else {
++                    if(sisbios_mode[i-1].mode_no == 0x5a ||
++                       sisbios_mode[i-1].mode_no == 0x5b) continue;
++                 }
++                 sisfb_mode_idx = i - 1;
++                 j = 1;
++                 break;
+               }
+-              i++;
+       }
+-      if(!j) printk(KERN_INFO "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
++      if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
++
+ }
+-static int sisfb_validate_mode(int myindex)
++static int sisfb_validate_mode(int myindex, unsigned long vbflags)
+ {
+-   u16 xres, yres;
++   u16 xres, yres, myres;
+ #ifdef CONFIG_FB_SIS_300
+    if(sisvga_engine == SIS_300_VGA) {
+@@ -283,8 +541,10 @@ static int sisfb_validate_mode(int myind
+    }
+ #endif
+-   switch (ivideo.disp_state & DISPTYPE_DISP2) {
+-     case DISPTYPE_LCD:
++   myres = sisbios_mode[myindex].yres;
++
++   switch (vbflags & VB_DISPTYPE_DISP2) {
++     case CRT2_LCD:
+       switch (sishw_ext.ulCRT2LCDType) {
+       case LCD_640x480:
+               xres =  640; yres =  480;  break;
+@@ -306,140 +566,209 @@ static int sisfb_validate_mode(int myind
+               xres = 1400; yres = 1050;  break;               
+       case LCD_1600x1200:
+               xres = 1600; yres = 1200;  break;
+-      case LCD_320x480:                               /* TW: FSTN */
++      case LCD_320x480:                               /* FSTN (old) */
+               xres =  320; yres =  480;  break;
++      case LCD_640x480_2:                             /* FSTN (new) */
++      case LCD_640x480_3:
++              xres =  640; yres =  480;  break;
+       default:
+               xres =    0; yres =    0;  break;
+       }
+-      if(sisbios_mode[myindex].xres > xres) {
+-              return(-1);
++
++      if(SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
++              xres = 1360; yres = 1024;
+       }
+-        if(sisbios_mode[myindex].yres > yres) {
++
++      if(SiS_Pr.SiS_CustomT == CUT_PANEL848) {
++              xres = 848;  yres =  480;
++      } else {
++         if(sisbios_mode[myindex].xres > xres) {
++              return(-1);
++         }
++           if(myres > yres) {
+               return(-1);
++         }
+       }
+-      if((sishw_ext.usExternalChip == 0x01) ||   /* LVDS */
+-           (sishw_ext.usExternalChip == 0x05) ||   /* LVDS+Chrontel */
+-         (sishw_ext.Is301BDH)) {                 /* 301B-DH */
++
++      if(vbflags & (VB_LVDS | VB_30xBDH)) {
+          switch (sisbios_mode[myindex].xres) {
++              case 320:
++                      if((myres != 200) && (myres != 240))
++                              return(-1);
++                      if((myres == 240) || (myres == 480)) {
++                              if(!sisfb_fstn) {
++                                 if(sisbios_mode[myindex].mode_no == 0x5a ||
++                                    sisbios_mode[myindex].mode_no == 0x5b)
++                                      return(-1);
++                              } else {
++                                 if(sisbios_mode[myindex].mode_no == 0x50 ||
++                                    sisbios_mode[myindex].mode_no == 0x56 ||
++                                    sisbios_mode[myindex].mode_no == 0x53)
++                                      return(-1);
++                              }
++                      }
++                      if(SiS_Pr.SiS_CustomT == CUT_PANEL848) return(-1);
++                      break;
++              case 400:
++                      if(myres != 300) return(-1);
++                      if(SiS_Pr.SiS_CustomT == CUT_PANEL848) return(-1);
++                      break;
+               case 512:
+-                      if(sisbios_mode[myindex].yres != 512) return -1;
+-                      if(sishw_ext.ulCRT2LCDType == LCD_1024x600) return -1;
++                      if(myres != 384) return(-1);
++                      if(sishw_ext.ulCRT2LCDType == LCD_1024x600) return(-1);
++                      if(SiS_Pr.SiS_CustomT == CUT_PANEL848) return(-1);
+                       break;
+               case 640:
+-                      if((sisbios_mode[myindex].yres != 400) &&
+-                         (sisbios_mode[myindex].yres != 480))
++                      if((myres != 400) && (myres != 480))
+                               return -1;
++                      if(SiS_Pr.SiS_CustomT == CUT_PANEL848) {
++                         if(myres == 400)
++                              return(-1);
++                      }
+                       break;
+               case 800:
+-                      if(sisbios_mode[myindex].yres != 600) return -1;
++                      if(myres != 600) return(-1);
++                      break;
++              case 848:
++                      if(SiS_Pr.SiS_CustomT != CUT_PANEL848) return(-1);
++                      if(myres != 480) return(-1);
+                       break;
+               case 1024:
+-                      if((sisbios_mode[myindex].yres != 600) &&
+-                         (sisbios_mode[myindex].yres != 768))
+-                              return -1;
+-                      if((sisbios_mode[myindex].yres == 600) &&
++                      if((myres != 600) && (myres != 768))
++                              return(-1);
++                      if((myres == 600) &&
+                          (sishw_ext.ulCRT2LCDType != LCD_1024x600))
+-                              return -1;
++                              return(-1);
+                       break;
+               case 1152:
+-                      if((sisbios_mode[myindex].yres) != 768) return -1;
+-                      if(sishw_ext.ulCRT2LCDType != LCD_1152x768) return -1;
++                      if(myres != 768) return(-1);
++                      if(sishw_ext.ulCRT2LCDType != LCD_1152x768) return(-1);
+                       break;
+               case 1280:
+-                      if((sisbios_mode[myindex].yres != 768) &&
+-                         (sisbios_mode[myindex].yres != 1024))
+-                              return -1;
+-                      if((sisbios_mode[myindex].yres == 768) &&
++                      if((myres != 768) && (myres != 1024))
++                              return(-1);
++                      if((myres == 768) &&
+                          (sishw_ext.ulCRT2LCDType != LCD_1280x768))
+-                              return -1;                              
++                              return(-1);
++                      if(SiS_Pr.SiS_CustomT == CUT_PANEL848) return(-1);
++                      break;
++              case 1360:
++                      if(SiS_Pr.SiS_CustomT != CUT_BARCO1366) return(-1);
++                      if(myres != 1024) return(-1);
+                       break;
+               case 1400:
+-                      if(sisbios_mode[myindex].yres != 1050) return -1;
++                      if(myres != 1050) return(-1);
++                      if(SiS_Pr.SiS_CustomT == CUT_PANEL848) return(-1);
+                       break;
+               case 1600:
+-                      if(sisbios_mode[myindex].yres != 1200) return -1;
++                      if(myres != 1200) return(-1);
++                      if(SiS_Pr.SiS_CustomT == CUT_PANEL848) return(-1);
+                       break;
+               default:
+-                      return -1;              
++                      return(-1);
+          }
+       } else {
+          switch (sisbios_mode[myindex].xres) {
++              case 320:
++                      if((myres != 200) && (myres != 240))
++                              return -1;
++                      break;
++              case 400:
++                      if(myres != 300) return(-1);
++                      break;
+               case 512:
+-                      if(sisbios_mode[myindex].yres != 512) return -1;
++                      if(myres != 384) return(-1);
+                       break;
+               case 640:
+-                      if((sisbios_mode[myindex].yres != 400) &&
+-                         (sisbios_mode[myindex].yres != 480))
+-                              return -1;
++                      if((myres != 400) && (myres != 480))
++                              return(-1);
+                       break;
+               case 800:
+-                      if(sisbios_mode[myindex].yres != 600) return -1;
++                      if(myres != 600) return(-1);
+                       break;
+               case 1024:
+-                      if(sisbios_mode[myindex].yres != 768) return -1;
++                      if(myres != 768) return(-1);
+                       break;
+               case 1280:
+-                      if((sisbios_mode[myindex].yres != 960) &&
+-                         (sisbios_mode[myindex].yres != 1024))
+-                              return -1;
+-                      if(sisbios_mode[myindex].yres == 960) {
+-                          if(sishw_ext.ulCRT2LCDType == LCD_1400x1050) 
+-                              return -1;
++                      if((myres != 960) && (myres != 768) && (myres != 1024))
++                              return(-1);
++                      if((myres == 768) || (myres == 960)) {
++                              if(sishw_ext.ulCRT2LCDType == LCD_1400x1050)
++                                      return(-1);
++                      }
++                      if(myres == 768) {
++                              if(sishw_ext.ulCRT2LCDType == LCD_1280x960)
++                                      return(-1);
+                       }
+                       break;
+               case 1400:
+-                      if(sisbios_mode[myindex].yres != 1050) return -1;
++                      if(myres != 1050) return(-1);
+                       break;
+               case 1600:
+-                      if(sisbios_mode[myindex].yres != 1200) return -1;
++                      if(myres != 1200) return(-1);
+                       break;
+               default:
+-                      return -1;              
++                      return(-1);
+          }
+       }
+       break;
+-     case DISPTYPE_TV:
++
++     case CRT2_TV:
+       switch (sisbios_mode[myindex].xres) {
++      case 320:
++              if(vbflags & VB_CHRONTEL) return(-1);
++              if((myres != 200) && (myres != 240))
++                      return(-1);
++              break;
++      case 400:
++              if(vbflags & VB_CHRONTEL) return(-1);
++              if(myres != 300) return(-1);
++              break;
+       case 512:
++              if(vbflags & VB_CHRONTEL) return(-1);
++              if((vbflags & VB_SISBRIDGE) && (vbflags & TV_NTSC))
++                      return(-1);
++              if(myres != 384) return(-1);
++              break;
+       case 640:
+-      case 800:
++              if((myres != 400) && (myres != 480))
++                      return(-1);
++              if((vbflags & VB_CHRONTEL) && (myres == 400))
++                      return(-1);
+               break;
+       case 720:
+-              if (ivideo.TV_type == TVMODE_NTSC) {
+-                      if (sisbios_mode[myindex].yres != 480) {
+-                              return(-1);
+-                      }
+-              } else if (ivideo.TV_type == TVMODE_PAL) {
+-                      if (sisbios_mode[myindex].yres != 576) {
+-                              return(-1);
+-                      }
+-              }
+-              /* TW: LVDS/CHRONTEL does not support 720 */
+-              if (ivideo.hasVB == HASVB_LVDS_CHRONTEL ||
+-                                      ivideo.hasVB == HASVB_CHRONTEL) {
+-                              return(-1);
+-              }
++              if(vbflags & VB_CHRONTEL) return(-1);
++              if((vbflags & TV_NTSC) && (myres != 480))
++                      return(-1);
++              if((vbflags & TV_PAL) && (myres != 576))
++                      return(-1);
++              break;
++      case 768:
++              if(vbflags & VB_CHRONTEL) return(-1);
++              if(!(vbflags & TV_PAL)) return(-1);
++              if(myres != 576) return(-1);
++              break;
++      case 800:
++              if(myres != 600) return(-1);
+               break;
+       case 1024:
+-              if (ivideo.TV_type == TVMODE_NTSC) {
+-                      if(sisbios_mode[myindex].bpp == 32) {
+-                             return(-1);
+-                      }
+-              }
+-              /* TW: LVDS/CHRONTEL only supports < 800 (1024 on 650/Ch7019)*/
+-              if (ivideo.hasVB == HASVB_LVDS_CHRONTEL ||
+-                                      ivideo.hasVB == HASVB_CHRONTEL) {
+-                  if(ivideo.chip < SIS_315H) {
++              if(vbflags & VB_301) return(-1);
++              if(vbflags & VB_CHRONTEL) {
++                      if(ivideo.chip < SIS_315H) {
+                               return(-1);
+-                  }
++                      }
+               }
+               break;
+       default:
+               return(-1);
+       }
+       break;
+-     case DISPTYPE_CRT2:      
+-        if(sisbios_mode[myindex].xres > 1280) return -1;
++
++     case CRT2_VGA:
++        if(sisbios_mode[myindex].xres > 1600) return(-1);
++      if(!(vbflags & (VB_301B|VB_302B))) {
++         if(sisbios_mode[myindex].xres > 1400) return(-1);
++      }
+       break;  
+      }
+      return(myindex);
+@@ -453,15 +782,20 @@ static void sisfb_search_crt2type(const 
+               return;
+       while(sis_crt2type[i].type_no != -1) {
+-              if (!strcmp(name, sis_crt2type[i].name)) {
++              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_dstn = (sis_crt2type[i].flags & FL_550_DSTN) ? 1 : 0;
++                      sisfb_fstn = (sis_crt2type[i].flags & FL_550_FSTN) ? 1 : 0;
+                       break;
+               }
+               i++;
+       }
+       if(sisfb_crt2type < 0)
+-              printk(KERN_INFO "sisfb: Invalid CRT2 type: %s\n", name);
++              printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
++        if(ivideo.chip != SIS_550) {
++         sisfb_dstn = sisfb_fstn = 0;
++      }
+ }
+ static void sisfb_search_queuemode(const char *name)
+@@ -472,23 +806,23 @@ static void sisfb_search_queuemode(const
+               return;
+       while (sis_queuemode[i].type_no != -1) {
+-              if (!strcmp(name, sis_queuemode[i].name)) {
++              if (!strnicmp(name, sis_queuemode[i].name, strlen(sis_queuemode[i].name))) {
+                       sisfb_queuemode = sis_queuemode[i].type_no;
+                       break;
+               }
+               i++;
+       }
+       if (sisfb_queuemode < 0)
+-              printk(KERN_INFO "sisfb: Invalid queuemode type: %s\n", name);
++              printk(KERN_ERR "sisfb: Invalid queuemode type: %s\n", name);
+ }
+-static u8 sisfb_search_refresh_rate(unsigned int rate)
++static u8 sisfb_search_refresh_rate(unsigned int rate, int mode_idx)
+ {
+       u16 xres, yres;
+       int i = 0;
+-      xres = sisbios_mode[sisfb_mode_idx].xres;
+-      yres = sisbios_mode[sisfb_mode_idx].yres;
++      xres = sisbios_mode[mode_idx].xres;
++      yres = sisbios_mode[mode_idx].yres;
+       sisfb_rate_idx = 0;
+       while ((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
+@@ -536,23 +870,60 @@ static void sisfb_search_tvstd(const cha
+               return;
+       while (sis_tvtype[i].type_no != -1) {
+-              if (!strcmp(name, sis_tvtype[i].name)) {
+-                      sisfb_tvmode = sis_tvtype[i].type_no;
++              if (!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
++                      ivideo.vbflags |= sis_tvtype[i].type_no;
+                       break;
+               }
+               i++;
+       }
+ }
++static void sisfb_search_specialtiming(const char *name)
++{
++      int i = 0;
++      BOOLEAN found = FALSE;
++
++      if(name == NULL)
++              return;
++
++      if(!strnicmp(name, "none", 4)) {
++              SiS_Pr.SiS_CustomT = 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))) {
++               SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
++               found = TRUE;
++               printk(KERN_INFO "sisfb: Special timing for %s %s forced\n",
++               mycustomttable[i].vendorName, mycustomttable[i].cardName);
++               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++;
++            }
++           }
++      }
++}
++
+ static BOOLEAN sisfb_bridgeisslave(void)
+ {
+-   unsigned char usScratchP1_00;
++   unsigned char P1_00;
+-   if(ivideo.hasVB == HASVB_NONE) return FALSE;
++   if(!(ivideo.vbflags & VB_VIDEOBRIDGE)) return FALSE;
+-   inSISIDXREG(SISPART1,0x00,usScratchP1_00);
+-   if( ((sisvga_engine == SIS_300_VGA) && (usScratchP1_00 & 0xa0) == 0x20) ||
+-       ((sisvga_engine == SIS_315_VGA) && (usScratchP1_00 & 0x50) == 0x10) ) {
++   inSISIDXREG(SISPART1,0x00,P1_00);
++   if( ((sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
++       ((sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
+          return TRUE;
+    } else {
+            return FALSE;
+@@ -597,7 +968,7 @@ static BOOLEAN sisfbcheckvretracecrt2(vo
+ static BOOLEAN sisfb_CheckVBRetrace(void) 
+ {
+-   if(ivideo.disp_state & DISPTYPE_DISP2) {
++   if(ivideo.currentvbflags & VB_DISPTYPE_DISP2) {
+       if(sisfb_bridgeisslave()) {
+          return(sisfbcheckvretracecrt1());
+       } else {
+@@ -607,60 +978,195 @@ static BOOLEAN sisfb_CheckVBRetrace(void
+    return(sisfbcheckvretracecrt1());
+ }
++static int sisfb_myblank(int blank)
++{
++   u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
++   BOOLEAN backlight = TRUE;
++
++   switch(blank) {
++   case 0:    /* on */
++      sr01  = 0x00;
++      sr11  = 0x00;
++      sr1f  = 0x00;
++      cr63  = 0x00;
++      p2_0  = 0x20;
++      p1_13 = 0x00;
++      backlight = TRUE;
++      break;
++   case 1:    /* blank */
++      sr01  = 0x20;
++      sr11  = 0x00;
++      sr1f  = 0x00;
++      cr63  = 0x00;
++      p2_0  = 0x20;
++      p1_13 = 0x00;
++      backlight = TRUE;
++      break;
++   case 2:    /* no vsync */
++      sr01  = 0x20;
++      sr11  = 0x08;
++      sr1f  = 0x80;
++      cr63  = 0x40;
++      p2_0  = 0x40;
++      p1_13 = 0x80;
++      backlight = FALSE;
++      break;
++   case 3:    /* no hsync */
++      sr01  = 0x20;
++      sr11  = 0x08;
++      sr1f  = 0x40;
++      cr63  = 0x40;
++      p2_0  = 0x80;
++      p1_13 = 0x40;
++      backlight = FALSE;
++      break;
++   case 4:    /* 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) {
++
++      setSISIDXREG(SISSR, 0x01, ~0x20, sr01);
++
++      if( (!sisfb_thismonitor.datavalid) ||
++          ((sisfb_thismonitor.datavalid) &&
++           (sisfb_thismonitor.feature & 0xe0))) {
++
++       if(sisvga_engine == SIS_315_VGA) {
++          setSISIDXREG(SISCR, 0x63, 0xbf, cr63);
++       }
++
++       setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f);
++      }
++
++   }
++
++   if(ivideo.currentvbflags & CRT2_LCD) {
++
++      if(ivideo.vbflags & (VB_301LV|VB_302LV)) {
++       if(backlight) {
++          SiS_SiS30xBLOn(&SiS_Pr, &sishw_ext);
++       } else {
++          SiS_SiS30xBLOff(&SiS_Pr, &sishw_ext);
++       }
++      } else if(sisvga_engine == SIS_315_VGA) {
++       if(ivideo.vbflags & VB_CHRONTEL) {
++          if(backlight) {
++             SiS_Chrontel701xBLOn(&SiS_Pr,&sishw_ext);
++          } else {
++             SiS_Chrontel701xBLOff(&SiS_Pr);
++          }
++       }
++      }
++
++      if(((sisvga_engine == SIS_300_VGA) &&
++          (ivideo.vbflags & (VB_301|VB_30xBDH|VB_LVDS))) ||
++         ((sisvga_engine == SIS_315_VGA) &&
++          ((ivideo.vbflags & (VB_LVDS | VB_CHRONTEL)) == VB_LVDS))) {
++          setSISIDXREG(SISSR, 0x11, ~0x0c, sr11);
++      }
++
++      if(sisvga_engine == SIS_300_VGA) {
++         if((ivideo.vbflags & (VB_301B|VB_302B)) &&
++            (!(ivideo.vbflags & VB_30xBDH))) {
++          setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13);
++       }
++      } else if(sisvga_engine == SIS_315_VGA) {
++         if((ivideo.vbflags & (VB_301B|VB_302B)) &&
++            (!(ivideo.vbflags & VB_30xBDH))) {
++          setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
++       }
++      }
++
++   } else if(ivideo.currentvbflags & CRT2_VGA) {
++
++      if(ivideo.vbflags & (VB_301B|VB_302B)) {
++         setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
++      }
++
++   }
++
++   return(0);
++}
++
+ /* ----------- FBDev related routines for all series ----------- */
++static void sisfb_set_vparms(void)
++{
++   switch(ivideo.video_bpp) {
++   case 8:
++              ivideo.DstColor = 0x0000;
++      ivideo.SiS310_AccelDepth = 0x00000000;
++      ivideo.video_cmap_len = 256;
++              break;
++   case 16:
++              ivideo.DstColor = 0x8000;
++              ivideo.SiS310_AccelDepth = 0x00010000;
++      ivideo.video_cmap_len = 16;
++              break;
++   case 32:
++              ivideo.DstColor = 0xC000;
++      ivideo.SiS310_AccelDepth = 0x00020000;
++      ivideo.video_cmap_len = 16;
++              break;
++   default:
++      ivideo.video_cmap_len = 16;
++      printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo.video_bpp);
++      ivideo.accel = 0;
++      break;
++   }
++}
++
+ static int sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
+                     struct fb_info *info)
+ {
+-      unsigned int htotal =
+-              var->left_margin + var->xres + var->right_margin +
+-              var->hsync_len;
+-      unsigned int vtotal = 0; 
++      unsigned int htotal = 0, vtotal = 0;
+       double drate = 0, hrate = 0;
+       int found_mode = 0;
+       int old_mode;
+-      unsigned char reg;
++      u32 pixclock;
+-      TWDEBUG("Inside do_set_var");
+-      
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)        
+-      inSISIDXREG(SISCR,0x34,reg);
+-      if(reg & 0x80) {
+-         printk(KERN_INFO "sisfb: Cannot change display mode, X server is active\n");
+-         return -EBUSY;
+-      }
+-#endif        
++      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->upper_margin + var->yres + var->lower_margin +
+-                       var->vsync_len;
++              vtotal += var->yres;
+               vtotal <<= 1;
+       } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
+-              vtotal = var->upper_margin + var->yres + var->lower_margin +
+-                       var->vsync_len;
++              vtotal += var->yres;
+               vtotal <<= 2;
+       } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+-              vtotal = var->upper_margin + (var->yres/2) + var->lower_margin +
+-                       var->vsync_len; 
+-      } else  vtotal = var->upper_margin + var->yres + var->lower_margin +
+-                       var->vsync_len;
++              vtotal += var->yres;
++              vtotal <<= 1;
++      } else  vtotal += var->yres;
+       if(!(htotal) || !(vtotal)) {
+               DPRINTK("sisfb: Invalid 'var' information\n");
+               return -EINVAL;
+       }
+-      if(var->pixclock && htotal && vtotal) {
+-         drate = 1E12 / var->pixclock;
++      if(pixclock && htotal && vtotal) {
++         drate = 1E12 / pixclock;
+          hrate = drate / htotal;
+          ivideo.refresh_rate = (unsigned int) (hrate / vtotal * 2 + 0.5);
+       } else ivideo.refresh_rate = 60;
+-      /* TW: Calculation wrong for 1024x600 - force it to 60Hz */
+-      if((var->xres == 1024) && (var->yres == 600)) ivideo.refresh_rate = 60;
+-
++#if 0
+       printk(KERN_DEBUG "sisfb: Change mode to %dx%dx%d-%dHz\n",
+               var->xres,var->yres,var->bits_per_pixel,ivideo.refresh_rate);
++#endif
+       old_mode = sisfb_mode_idx;
+       sisfb_mode_idx = 0;
+@@ -678,7 +1184,7 @@ static int sisfb_do_set_var(struct fb_va
+       }
+       if(found_mode)
+-              sisfb_mode_idx = sisfb_validate_mode(sisfb_mode_idx);
++              sisfb_mode_idx = sisfb_validate_mode(sisfb_mode_idx, ivideo.currentvbflags);
+       else
+               sisfb_mode_idx = -1;
+@@ -689,12 +1195,21 @@ static int sisfb_do_set_var(struct fb_va
+               return -EINVAL;
+       }
+-      if(sisfb_search_refresh_rate(ivideo.refresh_rate) == 0) {
++      if(sisfb_search_refresh_rate(ivideo.refresh_rate, sisfb_mode_idx) == 0) {
+               sisfb_rate_idx = sisbios_mode[sisfb_mode_idx].rate_idx;
+               ivideo.refresh_rate = 60;
+       }
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
++      if(sisfb_thismonitor.datavalid) {
++         if(!sisfb_verify_rate(&sisfb_thismonitor, sisfb_mode_idx,
++                               sisfb_rate_idx, ivideo.refresh_rate)) {
++            printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
++         }
++      }
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+       if(((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {
+ #else
+       if(isactive) {
+@@ -708,14 +1223,6 @@ static int sisfb_do_set_var(struct fb_va
+               outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
+-              sisfb_post_setmode();
+-
+-              DPRINTK("sisfb: Set new mode: %dx%dx%d-%d \n",
+-                      sisbios_mode[sisfb_mode_idx].xres,
+-                      sisbios_mode[sisfb_mode_idx].yres,
+-                      sisbios_mode[sisfb_mode_idx].bpp,
+-                      ivideo.refresh_rate);
+-
+               ivideo.video_bpp = sisbios_mode[sisfb_mode_idx].bpp;
+               ivideo.video_vwidth = ivideo.video_width = sisbios_mode[sisfb_mode_idx].xres;
+               ivideo.video_vheight = ivideo.video_height = sisbios_mode[sisfb_mode_idx].yres;
+@@ -725,53 +1232,38 @@ static int sisfb_do_set_var(struct fb_va
+               if(sisfb_accel) {
+                  ivideo.accel = (var->accel_flags & FB_ACCELF_TEXT) ? -1 : 0;
+               }
+-              switch(ivideo.video_bpp) {
+-              case 8:
+-                      ivideo.DstColor = 0x0000;
+-                      ivideo.SiS310_AccelDepth = 0x00000000;
+-                      ivideo.video_cmap_len = 256;
+-                      break;
+-              case 16:
+-                      ivideo.DstColor = 0x8000;
+-                      ivideo.SiS310_AccelDepth = 0x00010000;
+-                      ivideo.video_cmap_len = 16;
+-                      break;
+-              case 32:
+-                      ivideo.DstColor = 0xC000;
+-                      ivideo.SiS310_AccelDepth = 0x00020000;
+-                      ivideo.video_cmap_len = 16;
+-                      break;
+-              default:
+-                      ivideo.video_cmap_len = 16;
+-                      printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo.video_bpp);
+-                      ivideo.accel = 0;
+-                      break;
+-              }
++
++              sisfb_set_vparms();
++
++              ivideo.current_width = ivideo.video_width;
++              ivideo.current_height = ivideo.video_height;
++              ivideo.current_bpp = ivideo.video_bpp;
++              ivideo.current_htotal = htotal;
++              ivideo.current_vtotal = vtotal;
++              ivideo.current_pixclock = var->pixclock;
++              ivideo.current_refresh_rate = ivideo.refresh_rate;
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
++                sisfb_lastrates[sisfb_mode_no] = ivideo.refresh_rate;
++#endif
++
++              sisfb_post_setmode();
+       }
+-      TWDEBUG("End of do_set_var");
+       return 0;
+ }
+-#ifdef SISFB_PAN
+ static int sisfb_pan_var(struct fb_var_screeninfo *var)
+ {
+       unsigned int base;
+-      TWDEBUG("Inside pan_var");
+-      
+       if (var->xoffset > (var->xres_virtual - var->xres)) {
+-              printk(KERN_INFO "Pan: xo: %d xv %d xr %d\n",
+-                      var->xoffset, var->xres_virtual, var->xres);
+               return -EINVAL;
+       }
+       if(var->yoffset > (var->yres_virtual - var->yres)) {
+-              printk(KERN_INFO "Pan: yo: %d yv %d yr %d\n",
+-                      var->yoffset, var->yres_virtual, var->yres);
+               return -EINVAL;
+       }
+-        base = var->yoffset * var->xres_virtual + var->xoffset;
++      base = var->yoffset * var->xres_virtual + var->xoffset;
+         /* calculate base bpp dep. */
+         switch(var->bits_per_pixel) {
+@@ -794,7 +1286,7 @@ static int sisfb_pan_var(struct fb_var_s
+       if(sisvga_engine == SIS_315_VGA) {
+               setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
+       }
+-        if(ivideo.disp_state & DISPTYPE_DISP2) {
++        if(ivideo.currentvbflags & VB_DISPTYPE_DISP2) {
+               orSISIDXREG(SISPART1, sisfb_CRT2_write_enable, 0x01);
+               outSISIDXREG(SISPART1, 0x06, (base & 0xFF));
+               outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF));
+@@ -803,10 +1295,8 @@ static int sisfb_pan_var(struct fb_var_s
+                       setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
+               }
+         }
+-      TWDEBUG("End of pan_var");
+       return 0;
+ }
+-#endif
+ static void sisfb_bpp_to_var(struct fb_var_screeninfo *var)
+ {
+@@ -843,22 +1333,24 @@ static void sisfb_bpp_to_var(struct fb_v
+ void sis_dispinfo(struct ap_data *rec)
+ {
+-      rec->minfo.bpp    = ivideo.video_bpp;
+-      rec->minfo.xres   = ivideo.video_width;
+-      rec->minfo.yres   = ivideo.video_height;
+-      rec->minfo.v_xres = ivideo.video_vwidth;
+-      rec->minfo.v_yres = ivideo.video_vheight;
+-      rec->minfo.org_x  = ivideo.org_x;
+-      rec->minfo.org_y  = ivideo.org_y;
+-      rec->minfo.vrate  = ivideo.refresh_rate;
+-      rec->iobase       = ivideo.vga_base - 0x30;
+-      rec->mem_size     = ivideo.video_size;
+-      rec->disp_state   = ivideo.disp_state; 
+-      rec->version      = (VER_MAJOR << 24) | (VER_MINOR << 16) | VER_LEVEL; 
+-      rec->hasVB        = ivideo.hasVB; 
+-      rec->TV_type      = ivideo.TV_type; 
+-      rec->TV_plug      = ivideo.TV_plug; 
+-      rec->chip         = ivideo.chip;
++      rec->minfo.bpp      = ivideo.video_bpp;
++      rec->minfo.xres     = ivideo.video_width;
++      rec->minfo.yres     = ivideo.video_height;
++      rec->minfo.v_xres   = ivideo.video_vwidth;
++      rec->minfo.v_yres   = ivideo.video_vheight;
++      rec->minfo.org_x    = ivideo.org_x;
++      rec->minfo.org_y    = ivideo.org_y;
++      rec->minfo.vrate    = ivideo.refresh_rate;
++      rec->iobase         = ivideo.vga_base - 0x30;
++      rec->mem_size       = ivideo.video_size;
++      rec->disp_state     = ivideo.disp_state;
++      rec->version        = (VER_MAJOR << 24) | (VER_MINOR << 16) | VER_LEVEL;
++      rec->hasVB          = ivideo.hasVB;
++      rec->TV_type        = ivideo.TV_type;
++      rec->TV_plug        = ivideo.TV_plug;
++      rec->chip           = ivideo.chip;
++      rec->vbflags        = ivideo.vbflags;
++      rec->currentvbflags = ivideo.currentvbflags;
+ }
+ /* ------------ FBDev related routines for 2.4 series ----------- */
+@@ -873,7 +1365,6 @@ static void sisfb_crtc_to_var(struct fb_
+       int A, B, C, D, E, F, temp;
+       double hrate, drate;
+-      TWDEBUG("Inside crtc_to_var");
+       inSISIDXREG(SISSR, IND_SIS_COLOR_MODE, sr_data);
+       if (sr_data & SIS_INTERLACED_MODE)
+@@ -921,6 +1412,8 @@ static void sisfb_crtc_to_var(struct fb_
+       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);
+@@ -939,26 +1432,22 @@ static void sisfb_crtc_to_var(struct fb_
+       D = B - F - C;
+         var->yres = E;
+-#ifndef SISFB_PAN
+-      var->yres_virtual = E;
+-#endif
+-      /* TW: We have to report the physical dimension to the console! */
++      var->upper_margin = D;
++      var->lower_margin = F;
++      var->vsync_len = C;
++
+       if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+               var->yres <<= 1;
+-#ifndef SISFB_PAN
+-              var->yres_virtual <<= 1;
+-#endif
++              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;
+-#ifndef SISFB_PAN
+-              var->yres_virtual >>= 1;
+-#endif
++              var->upper_margin >>= 1;
++              var->lower_margin >>= 1;
++              var->vsync_len >>= 1;
+       }
+-      var->upper_margin = D;
+-      var->lower_margin = F;
+-      var->vsync_len = C;
+-
+       inSISIDXREG(SISSR, 0x0b, sr_data);
+       inSISIDXREG(SISCR, 0x00, cr_data);
+@@ -999,10 +1488,20 @@ static void sisfb_crtc_to_var(struct fb_
+       D = B - F - C;
+       var->xres = var->xres_virtual = E * 8;
+-      var->left_margin = D * 8;
+-      var->right_margin = F * 8;
+-      var->hsync_len = C * 8;
++      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;
+       var->sync = 0;
+@@ -1022,21 +1521,21 @@ static void sisfb_crtc_to_var(struct fb_
+       VT <<= 1;
+       HT = (HT + 5) * 8;
++      if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
++              VT <<= 1;
++      }
+       hrate = (double) ivideo.refresh_rate * (double) VT / 2;
+       drate = hrate * HT;
+       var->pixclock = (u32) (1E12 / drate);
+-#ifdef SISFB_PAN
+       if(sisfb_ypan) {
+           var->yres_virtual = ivideo.heapstart / (var->xres * (var->bits_per_pixel >> 3));
+           if(var->yres_virtual <= var->yres) {
+               var->yres_virtual = var->yres;
+           }
+       } else
+-#endif
+-         var->yres_virtual = var->yres;
++          var->yres_virtual = var->yres;
+-        TWDEBUG("end of crtc_to_var");
+ }
+ static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue,
+@@ -1069,7 +1568,7 @@ static int sisfb_setcolreg(unsigned regn
+               outSISREG(SISDACD, (red >> 10));
+               outSISREG(SISDACD, (green >> 10));
+               outSISREG(SISDACD, (blue >> 10));
+-              if (ivideo.disp_state & DISPTYPE_DISP2) {
++              if (ivideo.currentvbflags & VB_DISPTYPE_DISP2) {
+                       outSISREG(SISDAC2A, regno);
+                       outSISREG(SISDAC2D, (red >> 8));
+                       outSISREG(SISDAC2D, (green >> 8));
+@@ -1118,7 +1617,7 @@ static void sisfb_set_disp(int con, stru
+       display->ywrapstep = fix.ywrapstep;
+       display->line_length = fix.line_length;
+       display->next_line = fix.line_length;
+-      display->can_soft_blank = 0;
++      display->can_soft_blank = 1;
+       display->inverse = sisfb_inverse;
+       display->var = *var;
+@@ -1162,17 +1661,12 @@ static void sisfb_set_disp(int con, stru
+       display->dispsw = &sisfb_sw;
+       restore_flags(flags);
+-#ifdef SISFB_PAN
+-        if((ivideo.accel) && (sisfb_ypan)) {
+-          /* display->scrollmode = SCROLL_YPAN; - not defined */
++        if(sisfb_ypan) {
++          /* display->scrollmode = 0;  */
+       } else {
+           display->scrollmode = SCROLL_YREDRAW;
+           sisfb_sw.bmove = fbcon_redraw_bmove;
+       }
+-#else
+-      display->scrollmode = SCROLL_YREDRAW;
+-      sisfb_sw.bmove = fbcon_redraw_bmove;
+-#endif
+ }
+ static void sisfb_do_install_cmap(int con, struct fb_info *info)
+@@ -1191,17 +1685,16 @@ static void sisfb_do_install_cmap(int co
+ static int sisfb_get_var(struct fb_var_screeninfo *var, int con,
+                        struct fb_info *info)
+ {
+-      TWDEBUG("inside get_var");
+       if(con == -1)
+               memcpy(var, &default_var, sizeof(struct fb_var_screeninfo));
+       else
+               *var = fb_display[con].var;
+-      /* For FSTN, DSTN */
+-      if (var->xres == 320 && var->yres == 480)
++      if(sisfb_fstn) {
++         if (var->xres == 320 && var->yres == 480)
+               var->yres = 240;
+-              
+-      TWDEBUG("end of get_var");
++        }
++
+       return 0;
+ }
+@@ -1211,8 +1704,6 @@ static int sisfb_set_var(struct fb_var_s
+       int err;
+       unsigned int cols, rows;
+-      TWDEBUG("inside set_var");
+-
+       fb_display[con].var.activate = FB_ACTIVATE_NOW;
+         if(sisfb_do_set_var(var, con == currcon, info)) {
+               sisfb_crtc_to_var(var);
+@@ -1233,16 +1724,17 @@ static int sisfb_set_var(struct fb_var_s
+       cols = sisbios_mode[sisfb_mode_idx].cols;
+       rows = sisbios_mode[sisfb_mode_idx].rows;
+-      vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
++#if 0
++      /* Why was this called here? */
++      vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
++#endif
+-      TWDEBUG("end of set_var");
+       return 0;
+ }
+ static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+                         struct fb_info *info)
+ {
+-      TWDEBUG("inside get_cmap");
+         if (con == currcon)
+               return fb_get_cmap(cmap, kspc, sis_getcolreg, info);
+@@ -1251,7 +1743,6 @@ static int sisfb_get_cmap(struct fb_cmap
+       else
+               fb_copy_cmap(fb_default_cmap(ivideo.video_cmap_len), cmap, kspc ? 0 : 2);
+-      TWDEBUG("end of get_cmap");
+       return 0;
+ }
+@@ -1260,7 +1751,6 @@ static int sisfb_set_cmap(struct fb_cmap
+ {
+       int err;
+-      TWDEBUG("inside set_cmap");
+       if (!fb_display[con].cmap.len) {
+               err = fb_alloc_cmap(&fb_display[con].cmap, ivideo.video_cmap_len, 0);
+               if (err)
+@@ -1272,17 +1762,15 @@ static int sisfb_set_cmap(struct fb_cmap
+       else
+               fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
+-      TWDEBUG("end of set_cmap");
++
+       return 0;
+ }
+-#ifdef SISFB_PAN
+ static int sisfb_pan_display(struct fb_var_screeninfo *var, int con,
+                            struct fb_info* info)
+ {
+       int err;
+-      
+-      TWDEBUG("inside pan_display");
++
+       if (var->vmode & FB_VMODE_YWRAP) {
+               if (var->yoffset < 0 || var->yoffset >= fb_display[con].var.yres_virtual || var->xoffset)
+                       return -EINVAL;
+@@ -1303,10 +1791,8 @@ static int sisfb_pan_display(struct fb_v
+       else
+               fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;
+-      TWDEBUG("end of pan_display");
+       return 0;
+ }
+-#endif
+ static int sisfb_mmap(struct fb_info *info, struct file *file,
+                     struct vm_area_struct *vma)
+@@ -1316,7 +1802,6 @@ static int sisfb_mmap(struct fb_info *in
+       unsigned long off;
+       u32 len, mmio_off;
+-      TWDEBUG("inside mmap");
+       if(vma->vm_pgoff > (~0UL >> PAGE_SHIFT))  return -EINVAL;
+       off = vma->vm_pgoff << PAGE_SHIFT;
+@@ -1351,11 +1836,11 @@ static int sisfb_mmap(struct fb_info *in
+       if (boot_cpu_data.x86 > 3)
+               pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
+ #endif
++        /* RedHat requires vma as the first paramater to the following call */
+       if (io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start,
+                               vma->vm_page_prot))
+               return -EAGAIN;
+-        TWDEBUG("end of mmap");
+       return 0;
+ }
+@@ -1368,7 +1853,6 @@ static void sis_get_glyph(struct fb_info
+       u8 *gbuf = gly->gmask;
+       int size;
+-      TWDEBUG("Inside get_glyph");
+       gly->fontheight = fontheight(p);
+       gly->fontwidth = fontwidth(p);
+       widthb = (fontwidth(p) + 7) / 8;
+@@ -1382,16 +1866,11 @@ static void sis_get_glyph(struct fb_info
+       size = fontheight(p) * widthb;
+       memcpy(gbuf, cdat, size);
+       gly->ngmask = size;
+-      TWDEBUG("End of get_glyph");
+ }
+ static int sisfb_update_var(int con, struct fb_info *info)
+ {
+-#ifdef SISFB_PAN
+         return(sisfb_pan_var(&fb_display[con].var));
+-#else
+-      return 0;
+-#endif        
+ }
+ static int sisfb_switch(int con, struct fb_info *info)
+@@ -1428,127 +1907,7 @@ static int sisfb_switch(int con, struct 
+ static void sisfb_blank(int blank, struct fb_info *info)
+ {
+-      u8 reg;
+-
+-      inSISIDXREG(SISCR, 0x17, reg);
+-
+-      if(blank > 0)
+-              reg &= 0x7f;
+-      else
+-              reg |= 0x80;
+-
+-        outSISIDXREG(SISCR, 0x17, reg);               
+-      outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */
+-      outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */
+-      printk(KERN_DEBUG "sisfb_blank() called (%d)\n", blank);
+-}
+-
+-
+-static int sisfb_ioctl(struct inode *inode, struct file *file,
+-                     unsigned int cmd, unsigned long arg, int con,
+-                     struct fb_info *info)
+-{
+-      TWDEBUG("inside ioctl");
+-      switch (cmd) {
+-         case FBIO_ALLOC:
+-              if (!capable(CAP_SYS_RAWIO))
+-                      return -EPERM;
+-              sis_malloc((struct sis_memreq *) arg);
+-              break;
+-         case FBIO_FREE:
+-              if (!capable(CAP_SYS_RAWIO))
+-                      return -EPERM;
+-              sis_free(*(unsigned long *) arg);
+-              break;
+-         case FBIOGET_GLYPH:
+-                sis_get_glyph(info,(SIS_GLYINFO *) arg);
+-              break;  
+-         case FBIOGET_HWCINFO:
+-              {
+-                      unsigned long *hwc_offset = (unsigned long *) arg;
+-
+-                      if (sisfb_caps & HW_CURSOR_CAP)
+-                              *hwc_offset = sisfb_hwcursor_vbase -
+-                                  (unsigned long) ivideo.video_vbase;
+-                      else
+-                              *hwc_offset = 0;
+-
+-                      break;
+-              }
+-         case FBIOPUT_MODEINFO:
+-              {
+-                      struct mode_info *x = (struct mode_info *)arg;
+-
+-                      ivideo.video_bpp        = x->bpp;
+-                      ivideo.video_width      = x->xres;
+-                      ivideo.video_height     = x->yres;
+-                      ivideo.video_vwidth     = x->v_xres;
+-                      ivideo.video_vheight    = x->v_yres;
+-                      ivideo.org_x            = x->org_x;
+-                      ivideo.org_y            = x->org_y;
+-                      ivideo.refresh_rate     = x->vrate;
+-                      ivideo.video_linelength = ivideo.video_vwidth * (ivideo.video_bpp >> 3);
+-                      switch(ivideo.video_bpp) {
+-                      case 8:
+-                              ivideo.DstColor = 0x0000;
+-                              ivideo.SiS310_AccelDepth = 0x00000000;
+-                              ivideo.video_cmap_len = 256;
+-                              break;
+-                      case 16:
+-                              ivideo.DstColor = 0x8000;
+-                              ivideo.SiS310_AccelDepth = 0x00010000;
+-                              ivideo.video_cmap_len = 16;
+-                              break;
+-                      case 32:
+-                              ivideo.DstColor = 0xC000;
+-                              ivideo.SiS310_AccelDepth = 0x00020000;
+-                              ivideo.video_cmap_len = 16;
+-                              break;
+-                      default:
+-                              ivideo.video_cmap_len = 16;
+-                              printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo.video_bpp);
+-                              ivideo.accel = 0;
+-                              break;
+-                      }
+-
+-                      break;
+-              }
+-         case FBIOGET_DISPINFO:
+-              sis_dispinfo((struct ap_data *)arg);
+-              break;
+-         case SISFB_GET_INFO:  /* TW: New for communication with X driver */
+-              {
+-                      sisfb_info *x = (sisfb_info *)arg;
+-
+-                      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;
+-                      x->fbvidmode = sisfb_mode_no;
+-                      x->sisfb_caps = sisfb_caps;
+-                      x->sisfb_tqlen = 512; /* yet unused */
+-                      x->sisfb_pcibus = ivideo.pcibus;
+-                      x->sisfb_pcislot = ivideo.pcislot;
+-                      x->sisfb_pcifunc = ivideo.pcifunc;
+-                      x->sisfb_lcdpdc = sisfb_detectedpdc;
+-                      x->sisfb_lcda = sisfb_detectedlcda;
+-                      break;
+-              }
+-         case SISFB_GET_VBRSTATUS:
+-              {
+-                      unsigned long *vbrstatus = (unsigned long *) arg;
+-                      if(sisfb_CheckVBRetrace()) *vbrstatus = 1;
+-                      else                       *vbrstatus = 0;
+-              }
+-         default:
+-              return -EINVAL;
+-      }
+-      TWDEBUG("end of ioctl");
+-      return 0;
+-
++      sisfb_myblank(blank);
+ }
+ #endif
+@@ -1575,11 +1934,9 @@ static int sisfb_get_cmap_len(const stru
+               rc = 256;       
+               break;
+       case 16:
+-              rc = 16;        
+-              break;          
+       case 32:
+               rc = 16;
+-              break;  
++              break;
+       }
+       return rc;
+ }
+@@ -1596,7 +1953,7 @@ static int sisfb_setcolreg(unsigned regn
+               outSISREG(SISDACD, (red >> 10));
+               outSISREG(SISDACD, (green >> 10));
+               outSISREG(SISDACD, (blue >> 10));
+-              if (ivideo.disp_state & DISPTYPE_DISP2) {
++              if (ivideo.currentvbflags & VB_DISPTYPE_DISP2) {
+                       outSISREG(SISDAC2A, regno);
+                       outSISREG(SISDAC2D, (red >> 8));
+                       outSISREG(SISDAC2D, (green >> 8));
+@@ -1622,63 +1979,52 @@ static int sisfb_set_par(struct fb_info 
+ {
+       int err;
+-      TWDEBUG("inside set_par");
+         if((err = sisfb_do_set_var(&info->var, 1, info)))
+               return err;
+       sisfb_get_fix(&info->fix, info->currcon, info);
+-      TWDEBUG("end of set_par");
+       return 0;
+ }
+ static int sisfb_check_var(struct fb_var_screeninfo *var,
+                            struct fb_info *info)
+ {
+-      unsigned int htotal =
+-              var->left_margin + var->xres + var->right_margin +
+-              var->hsync_len;
+-      unsigned int vtotal = 0;
++      unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
+       double drate = 0, hrate = 0;
+       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;
+-      TWDEBUG("Inside check_var");
++      pixclock = var->pixclock;
+       if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
+-              vtotal = var->upper_margin + var->yres + var->lower_margin +
+-                       var->vsync_len;   
++              vtotal += var->yres;
+               vtotal <<= 1;
+       } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
+-              vtotal = var->upper_margin + var->yres + var->lower_margin +
+-                       var->vsync_len;   
++              vtotal += var->yres;
+               vtotal <<= 2;
+       } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+-              vtotal = var->upper_margin + (var->yres/2) + var->lower_margin +
+-                       var->vsync_len;   
+-      } else  vtotal = var->upper_margin + var->yres + var->lower_margin +
+-                       var->vsync_len;
++              vtotal += var->yres;
++              vtotal <<= 1;
++      } else  vtotal += var->yres;
+       if(!(htotal) || !(vtotal)) {
+               SISFAIL("sisfb: no valid timing data");
+       }
+-      if((var->pixclock) && (htotal)) {
+-         drate = 1E12 / var->pixclock;
+-         hrate = drate / htotal;
+-         refresh_rate = (unsigned int) (hrate / vtotal * 2 + 0.5);
+-      } else refresh_rate = 60;
+-
+-      /* TW: Calculation wrong for 1024x600 - force it to 60Hz */
+-      if((var->xres == 1024) && (var->yres == 600)) refresh_rate = 60;
+-
+       search_idx = 0;
+       while( (sisbios_mode[search_idx].mode_no != 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(search_idx) > 0) {
++                      if(sisfb_validate_mode(search_idx, ivideo.currentvbflags) > 0) {
+                          found_mode = 1;
+                          break;
+                       }
+@@ -1687,38 +2033,95 @@ static int sisfb_check_var(struct fb_var
+       }
+       if(!found_mode) {
+-      
+-              printk(KERN_ERR "sisfb: %dx%dx%d is no valid mode\n", 
+-                      var->xres, var->yres, var->bits_per_pixel);
+-                      
++
+                 search_idx = 0;
+               while(sisbios_mode[search_idx].mode_no != 0) {
+-                     
+                  if( (var->xres <= sisbios_mode[search_idx].xres) &&
+-                     (var->yres <= sisbios_mode[search_idx].yres) && 
++                     (var->yres <= sisbios_mode[search_idx].yres) &&
+                      (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
+-                        if(sisfb_validate_mode(search_idx) > 0) {
++                        if(sisfb_validate_mode(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;
+-                      printk(KERN_DEBUG "sisfb: Adapted to mode %dx%dx%d\n",
+-                              var->xres, var->yres, var->bits_per_pixel);
+-                 
++
++
+               } else {
+-                      printk(KERN_ERR "sisfb: Failed to find similar mode to %dx%dx%d\n", 
++                      printk(KERN_ERR "sisfb: Failed to find supported mode near %dx%dx%d\n",
+                               var->xres, var->yres, var->bits_per_pixel);
+                       return -EINVAL;
+               }
+       }
+-      /* TW: TODO: Check the refresh rate */          
+-      
++      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 = 1E12 / pixclock;
++              hrate = drate / htotal;
++              refresh_rate = (unsigned int) (hrate / vtotal * 2 + 0.5);
++      } else if( ( (ivideo.current_htotal != htotal) ||       /* x!=x | y!=y & c=c -> invalid pixclock */
++                   (ivideo.current_vtotal != vtotal) ) &&
++                 (ivideo.current_pixclock == var->pixclock) ) {
++              if(sisfb_lastrates[sisbios_mode[search_idx].mode_no]) {
++                      refresh_rate = sisfb_lastrates[sisbios_mode[search_idx].mode_no];
++              } else if(sisfb_parm_rate != -1) {
++                      refresh_rate = sisfb_parm_rate;
++              } else {
++                      refresh_rate = 60;
++              }
++              recalc_clock = TRUE;
++      } else if((pixclock) && (htotal) && (vtotal)) {
++              drate = 1E12 / pixclock;
++              hrate = drate / htotal;
++              refresh_rate = (unsigned int) (hrate / vtotal * 2 + 0.5);
++      } 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(refresh_rate, search_idx);
++
++      /* Eventually recalculate timing and clock */
++      if(recalc_clock) {
++         if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
++         var->pixclock = (u32) (1E12 / sisfb_mode_rate_to_dclock(&SiS_Pr, &sishw_ext,
++                                              sisbios_mode[search_idx].mode_no, myrateindex));
++         sisfb_mode_rate_to_ddata(&SiS_Pr, &sishw_ext,
++                                      sisbios_mode[search_idx].mode_no, myrateindex,
++                                      &var->left_margin, &var->right_margin,
++                                      &var->upper_margin, &var->lower_margin,
++                                      &var->hsync_len, &var->vsync_len,
++                                      &var->sync, &var->vmode);
++         if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
++              var->pixclock <<= 1;
++         }
++      }
++
++      if(sisfb_thismonitor.datavalid) {
++         if(!sisfb_verify_rate(&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(var);  
+       
+@@ -1732,17 +2135,19 @@ static int sisfb_check_var(struct fb_var
+       if(var->xres != var->xres_virtual)
+               var->xres_virtual = var->xres;
+-      if(!sisfb_ypan) {
+-              if(var->yres != var->yres_virtual)
+-                      var->yres_virtual = var->yres;
+-      } else {
++      if(sisfb_ypan) {
+          /* TW: Now patch yres_virtual if we use panning */
+          /* *** May I do this? *** */
+          var->yres_virtual = ivideo.heapstart / (var->xres * (var->bits_per_pixel >> 3));
+-          if(var->yres_virtual <= var->yres) {
++         if(var->yres_virtual <= var->yres) {
+               /* TW: Paranoia check */
+               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 */
+@@ -1757,28 +2162,25 @@ static int sisfb_check_var(struct fb_var
+           var->green.msb_right =
+           var->blue.msb_right =
+           var->transp.offset = var->transp.length = var->transp.msb_right = 0;                
+-              
+-      TWDEBUG("end of check_var");
++
+       return 0;
+ }
+-#ifdef SISFB_PAN
+ static int sisfb_pan_display(struct fb_var_screeninfo *var,
+                            struct fb_info* info)
+ {
+       int err;
+-      
+-      TWDEBUG("inside pan_display");
+-      
++
+       if (var->xoffset > (var->xres_virtual - var->xres))
+               return -EINVAL;
+       if (var->yoffset > (var->yres_virtual - var->yres))
+               return -EINVAL;
+       if (var->vmode & FB_VMODE_YWRAP) {
+-              if (var->yoffset < 0
+-                  || var->yoffset >= info->var.yres_virtual
+-                  || var->xoffset) return -EINVAL;
++              if (var->yoffset < 0 ||
++                  var->yoffset >= info->var.yres_virtual ||
++                  var->xoffset)
++                      return -EINVAL;
+       } else {
+               if (var->xoffset + info->var.xres > info->var.xres_virtual ||
+                   var->yoffset + info->var.yres > info->var.yres_virtual)
+@@ -1794,10 +2196,8 @@ static int sisfb_pan_display(struct fb_v
+       else
+               info->var.vmode &= ~FB_VMODE_YWRAP;
+-      TWDEBUG("end of pan_display");
+       return 0;
+ }
+-#endif
+ static int sisfb_mmap(struct fb_info *info, struct file *file,
+                     struct vm_area_struct *vma)
+@@ -1806,7 +2206,6 @@ static int sisfb_mmap(struct fb_info *in
+       unsigned long off;
+       u32 len, mmio_off;
+-      TWDEBUG("inside mmap");
+       if(vma->vm_pgoff > (~0UL >> PAGE_SHIFT))  return -EINVAL;
+       off = vma->vm_pgoff << PAGE_SHIFT;
+@@ -1844,139 +2243,143 @@ static int sisfb_mmap(struct fb_info *in
+                               vma->vm_page_prot))
+               return -EAGAIN;
+-        TWDEBUG("end of mmap");
+       return 0;
+ }
+ static int sisfb_blank(int blank, struct fb_info *info)
+ {
+-      u8 reg;
++      return(sisfb_myblank(blank));
++}
+-      inSISIDXREG(SISCR, 0x17, reg);
++#endif
+-      if(blank > 0)
+-              reg &= 0x7f;
+-      else
+-              reg |= 0x80;
++/* ----------- FBDev related routines for all series ---------- */
+-        outSISIDXREG(SISCR, 0x17, reg);               
+-      outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */
+-      outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */
+-        return(0);
+-}
++#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)
++#else
+ static int sisfb_ioctl(struct inode *inode, struct file *file,
+-                     unsigned int cmd, unsigned long arg, 
++                     unsigned int cmd, unsigned long arg, int con,
+                      struct fb_info *info)
++#endif
+ {
+-      TWDEBUG("inside ioctl");
++      struct sis_memreq sismemreq;
++      struct ap_data sisapdata;
++      unsigned long sismembase = 0;
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
++      SIS_GLYINFO sisglyinfo;
++#endif
++
+       switch (cmd) {
+          case FBIO_ALLOC:
+-              if (!capable(CAP_SYS_RAWIO))
++              if(!capable(CAP_SYS_RAWIO))
+                       return -EPERM;
+-              sis_malloc((struct sis_memreq *) arg);
++              if(copy_from_user(&sismemreq, (void *)arg, sizeof(sismemreq)))
++                      return -EFAULT;
++              sis_malloc(&sismemreq);
++              if(copy_to_user((void *)arg, &sismemreq, sizeof(sismemreq))) {
++                      sis_free(sismemreq.offset);
++                      return -EFAULT;
++              }
+               break;
+          case FBIO_FREE:
+-              if (!capable(CAP_SYS_RAWIO))
++              if(!capable(CAP_SYS_RAWIO))
+                       return -EPERM;
+-              sis_free(*(unsigned long *) arg);
++              if(get_user(sismembase, (unsigned long *) arg))
++                      return -EFAULT;
++              sis_free(sismembase);
+               break;
+-         case FBIOGET_HWCINFO:
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
++         case FBIOGET_GLYPH:
++              if(copy_from_user(&sisglyinfo, (void *)arg, sizeof(sisglyinfo)))
++                      return -EFAULT;
++                sis_get_glyph(info, &sisglyinfo);
++              break;
++         case FBIOPUT_MODEINFO:
+               {
+-                      unsigned long *hwc_offset = (unsigned long *) arg;
++                      struct mode_info x;
+-                      if (sisfb_caps & HW_CURSOR_CAP)
+-                              *hwc_offset = sisfb_hwcursor_vbase -
+-                                  (unsigned long) ivideo.video_vbase;
+-                      else
+-                              *hwc_offset = 0;
++                      if(copy_from_user(&x, (void *)arg, sizeof(x)))
++                              return -EFAULT;
++                      ivideo.video_bpp        = x.bpp;
++                      ivideo.video_width      = x.xres;
++                      ivideo.video_height     = x.yres;
++                      ivideo.video_vwidth     = x.v_xres;
++                      ivideo.video_vheight    = x.v_yres;
++                      ivideo.org_x            = x.org_x;
++                      ivideo.org_y            = x.org_y;
++                      ivideo.refresh_rate     = x.vrate;
++                      ivideo.video_linelength = ivideo.video_vwidth * (ivideo.video_bpp >> 3);
++                      sisfb_set_vparms();
+                       break;
+               }
+-         case FBIOPUT_MODEINFO:
++#endif
++         case FBIOGET_HWCINFO:
+               {
+-                      struct mode_info *x = (struct mode_info *)arg;
++                      unsigned long myhwcoffset = 0;
+-                      ivideo.video_bpp        = x->bpp;
+-                      ivideo.video_width      = x->xres;
+-                      ivideo.video_height     = x->yres;
+-                      ivideo.video_vwidth     = x->v_xres;
+-                      ivideo.video_vheight    = x->v_yres;
+-                      ivideo.org_x            = x->org_x;
+-                      ivideo.org_y            = x->org_y;
+-                      ivideo.refresh_rate     = x->vrate;
+-                      ivideo.video_linelength = ivideo.video_vwidth * (ivideo.video_bpp >> 3);
+-                      switch(ivideo.video_bpp) {
+-                      case 8:
+-                              ivideo.DstColor = 0x0000;
+-                              ivideo.SiS310_AccelDepth = 0x00000000;
+-                              ivideo.video_cmap_len = 256;
+-                              break;
+-                      case 16:
+-                              ivideo.DstColor = 0x8000;
+-                              ivideo.SiS310_AccelDepth = 0x00010000;
+-                              ivideo.video_cmap_len = 16;
+-                              break;
+-                      case 32:
+-                              ivideo.DstColor = 0xC000;
+-                              ivideo.SiS310_AccelDepth = 0x00020000;
+-                              ivideo.video_cmap_len = 16;
+-                              break;
+-                      default:
+-                              ivideo.video_cmap_len = 16;
+-                              printk(KERN_ERR "sisfb: Unsupported accel depth %d", ivideo.video_bpp);
+-                              ivideo.accel = 0;
+-                              break;
+-                      }
++                      if(sisfb_caps & HW_CURSOR_CAP)
++                              myhwcoffset = sisfb_hwcursor_vbase -
++                                  (unsigned long) ivideo.video_vbase;
++
++                      return put_user(myhwcoffset, (unsigned long *)arg);
+                       break;
+               }
+          case FBIOGET_DISPINFO:
+-              sis_dispinfo((struct ap_data *)arg);
++              sis_dispinfo(&sisapdata);
++              if(copy_to_user((void *)arg, &sisapdata, sizeof(sisapdata)))
++                      return -EFAULT;
+               break;
+-         case SISFB_GET_INFO:  /* TW: New for communication with X driver */
++         case SISFB_GET_INFO:  /* For communication with X driver */
+               {
+-                      sisfb_info *x = (sisfb_info *)arg;
++                      sisfb_info x;
+-                      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;
+-                      x->fbvidmode = sisfb_mode_no;
+-                      x->sisfb_caps = sisfb_caps;
+-                      x->sisfb_tqlen = 512; /* yet unused */
+-                      x->sisfb_pcibus = ivideo.pcibus;
+-                      x->sisfb_pcislot = ivideo.pcislot;
+-                      x->sisfb_pcifunc = ivideo.pcifunc;
+-                      x->sisfb_lcdpdc = sisfb_detectedpdc;
+-                      x->sisfb_lcda = sisfb_detectedlcda;
++                      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;
++                      x.fbvidmode = sisfb_mode_no;
++                      x.sisfb_caps = sisfb_caps;
++                      x.sisfb_tqlen = 512; /* yet unused */
++                      x.sisfb_pcibus = ivideo.pcibus;
++                      x.sisfb_pcislot = ivideo.pcislot;
++                      x.sisfb_pcifunc = ivideo.pcifunc;
++                      x.sisfb_lcdpdc = sisfb_detectedpdc;
++                      x.sisfb_lcda = sisfb_detectedlcda;
++                      x.sisfb_vbflags = ivideo.vbflags;
++                      x.sisfb_currentvbflags = ivideo.currentvbflags;
++                      x.sisfb_scalelcd = SiS_Pr.UsePanelScaler;
++                      x.sisfb_specialtiming = SiS_Pr.SiS_CustomT;
++                      if(copy_to_user((void *)arg, &x, sizeof(x)))
++                              return -EFAULT;
+                       break;
+               }
+          case SISFB_GET_VBRSTATUS:
+               {
+-                      unsigned long *vbrstatus = (unsigned long *) arg;
+-                      if(sisfb_CheckVBRetrace()) *vbrstatus = 1;
+-                      else                       *vbrstatus = 0;
++                      if(sisfb_CheckVBRetrace())
++                              return put_user(1UL, (unsigned long *) arg);
++                      else
++                              return put_user(0UL, (unsigned long *) arg);
++                      break;
+               }
+          default:
+               return -EINVAL;
+       }
+-      TWDEBUG("end of ioctl");
+       return 0;
+-
+ }
+-#endif
+-
+-/* ----------- FBDev related routines for all series ---------- */
+ static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+                        struct fb_info *info)
+ {
+-      TWDEBUG("inside get_fix");
+       memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)        
+@@ -1987,45 +2390,47 @@ static int sisfb_get_fix(struct fb_fix_s
+       fix->smem_start = ivideo.video_base;
+-        /* TW */
+         if((!sisfb_mem) || (sisfb_mem > (ivideo.video_size/1024))) {
+-          if (ivideo.video_size > 0x1000000) {
+-              fix->smem_len = 0xc00000;
+-          } else if (ivideo.video_size > 0x800000)
+-              fix->smem_len = 0x800000;
+-          else
+-              fix->smem_len = 0x400000;
++          if(sisvga_engine == SIS_300_VGA) {
++             if(ivideo.video_size > 0x1000000) {
++                      fix->smem_len = 0xc00000;
++             } else if(ivideo.video_size > 0x800000)
++                      fix->smem_len = 0x800000;
++             else
++                      fix->smem_len = 0x400000;
++            } else {
++              fix->smem_len = ivideo.video_size - 0x100000;
++          }
+         } else
+               fix->smem_len = sisfb_mem * 1024;
+-      fix->type        = video_type;
++      fix->type        = FB_TYPE_PACKED_PIXELS;
+       fix->type_aux    = 0;
+       if(ivideo.video_bpp == 8)
+               fix->visual = FB_VISUAL_PSEUDOCOLOR;
+       else
+               fix->visual = FB_VISUAL_TRUECOLOR;
+       fix->xpanstep    = 0;
+-#ifdef SISFB_PAN
++
+         if(sisfb_ypan)         fix->ypanstep = 1;
+-#endif
++
+       fix->ywrapstep   = 0;
+       fix->line_length = ivideo.video_linelength;
+       fix->mmio_start  = ivideo.mmio_base;
+       fix->mmio_len    = sisfb_mmio_size;
+       if(sisvga_engine == SIS_300_VGA) 
+          fix->accel    = FB_ACCEL_SIS_GLAMOUR;
+-      else if(ivideo.chip == SIS_330)
++      else if((ivideo.chip == SIS_330) || (ivideo.chip == SIS_660) || (ivideo.chip == SIS_760))
+          fix->accel    = FB_ACCEL_SIS_XABRE;
+-      else 
++      else
+          fix->accel    = FB_ACCEL_SIS_GLAMOUR_2;
+-      
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)                
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+       fix->reserved[0] = ivideo.video_size & 0xFFFF;
+       fix->reserved[1] = (ivideo.video_size >> 16) & 0xFFFF;
+       fix->reserved[2] = sisfb_caps;
+-#endif        
++#endif
+-      TWDEBUG("end of get_fix");
+       return 0;
+ }
+@@ -2033,17 +2438,15 @@ static int sisfb_get_fix(struct fb_fix_s
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+ static struct fb_ops sisfb_ops = {
+-      owner:          THIS_MODULE,
+-      fb_get_fix:     sisfb_get_fix,
+-      fb_get_var:     sisfb_get_var,
+-      fb_set_var:     sisfb_set_var,
+-      fb_get_cmap:    sisfb_get_cmap,
+-      fb_set_cmap:    sisfb_set_cmap,
+-#ifdef SISFB_PAN
+-        fb_pan_display:       sisfb_pan_display,
+-#endif
+-      fb_ioctl:       sisfb_ioctl,
+-      fb_mmap:        sisfb_mmap,
++      .owner          = THIS_MODULE,
++      .fb_get_fix     = sisfb_get_fix,
++      .fb_get_var     = sisfb_get_var,
++      .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_ioctl       = sisfb_ioctl,
++      .fb_mmap        = sisfb_mmap,
+ };
+ #endif
+@@ -2056,9 +2459,7 @@ static struct fb_ops sisfb_ops = {
+       .fb_check_var = sisfb_check_var,
+       .fb_set_par   = sisfb_set_par,
+       .fb_setcolreg = sisfb_setcolreg,
+-#ifdef SISFB_PAN
+         .fb_pan_display = sisfb_pan_display,
+-#endif        
+         .fb_blank     = sisfb_blank,
+       .fb_fillrect  = fbcon_sis_fillrect,
+       .fb_copyarea  = fbcon_sis_copyarea,
+@@ -2105,35 +2506,42 @@ static int sisfb_get_dram_size_300(void)
+       } else {                /* 540, 630, 730 */
+-              pdev = pci_find_device(PCI_VENDOR_ID_SI, nbridge_id, pdev);
+-              if (pdev) {
+-                      pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS, &pci_data);
+-                      pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4;
+-                      ivideo.video_size = (unsigned int)(1 << (pci_data+21));
+-                      pdev_valid = 1;
+-
+-                      reg = SIS_DATA_BUS_64 << 6;
+-                      switch (pci_data) {
+-                         case BRI_DRAM_SIZE_2MB:
+-                              reg |= SIS_DRAM_SIZE_2MB;
+-                              break;
+-                         case BRI_DRAM_SIZE_4MB:
+-                              reg |= SIS_DRAM_SIZE_4MB;
+-                              break;
+-                         case BRI_DRAM_SIZE_8MB:
+-                              reg |= SIS_DRAM_SIZE_8MB;
+-                              break;
+-                         case BRI_DRAM_SIZE_16MB:
+-                              reg |= SIS_DRAM_SIZE_16MB;
+-                              break;
+-                         case BRI_DRAM_SIZE_32MB:
+-                              reg |= SIS_DRAM_SIZE_32MB;
+-                              break;
+-                         case BRI_DRAM_SIZE_64MB:
+-                              reg |= SIS_DRAM_SIZE_64MB;
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,74)
++              pci_for_each_dev(pdev) {
++#else
++              while((pdev = pci_find_device(PCI_VENDOR_ID_SI, PCI_ANY_ID, pdev))) {
++#endif
++                      if ((pdev->vendor == PCI_VENDOR_ID_SI)
++                                     && (pdev->device == nbridge_id)) {
++                              pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS, &pci_data);
++                              pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4;
++                              ivideo.video_size = (unsigned int)(1 << (pci_data+21));
++                              pdev_valid = 1;
++
++                              reg = SIS_DATA_BUS_64 << 6;
++                              switch (pci_data) {
++                                 case BRI_DRAM_SIZE_2MB:
++                                      reg |= SIS_DRAM_SIZE_2MB;
++                                      break;
++                                 case BRI_DRAM_SIZE_4MB:
++                                      reg |= SIS_DRAM_SIZE_4MB;
++                                      break;
++                                 case BRI_DRAM_SIZE_8MB:
++                                      reg |= SIS_DRAM_SIZE_8MB;
++                                      break;
++                                 case BRI_DRAM_SIZE_16MB:
++                                      reg |= SIS_DRAM_SIZE_16MB;
++                                      break;
++                                 case BRI_DRAM_SIZE_32MB:
++                                      reg |= SIS_DRAM_SIZE_32MB;
++                                      break;
++                                 case BRI_DRAM_SIZE_64MB:
++                                      reg |= SIS_DRAM_SIZE_64MB;
++                                      break;
++                              }
++                              outSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg);
+                               break;
+                       }
+-                      outSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg);
+               }
+       
+               if (!pdev_valid)  return -1;
+@@ -2141,171 +2549,10 @@ static int sisfb_get_dram_size_300(void)
+       return 0;
+ }
+-static void sisfb_detect_VB_connect_300()
+-{
+-      u8 sr16, sr17, cr32, temp;
+-
+-      ivideo.TV_plug = ivideo.TV_type = 0;
+-
+-        switch(ivideo.hasVB) {
+-        case HASVB_LVDS_CHRONTEL:
+-        case HASVB_CHRONTEL:
+-           SiS_SenseCh();
+-           break;
+-        case HASVB_301:
+-        case HASVB_302:
+-           SiS_Sense30x();
+-           break;
+-      }
+-
+-      inSISIDXREG(SISSR, IND_SIS_SCRATCH_REG_17, sr17);
+-        inSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR32, cr32);
+-
+-      if ((sr17 & 0x0F) && (ivideo.chip != SIS_300)) {
+-
+-              if ((sr17 & 0x01) && !sisfb_crt1off)
+-                      sisfb_crt1off = 0;
+-              else {
+-                      if (sr17 & 0x0E)
+-                              sisfb_crt1off = 1;
+-                      else
+-                              sisfb_crt1off = 0;
+-              }
+-
+-              if (sisfb_crt2type != -1)
+-                      /* TW: override detected CRT2 type */
+-                      ivideo.disp_state = sisfb_crt2type;
+-                else if (sr17 & 0x04)
+-                      ivideo.disp_state = DISPTYPE_TV;                        
+-              else if (sr17 & 0x02)
+-                      ivideo.disp_state = DISPTYPE_LCD;                       
+-              else if (sr17 & 0x08 )
+-                      ivideo.disp_state = DISPTYPE_CRT2;
+-              else
+-                      ivideo.disp_state = 0;
+-
+-              if(sisfb_tvplug != -1)
+-                      /* PR/TW: override detected TV type */
+-                      ivideo.TV_plug = sisfb_tvplug;
+-              else if (sr17 & 0x20)
+-                      ivideo.TV_plug = TVPLUG_SVIDEO;
+-              else if (sr17 & 0x10)
+-                      ivideo.TV_plug = TVPLUG_COMPOSITE;
+-
+-              inSISIDXREG(SISSR, IND_SIS_SCRATCH_REG_16, sr16);
+-              if (sr16 & 0x20)
+-                      ivideo.TV_type = TVMODE_PAL;
+-              else
+-                      ivideo.TV_type = TVMODE_NTSC;
+-
+-      } else {
+-
+-              if ((cr32 & SIS_CRT1) && !sisfb_crt1off)
+-                      sisfb_crt1off = 0;
+-              else {
+-                      if (cr32 & 0x5F)
+-                              sisfb_crt1off = 1;
+-                      else
+-                              sisfb_crt1off = 0;
+-              }
+-
+-              if (sisfb_crt2type != -1)
+-                      /* TW: override detected CRT2 type */
+-                      ivideo.disp_state = sisfb_crt2type;
+-              else if (cr32 & SIS_VB_TV)
+-                      ivideo.disp_state = DISPTYPE_TV;
+-              else if (cr32 & SIS_VB_LCD)
+-                      ivideo.disp_state = DISPTYPE_LCD;
+-              else if (cr32 & SIS_VB_CRT2)
+-                      ivideo.disp_state = DISPTYPE_CRT2;
+-              else
+-                      ivideo.disp_state = 0;
+-
+-              /* TW: Detect TV plug & type */
+-              if(sisfb_tvplug != -1)
+-                      /* PR/TW: override with option */
+-                      ivideo.TV_plug = sisfb_tvplug;
+-              else if (cr32 & SIS_VB_HIVISION) {
+-                      ivideo.TV_type = TVMODE_HIVISION;
+-                      ivideo.TV_plug = TVPLUG_SVIDEO;
+-              }
+-              else if (cr32 & SIS_VB_SVIDEO)
+-                      ivideo.TV_plug = TVPLUG_SVIDEO;
+-              else if (cr32 & SIS_VB_COMPOSITE)
+-                      ivideo.TV_plug = TVPLUG_COMPOSITE;
+-              else if (cr32 & SIS_VB_SCART)
+-                      ivideo.TV_plug = TVPLUG_SCART;
+-
+-              if (ivideo.TV_type == 0) {
+-                      inSISIDXREG(SISSR, IND_SIS_POWER_ON_TRAP, temp);
+-                      if (temp & 0x01)
+-                              ivideo.TV_type = TVMODE_PAL;
+-                      else
+-                              ivideo.TV_type = TVMODE_NTSC;
+-              }
+-
+-      }
+-
+-      /* TW: Copy forceCRT1 option to CRT1off if option is given */
+-      if (sisfb_forcecrt1 != -1) {
+-              if(sisfb_forcecrt1) sisfb_crt1off = 0;
+-              else                sisfb_crt1off = 1;
+-      }
+-}
+-
+-static void sisfb_get_VB_type_300(void)
+-{
+-      u8 reg;
+-
+-      if(ivideo.chip != SIS_300) {
+-              if(!sisfb_has_VB_300()) {
+-                      inSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR37, reg);
+-                      switch ((reg & SIS_EXTERNAL_CHIP_MASK) >> 1) {
+-                         case SIS_EXTERNAL_CHIP_LVDS:
+-                              ivideo.hasVB = HASVB_LVDS;
+-                              break;
+-                         case SIS_EXTERNAL_CHIP_TRUMPION:
+-                              ivideo.hasVB = HASVB_TRUMPION;
+-                              break;
+-                         case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
+-                              ivideo.hasVB = HASVB_LVDS_CHRONTEL;
+-                              break;
+-                         case SIS_EXTERNAL_CHIP_CHRONTEL:
+-                              ivideo.hasVB = HASVB_CHRONTEL;
+-                              break;
+-                         default:
+-                              break;
+-                      }
+-              }
+-      } else {
+-              sisfb_has_VB_300();
+-      }
+-}
+-
+-static int sisfb_has_VB_300(void)
+-{
+-      u8 vb_chipid;
+-
+-      inSISIDXREG(SISPART4, 0x00, vb_chipid);
+-      switch (vb_chipid) {
+-         case 0x01:
+-              ivideo.hasVB = HASVB_301;
+-              break;
+-         case 0x02:
+-              ivideo.hasVB = HASVB_302;
+-              break;
+-         default:
+-              ivideo.hasVB = HASVB_NONE;
+-              return FALSE;
+-      }
+-      return TRUE;
+-
+-}
+-
+ #endif  /* CONFIG_FB_SIS_300 */
+-#ifdef CONFIG_FB_SIS_315    /* for SiS 315/550/650/740/330 */
++#ifdef CONFIG_FB_SIS_315    /* for SiS 315/550/650/740/330/660/760 */
+ static int sisfb_get_dram_size_315(void)
+ {
+@@ -2314,21 +2561,33 @@ static int sisfb_get_dram_size_315(void)
+       u8  pci_data;
+       u8  reg = 0;
+-      if (ivideo.chip == SIS_550 || ivideo.chip == SIS_650 || ivideo.chip == SIS_740) {
++      if (ivideo.chip == SIS_550 ||
++          ivideo.chip == SIS_650 ||
++          ivideo.chip == SIS_740 ||
++          ivideo.chip == SIS_660 ||
++          ivideo.chip == SIS_760) {
+ #ifdef LINUXBIOS
+-              while ((pdev = pci_find_device(PCI_VENDOR_ID_SI, PCI_ANY_ID, pdev)) != NULL) {
+-                      if ((pdev->device == PCI_DEVICE_ID_SI_550) ||
+-                           (pdev->device == PCI_DEVICE_ID_SI_650) ||
+-                           (pdev->device == PCI_DEVICE_ID_SI_740)) {
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,74)
++              pci_for_each_dev(pdev) {
++#else
++              while((pdev = pci_find_device(PCI_VENDOR_ID_SI, PCI_ANY_ID, pdev))) {
++#endif
++
++                      if ( (pdev->vendor == PCI_VENDOR_ID_SI)
++                              && ( (pdev->device == PCI_DEVICE_ID_SI_550) ||
++                                   (pdev->device == PCI_DEVICE_ID_SI_650) ||
++                                   (pdev->device == PCI_DEVICE_ID_SI_740) ||
++                                   (pdev->device == PCI_DEVICE_ID_SI_660) ||
++                                   (pdev->device == PCI_DEVICE_ID_SI_760))) {
+                               pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS,
+                                                    &pci_data);
+                               pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4;
+                               ivideo.video_size = (unsigned int)(1 << (pci_data + 21));
+                               pdev_valid = 1;
+-                              /* TW: Initialize SR14 "by hand" */
++                              /* Initialize SR14 "by hand" */
+                               inSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg);
+                               reg &= 0xC0;
+                               switch (pci_data) {
+@@ -2390,7 +2649,15 @@ static int sisfb_get_dram_size_315(void)
+                              "now reading from PCI config\n");
+                       pdev_valid = 0;
+-                      while ((pdev = pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_550, pdev)) != NULL) {
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,74)
++                      pci_for_each_dev(pdev) {
++#else
++                      while((pdev = pci_find_device(PCI_VENDOR_ID_SI, PCI_ANY_ID, pdev))) {
++#endif
++
++                         if ( (pdev->vendor == PCI_VENDOR_ID_SI)
++                               && (pdev->device == PCI_DEVICE_ID_SI_550) ) {
++
+                               pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS,
+                                                    &pci_data);
+                               pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4;
+@@ -2415,6 +2682,7 @@ static int sisfb_get_dram_size_315(void)
+                                       return -1;
+                               }
+                               outSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg);
++                         }
+                       }
+                       if (!pdev_valid) {
+                               printk(KERN_INFO "sisfb: Total confusion - No SiS PCI VGA device found?!\n");
+@@ -2425,7 +2693,7 @@ static int sisfb_get_dram_size_315(void)
+ #endif
+               return 0;
+-      } else {        /* 315 */
++      } else {        /* 315, 330 */
+               inSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg);
+               switch ((reg & SIS315_DRAM_SIZE_MASK) >> 4) {
+@@ -2458,7 +2726,7 @@ static int sisfb_get_dram_size_315(void)
+               reg >>= 2;
+               
+               if(ivideo.chip == SIS_330) {
+-              
++
+                  if(reg) ivideo.video_size <<= 1;
+               
+               } else {
+@@ -2470,7 +2738,7 @@ static int sisfb_get_dram_size_315(void)
+                     case SIS315_DUAL_CHANNEL_1_RANK:
+                          ivideo.video_size <<= 1;
+                          break;
+-                    case SIS315_ASYM_DDR:             /* TW: DDR asymentric */
++                    case SIS315_ASYM_DDR:             /* TW: DDR asymetric */
+                          ivideo.video_size += (ivideo.video_size/2);
+                          break;
+                  }
+@@ -2483,127 +2751,241 @@ static int sisfb_get_dram_size_315(void)
+       
+ }
+-static void sisfb_detect_VB_connect_315(void)
++#endif   /* CONFIG_FB_SIS_315 */
++
++
++/* -------------- video bridge detection --------------- */
++
++static void sisfb_detect_VB_connect()
+ {
+-      u8 cr32, temp=0;
++      u8 sr16, sr17, cr32, temp;
++
++      if(sisvga_engine == SIS_300_VGA) {
+-      ivideo.TV_plug = ivideo.TV_type = 0;
++              inSISIDXREG(SISSR, IND_SIS_SCRATCH_REG_17, sr17);
++
++              if ((sr17 & 0x0F) && (ivideo.chip != SIS_300)) {
++
++                      /* Old BIOSes store the detected CRT2 type in SR17
++                       * instead of CR32. However, since our detection
++                       * routines store their results to CR32, we now copy
++                       * the remaining bits (for LCD and VGA) to CR32 for
++                       * unified usage.
++                       * SR17[0] CRT1    [1] LCD     [2] TV    [3] VGA2
++                       *     [4] AVIDEO  [5] SVIDEO
++                       */
++
++#if 0
++                      if (sr17 & 0x01) orSISIDXREG(SISCR, 0x32, SIS_CRT1);
++                      else             andSISIDXREG(SISCR, 0x32, ~SIS_CRT1);
++
++                      if (sr17 & 0x02) orSISIDXREG(SISCR, 0x32, SIS_VB_LCD);
++                      else             andSISIDXREG(SISCR, 0x32, ~SIS_VB_LCD);
++
++                      /* no HiVision and no DVI connector here */
++                      andSISIDXREG(SISCR, 0x32, ~0xc0);
++#endif
++
++                      /* PAL/NTSC is stored on SR16 on such machines */
++                      if (!(ivideo.vbflags & (TV_PAL | TV_NTSC))) {
++                              inSISIDXREG(SISSR, IND_SIS_SCRATCH_REG_16, sr16);
++                              if (sr16 & 0x20)
++                                      ivideo.vbflags |= TV_PAL;
++                              else
++                                      ivideo.vbflags |= TV_NTSC;
++                      }
++
++              }
+-        switch(ivideo.hasVB) {
+-        case HASVB_LVDS_CHRONTEL:
+-        case HASVB_CHRONTEL:
+-           SiS_SenseCh();
+-           break;
+-        case HASVB_301:
+-        case HASVB_302:
+-           SiS_Sense30x();
+-           break;
+       }
+       inSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR32, cr32);
+-      if ((cr32 & SIS_CRT1) && !sisfb_crt1off)
++      if (cr32 & SIS_CRT1)
+               sisfb_crt1off = 0;
+       else {
+-              if (cr32 & 0x5F)   
++              if (cr32 & 0x5F)
+                       sisfb_crt1off = 1;
+               else
+                       sisfb_crt1off = 0;
+       }
+-      if (sisfb_crt2type != -1)
+-              /* TW: Override with option */
+-              ivideo.disp_state = sisfb_crt2type;
+-      else if (cr32 & SIS_VB_TV)
+-              ivideo.disp_state = DISPTYPE_TV;                
+-      else if (cr32 & SIS_VB_LCD)
+-              ivideo.disp_state = DISPTYPE_LCD;               
+-      else if (cr32 & SIS_VB_CRT2)
+-              ivideo.disp_state = DISPTYPE_CRT2;
+-      else
+-              ivideo.disp_state = 0;
++      ivideo.vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
++      if (cr32 & SIS_VB_TV)
++              ivideo.vbflags |= CRT2_TV;
++      if (cr32 & SIS_VB_LCD)
++              ivideo.vbflags |= CRT2_LCD;
++      if (cr32 & SIS_VB_CRT2)
++              ivideo.vbflags |= CRT2_VGA;
++
++      /* TW: Detect/set TV plug & type */
+       if(sisfb_tvplug != -1)
+-              /* PR/TW: Override with option */
+-              ivideo.TV_plug = sisfb_tvplug;
+-      else if (cr32 & SIS_VB_HIVISION) {
+-              ivideo.TV_type = TVMODE_HIVISION;
+-              ivideo.TV_plug = TVPLUG_SVIDEO;
+-      }
++              ivideo.vbflags |= sisfb_tvplug;
++      if (cr32 & SIS_VB_HIVISION)
++              ivideo.vbflags |= (TV_HIVISION | TV_SVIDEO);
+       else if (cr32 & SIS_VB_SVIDEO)
+-              ivideo.TV_plug = TVPLUG_SVIDEO;
++              ivideo.vbflags |= TV_SVIDEO;
+       else if (cr32 & SIS_VB_COMPOSITE)
+-              ivideo.TV_plug = TVPLUG_COMPOSITE;
++              ivideo.vbflags |= TV_AVIDEO;
+       else if (cr32 & SIS_VB_SCART)
+-              ivideo.TV_plug = TVPLUG_SCART;
++              ivideo.vbflags |= TV_SCART;
+-      if(ivideo.TV_type == 0) {
+-          /* TW: PAL/NTSC changed for 650 */
+-          if((ivideo.chip <= SIS_315PRO) || (ivideo.chip >= SIS_330)) {
+-
+-                inSISIDXREG(SISCR, 0x38, temp);
+-              if(temp & 0x10)
+-                      ivideo.TV_type = TVMODE_PAL;
+-              else
+-                      ivideo.TV_type = TVMODE_NTSC;
++      if (!(ivideo.vbflags & (TV_PAL | TV_NTSC))) {
++              if(sisvga_engine == SIS_300_VGA) {
++                      inSISIDXREG(SISSR, IND_SIS_POWER_ON_TRAP, temp);
++                      if (temp & 0x01)
++                              ivideo.vbflags |= TV_PAL;
++                      else
++                              ivideo.vbflags |= TV_NTSC;
++              } else if((ivideo.chip <= SIS_315PRO) || (ivideo.chip == SIS_330)) {
+-          } else {
++                      inSISIDXREG(SISCR, 0x38, temp);
++                      if(temp & 0x10)
++                              ivideo.vbflags |= TV_PAL;
++                      else
++                              ivideo.vbflags |= TV_NTSC;
+-              inSISIDXREG(SISCR, 0x79, temp);
+-              if(temp & 0x20)
+-                      ivideo.TV_type = TVMODE_PAL;
+-              else
+-                      ivideo.TV_type = TVMODE_NTSC;
+-          }
++              } else {
++
++                      inSISIDXREG(SISCR, 0x79, temp);
++                      if(temp & 0x20)
++                              ivideo.vbflags |= TV_PAL;
++                      else
++                              ivideo.vbflags |= TV_NTSC;
++              }
+       }
+       /* TW: Copy forceCRT1 option to CRT1off if option is given */
+       if (sisfb_forcecrt1 != -1) {
+-              if (sisfb_forcecrt1) sisfb_crt1off = 0;
+-              else                 sisfb_crt1off = 1;
++              if(sisfb_forcecrt1) sisfb_crt1off = 0;
++              else                sisfb_crt1off = 1;
+       }
+-}
+-
+-static void sisfb_get_VB_type_315(void)
+-{
+-      u8 reg;
+-      if (!sisfb_has_VB_315()) {
+-              inSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR37, reg);
+-              switch ((reg & SIS_EXTERNAL_CHIP_MASK) >> 1) {
+-                 case SIS310_EXTERNAL_CHIP_LVDS:
+-                      ivideo.hasVB = HASVB_LVDS;
+-                      break;
+-                 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
+-                      ivideo.hasVB = HASVB_LVDS_CHRONTEL;
+-                      break;
+-                 default:
+-                      break;
+-              }
+-      }
+ }
+-
+-static int sisfb_has_VB_315(void)
++static void sisfb_get_VB_type(void)
+ {
+       u8 vb_chipid;
++      u8 reg;
++      char stdstr[]    = "sisfb: Detected";
++      char bridgestr[] = "video bridge";
++      char lvdsstr[]   = "LVDS transmitter";
++      char chrstr[]    = "Chrontel TV encoder";
++
++      ivideo.hasVB = HASVB_NONE;
++      sishw_ext.ujVBChipID = VB_CHIP_UNKNOWN;
++      sishw_ext.Is301BDH = FALSE;
++      sishw_ext.usExternalChip = 0;
+       inSISIDXREG(SISPART4, 0x00, vb_chipid);
+       switch (vb_chipid) {
+          case 0x01:
+               ivideo.hasVB = HASVB_301;
++              inSISIDXREG(SISPART4, 0x01, reg);
++              if(reg < 0xb0) {
++                      ivideo.vbflags |= VB_301;
++                      sishw_ext.ujVBChipID = VB_CHIP_301;
++                      printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
++              } else if(reg < 0xd0) {
++                      ivideo.vbflags |= VB_301B;
++                      sishw_ext.ujVBChipID = VB_CHIP_301B;
++                      printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
++              } else if(reg < 0xe0) {
++                      ivideo.vbflags |= VB_301LV;
++                      sishw_ext.ujVBChipID = VB_CHIP_301LV;
++                      printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
++              } else if(reg <= 0xe1) {
++                      ivideo.vbflags |= VB_302LV;
++                      sishw_ext.ujVBChipID = VB_CHIP_302LV;
++                      printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
++              }
+               break;
+          case 0x02:
+               ivideo.hasVB = HASVB_302;
++              inSISIDXREG(SISPART4, 0x01, reg);
++              if(reg < 0xd0) {
++                      ivideo.vbflags |= VB_302B;
++                      sishw_ext.ujVBChipID = VB_CHIP_302B;
++                      printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
++              } else if(reg < 0xe0) {
++                      ivideo.vbflags |= VB_301LV;
++                      sishw_ext.ujVBChipID = VB_CHIP_301LV;
++                      printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
++              } else if(reg <= 0xe1) {
++                      ivideo.vbflags |= VB_302LV;
++                      sishw_ext.ujVBChipID = VB_CHIP_302LV;
++                      printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
++              }
+               break;
+-         default:
+-              ivideo.hasVB = HASVB_NONE;
+-              return FALSE;
+       }
+-      return TRUE;
+-}
+-#endif   /* CONFIG_FB_SIS_315 */
++      if(ivideo.vbflags & (VB_301B | VB_302B)) {
++              inSISIDXREG(SISPART4,0x23,reg);
++              if(!(reg & 0x02)) {
++                      sishw_ext.Is301BDH = TRUE;
++                      ivideo.vbflags |= VB_30xBDH;
++                      printk(KERN_INFO "This %s does not support LCD output\n", bridgestr);
++              }
++      }
++
++      if((!(ivideo.vbflags & VB_VIDEOBRIDGE)) && (ivideo.chip != SIS_300)) {
++              inSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR37, reg);
++              reg &= SIS_EXTERNAL_CHIP_MASK;
++              reg >>= 1;
++              if(sisvga_engine == SIS_300_VGA) {
++                      switch (reg) {
++                         case SIS_EXTERNAL_CHIP_LVDS:
++                              ivideo.hasVB = HASVB_LVDS;
++                              ivideo.vbflags |= VB_LVDS;
++                              sishw_ext.usExternalChip = 0x01;
++                              printk(KERN_INFO "%s %s\n", stdstr, lvdsstr);
++                              break;
++                         case SIS_EXTERNAL_CHIP_TRUMPION:
++                              ivideo.hasVB = HASVB_TRUMPION;
++                              ivideo.vbflags |= VB_TRUMPION;
++                              sishw_ext.usExternalChip = 0x02;
++                              printk(KERN_INFO "%s Trumpion LCD scaler\n", stdstr);
++                              break;
++                         case SIS_EXTERNAL_CHIP_CHRONTEL:
++                              ivideo.hasVB = HASVB_CHRONTEL;
++                              ivideo.vbflags |= VB_CHRONTEL;
++                              sishw_ext.usExternalChip = 0x04;
++                              printk(KERN_INFO "%s %s\n", stdstr, chrstr);
++                              break;
++                         case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
++                              ivideo.hasVB = HASVB_LVDS_CHRONTEL;
++                              ivideo.vbflags |= (VB_LVDS | VB_CHRONTEL);
++                              sishw_ext.usExternalChip = 0x05;
++                              printk(KERN_INFO "%s %s and %s\n", stdstr, lvdsstr, chrstr);
++                              break;
++                      }
++              } else {
++                      switch (reg) {
++                         case SIS310_EXTERNAL_CHIP_LVDS:
++                              ivideo.hasVB = HASVB_LVDS;
++                              ivideo.vbflags |= VB_LVDS;
++                              sishw_ext.usExternalChip = 0x01;
++                              printk(KERN_INFO "%s %s\n", stdstr, lvdsstr);
++                              break;
++                         case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
++                              ivideo.hasVB = HASVB_LVDS_CHRONTEL;
++                              ivideo.vbflags |= (VB_LVDS | VB_CHRONTEL);
++                              sishw_ext.usExternalChip = 0x05;
++                              printk(KERN_INFO "%s %s and %s\n", stdstr, lvdsstr, chrstr);
++                              break;
++                      }
++              }
++
++      }
++
++      if(ivideo.vbflags & VB_SISBRIDGE) {
++              SiS_Sense30x();
++      } else if(ivideo.vbflags & VB_CHRONTEL) {
++              SiS_SenseCh();
++      }
++
++}
+ /* ------------------ Sensing routines ------------------ */
+@@ -2621,34 +3003,39 @@ SISDoSense(int tempbl, int tempbh, int t
+     inSISIDXREG(SISPART4,0x03,temp);
+     temp ^= 0x0e;
+     temp &= tempch;
+-    return(temp);
++    return((temp == tempch));
+ }
+ void
+ SiS_Sense30x(void)
+ {
+-  u8 backupP4_0d;
++  u8 backupP4_0d,backupP2_00;
+   u8 testsvhs_tempbl, testsvhs_tempbh;
+   u8 testsvhs_tempcl, testsvhs_tempch;
+   u8 testcvbs_tempbl, testcvbs_tempbh;
+   u8 testcvbs_tempcl, testcvbs_tempch;
+   u8 testvga2_tempbl, testvga2_tempbh;
+   u8 testvga2_tempcl, testvga2_tempch;
+-  int myflag, result;
++  int myflag, result, haveresult, i, j;
++  char stdstr[] = "sisfb: Detected";
++  char tvstr[]  = "TV connected to";
+   inSISIDXREG(SISPART4,0x0d,backupP4_0d);
+   outSISIDXREG(SISPART4,0x0d,(backupP4_0d | 0x04));
++  inSISIDXREG(SISPART2,0x00,backupP2_00);
++  outSISIDXREG(SISPART2,0x00,(backupP2_00 | 0x1c));
++
+   if(sisvga_engine == SIS_300_VGA) {
+-      testvga2_tempbh = 0x00; testvga2_tempbl = 0xd1;
+-        testsvhs_tempbh = 0x00; testsvhs_tempbl = 0xb9;
+-      testcvbs_tempbh = 0x00; testcvbs_tempbl = 0xb3;
+-      if((sishw_ext.ujVBChipID != VB_CHIP_301) &&
+-         (sishw_ext.ujVBChipID != VB_CHIP_302) ) {
+-         testvga2_tempbh = 0x01; testvga2_tempbl = 0x90;
+-         testsvhs_tempbh = 0x01; testsvhs_tempbl = 0x6b;
+-         testcvbs_tempbh = 0x01; testcvbs_tempbl = 0x74;
++      if(ivideo.vbflags & (VB_301B|VB_302B|VB_301LV|VB_302LV)) {
++              testvga2_tempbh = 0x01; testvga2_tempbl = 0x90;
++              testsvhs_tempbh = 0x01; testsvhs_tempbl = 0x6b;
++              testcvbs_tempbh = 0x01; testcvbs_tempbl = 0x74;
++      } else {
++              testvga2_tempbh = 0x00; testvga2_tempbl = 0xd1;
++              testsvhs_tempbh = 0x00; testsvhs_tempbl = 0xb9;
++              testcvbs_tempbh = 0x00; testcvbs_tempbl = 0xb3;
+       }
+       inSISIDXREG(SISPART4,0x01,myflag);
+       if(myflag & 0x04) {
+@@ -2657,35 +3044,36 @@ SiS_Sense30x(void)
+          testcvbs_tempbh = 0x00; testcvbs_tempbl = 0xee;
+       }
+       testvga2_tempch = 0x0e; testvga2_tempcl = 0x08;
+-      testsvhs_tempch = 0x06; testsvhs_tempcl = 0x04;
++      testsvhs_tempch = 0x04; testsvhs_tempcl = 0x04;
+       testcvbs_tempch = 0x08; testcvbs_tempcl = 0x04;
++      if(ivideo.vbflags & (VB_301LV|VB_302LV)) {
++              testvga2_tempbh = 0x00; testvga2_tempbl = 0x00;
++              testvga2_tempch = 0x00; testvga2_tempcl = 0x00;
++       }
+       if(ivideo.chip == SIS_300) {
+          inSISIDXREG(SISSR,0x3b,myflag);
+          if(!(myflag & 0x01)) {
+-            testvga2_tempbh = 0x00; testvga2_tempbl = 0x00;
+-            testvga2_tempch = 0x00; testvga2_tempcl = 0x00;
++              testvga2_tempbh = 0x00; testvga2_tempbl = 0x00;
++              testvga2_tempch = 0x00; testvga2_tempcl = 0x00;
+          }
+       }
+   } else {
+-      testvga2_tempbh = 0x00; testvga2_tempbl = 0xd1;
+-        testsvhs_tempbh = 0x00; testsvhs_tempbl = 0xb9;
+-      testcvbs_tempbh = 0x00; testcvbs_tempbl = 0xb3;
+-      if((sishw_ext.ujVBChipID != VB_CHIP_301) &&
+-         (sishw_ext.ujVBChipID != VB_CHIP_302)) {
+-            testvga2_tempbh = 0x01; testvga2_tempbl = 0x90;
+-            testsvhs_tempbh = 0x01; testsvhs_tempbl = 0x6b;
+-            testcvbs_tempbh = 0x01; testcvbs_tempbl = 0x74;
+-            if(sishw_ext.ujVBChipID == VB_CHIP_301LV ||
+-               sishw_ext.ujVBChipID == VB_CHIP_302LV) {
+-               testvga2_tempbh = 0x00; testvga2_tempbl = 0x00;
+-               testsvhs_tempbh = 0x02; testsvhs_tempbl = 0x00;
+-               testcvbs_tempbh = 0x01; testcvbs_tempbl = 0x00;
+-            }
++      if(ivideo.vbflags & (VB_301B|VB_302B)) {
++              testvga2_tempbh = 0x01; testvga2_tempbl = 0x90;
++              testsvhs_tempbh = 0x01; testsvhs_tempbl = 0x6b;
++              testcvbs_tempbh = 0x01; testcvbs_tempbl = 0x74;
++      } else if(ivideo.vbflags & (VB_301LV|VB_302LV)) {
++              testvga2_tempbh = 0x00; testvga2_tempbl = 0x00;
++              testsvhs_tempbh = 0x02; testsvhs_tempbl = 0x00;
++              testcvbs_tempbh = 0x01; testcvbs_tempbl = 0x00;
++      } else {
++              testvga2_tempbh = 0x00; testvga2_tempbl = 0xd1;
++              testsvhs_tempbh = 0x00; testsvhs_tempbl = 0xb9;
++              testcvbs_tempbh = 0x00; testcvbs_tempbl = 0xb3;
+       }
+-      if(sishw_ext.ujVBChipID != VB_CHIP_301LV &&
+-         sishw_ext.ujVBChipID != VB_CHIP_302LV) {
++      if(ivideo.vbflags & (VB_301|VB_301B|VB_302B)) {
+          inSISIDXREG(SISPART4,0x01,myflag);
+          if(myflag & 0x04) {
+             testvga2_tempbh = 0x00; testvga2_tempbl = 0xfd;
+@@ -2693,49 +3081,78 @@ SiS_Sense30x(void)
+             testcvbs_tempbh = 0x00; testcvbs_tempbl = 0xee;
+          }
+       }
+-      if((sishw_ext.ujVBChipID == VB_CHIP_301LV) ||
+-         (sishw_ext.ujVBChipID == VB_CHIP_302LV) ) {
++      if(ivideo.vbflags & (VB_301LV|VB_302LV)) {
+          testvga2_tempbh = 0x00; testvga2_tempbl = 0x00;
+          testvga2_tempch = 0x00; testvga2_tempcl = 0x00;
+          testsvhs_tempch = 0x04; testsvhs_tempcl = 0x08;
+          testcvbs_tempch = 0x08; testcvbs_tempcl = 0x08;
+       } else {
+          testvga2_tempch = 0x0e; testvga2_tempcl = 0x08;
+-         testsvhs_tempch = 0x06; testsvhs_tempcl = 0x04;
++         testsvhs_tempch = 0x04; testsvhs_tempcl = 0x04;
+          testcvbs_tempch = 0x08; testcvbs_tempcl = 0x04;
+       }
+     } 
+     if(testvga2_tempch || testvga2_tempcl || testvga2_tempbh || testvga2_tempbl) {
+-        result = SISDoSense(testvga2_tempbl, testvga2_tempbh,
+-                            testvga2_tempcl, testvga2_tempch);
+-      if(result) {
+-              printk(KERN_INFO "sisfb: Detected secondary VGA connection\n");
+-              orSISIDXREG(SISCR, 0x32, 0x10);
+-      }
++       haveresult = 0;
++       for(j = 0; j < 10; j++) {
++          result = 0;
++          for(i = 0; i < 3; i++) {
++             if(SISDoSense(testvga2_tempbl, testvga2_tempbh,
++                           testvga2_tempcl, testvga2_tempch))
++              result++;
++          }
++        if((result == 0) || (result >= 2)) break;
++       }
++       if(result) {
++          printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
++        orSISIDXREG(SISCR, 0x32, 0x10);
++       } else {
++        andSISIDXREG(SISCR, 0x32, ~0x10);
++       }
++    }
++
++    haveresult = 0;
++    for(j = 0; j < 10; j++) {
++       result = 0;
++       for(i = 0; i < 3; i++) {
++          if(SISDoSense(testsvhs_tempbl, testsvhs_tempbh,
++                        testsvhs_tempcl, testsvhs_tempch))
++              result++;
++       }
++       if((result == 0) || (result >= 2)) break;
+     }
+-    
+-    result = SISDoSense(testsvhs_tempbl, testsvhs_tempbh,
+-                        testsvhs_tempcl, testsvhs_tempch);
+     if(result) {
+-        printk(KERN_INFO "sisfb: Detected TV connected to SVHS output\n");
+-        /* TW: So we can be sure that there IS a SVHS output */
+-      ivideo.TV_plug = TVPLUG_SVIDEO;
++        printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
++      ivideo.vbflags |= TV_SVIDEO;
+       orSISIDXREG(SISCR, 0x32, 0x02);
++      andSISIDXREG(SISCR, 0x32, ~0x05);
+     }
+     if(!result) {
+-        result = SISDoSense(testcvbs_tempbl, testcvbs_tempbh,
+-                          testcvbs_tempcl, testcvbs_tempch);
++
++      haveresult = 0;
++              for(j = 0; j < 10; j++) {
++           result = 0;
++           for(i = 0; i < 3; i++) {
++              if(SISDoSense(testcvbs_tempbl, testcvbs_tempbh,
++                          testcvbs_tempcl, testcvbs_tempch))
++              result++;
++           }
++           if((result == 0) || (result >= 2)) break;
++        }
+       if(result) {
+-          printk(KERN_INFO "sisfb: Detected TV connected to CVBS output\n");
+-          /* TW: So we can be sure that there IS a CVBS output */
+-          ivideo.TV_plug = TVPLUG_COMPOSITE;
++          printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
++          ivideo.vbflags |= TV_AVIDEO;
+           orSISIDXREG(SISCR, 0x32, 0x01);
++          andSISIDXREG(SISCR, 0x32, ~0x06);
++      } else {
++          andSISIDXREG(SISCR, 0x32, ~0x07);
+       }
+     }
+     SISDoSense(0, 0, 0, 0);
++    outSISIDXREG(SISPART2,0x00,backupP2_00);
+     outSISIDXREG(SISPART4,0x0d,backupP4_0d);
+ }
+@@ -2744,51 +3161,84 @@ void
+ SiS_SenseCh(void)
+ {
+-   u8 temp1;
+-#ifdef CONFIG_FB_SIS_315
+-   u8 temp2;
++   u8 temp1, temp2;
++#ifdef CONFIG_FB_SIS_300
++   unsigned char test[3];
++   int i;
+ #endif
++   char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
+    if(ivideo.chip < SIS_315H) {
+ #ifdef CONFIG_FB_SIS_300
+-       SiS_Pr.SiS_IF_DEF_CH70xx = 1;          /* TW: Chrontel 7005 */
++       SiS_Pr.SiS_IF_DEF_CH70xx = 1;          /* Chrontel 700x */
++       SiS_SetChrontelGPIO(&SiS_Pr, 0x9c);    /* Set general purpose IO for Chrontel communication */
++       SiS_DDC2Delay(&SiS_Pr, 1000);
+        temp1 = SiS_GetCH700x(&SiS_Pr, 0x25);
+-       if ((temp1 >= 50) && (temp1 <= 100)) {
+-         /* TW: Read power status */
++       /* TW: See Chrontel TB31 for explanation */
++       temp2 = SiS_GetCH700x(&SiS_Pr, 0x0e);
++       if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
++        SiS_SetCH700x(&SiS_Pr, 0x0b0e);
++        SiS_DDC2Delay(&SiS_Pr, 300);
++       }
++       temp2 = SiS_GetCH700x(&SiS_Pr, 0x25);
++       if(temp2 != temp1) temp1 = temp2;
++
++       if((temp1 >= 0x22) && (temp1 <= 0x50)) {
++         /* Read power status */
+          temp1 = SiS_GetCH700x(&SiS_Pr, 0x0e);
+          if((temp1 & 0x03) != 0x03) {
+-              /* TW: Power all outputs */
+-              SiS_SetCH70xxANDOR(&SiS_Pr, 0x030E,0xF8);
++              /* Power all outputs */
++              SiS_SetCH700x(&SiS_Pr, 0x0B0E);
++              SiS_DDC2Delay(&SiS_Pr, 300);
+          }
+-         /* TW: Sense connected TV devices */
+-         SiS_SetCH700x(&SiS_Pr, 0x0110);
+-         SiS_SetCH700x(&SiS_Pr, 0x0010);
+-         temp1 = SiS_GetCH700x(&SiS_Pr, 0x10);
+-         if(!(temp1 & 0x08)) {
+-              printk(KERN_INFO
+-                 "sisfb: Chrontel: Detected TV connected to SVHS output\n");
+-              /* TW: So we can be sure that there IS a SVHS output */
+-              ivideo.TV_plug = TVPLUG_SVIDEO;
++         /* Sense connected TV devices */
++         for(i = 0; i < 3; i++) {
++             SiS_SetCH700x(&SiS_Pr, 0x0110);
++             SiS_DDC2Delay(&SiS_Pr, 0x96);
++             SiS_SetCH700x(&SiS_Pr, 0x0010);
++             SiS_DDC2Delay(&SiS_Pr, 0x96);
++             temp1 = SiS_GetCH700x(&SiS_Pr, 0x10);
++             if(!(temp1 & 0x08))       test[i] = 0x02;
++             else if(!(temp1 & 0x02))  test[i] = 0x01;
++             else                      test[i] = 0;
++             SiS_DDC2Delay(&SiS_Pr, 0x96);
++         }
++
++         if(test[0] == test[1])      temp1 = test[0];
++         else if(test[0] == test[2]) temp1 = test[0];
++         else if(test[1] == test[2]) temp1 = test[1];
++         else {
++              printk(KERN_INFO
++                      "sisfb: TV detection unreliable - test results varied\n");
++              temp1 = test[2];
++         }
++         if(temp1 == 0x02) {
++              printk(KERN_INFO "%s SVIDEO output\n", stdstr);
++              ivideo.vbflags |= TV_SVIDEO;
+               orSISIDXREG(SISCR, 0x32, 0x02);
+-         } else if (!(temp1 & 0x02)) {
+-              printk(KERN_INFO
+-                 "sisfb: Chrontel: Detected TV connected to CVBS output\n");
+-              /* TW: So we can be sure that there IS a CVBS output */
+-              ivideo.TV_plug = TVPLUG_COMPOSITE;
++              andSISIDXREG(SISCR, 0x32, ~0x05);
++         } else if (temp1 == 0x01) {
++              printk(KERN_INFO "%s CVBS output\n", stdstr);
++              ivideo.vbflags |= TV_AVIDEO;
+               orSISIDXREG(SISCR, 0x32, 0x01);
++              andSISIDXREG(SISCR, 0x32, ~0x06);
+          } else {
+               SiS_SetCH70xxANDOR(&SiS_Pr, 0x010E,0xF8);
++              andSISIDXREG(SISCR, 0x32, ~0x07);
+          }
+        } else if(temp1 == 0) {
+         SiS_SetCH70xxANDOR(&SiS_Pr, 0x010E,0xF8);
++        andSISIDXREG(SISCR, 0x32, ~0x07);
+        }
++       /* Set general purpose IO for Chrontel communication */
++       SiS_SetChrontelGPIO(&SiS_Pr, 0x00);
+ #endif
+    } else {
+ #ifdef CONFIG_FB_SIS_315
+-      SiS_Pr.SiS_IF_DEF_CH70xx = 2;           /* TW: Chrontel 7019 */
++      SiS_Pr.SiS_IF_DEF_CH70xx = 2;           /* Chrontel 7019 */
+         temp1 = SiS_GetCH701x(&SiS_Pr, 0x49);
+       SiS_SetCH701x(&SiS_Pr, 0x2049);
+       SiS_DDC2Delay(&SiS_Pr, 0x96);
+@@ -2808,22 +3258,24 @@ SiS_SenseCh(void)
+       if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
+       switch(temp1) {
+       case 0x01:
+-           printk(KERN_INFO
+-              "sisfb: Chrontel: Detected TV connected to CVBS output\n");
+-           ivideo.TV_plug = TVPLUG_COMPOSITE;
++           printk(KERN_INFO "%s CVBS output\n", stdstr);
++           ivideo.vbflags |= TV_AVIDEO;
+            orSISIDXREG(SISCR, 0x32, 0x01);
++           andSISIDXREG(SISCR, 0x32, ~0x06);
+              break;
+       case 0x02:
+-           printk(KERN_INFO
+-              "sisfb: Chrontel: Detected TV connected to SVHS output\n");
+-           ivideo.TV_plug = TVPLUG_SVIDEO;
++           printk(KERN_INFO "%s SVIDEO output\n", stdstr);
++           ivideo.vbflags |= TV_SVIDEO;
+            orSISIDXREG(SISCR, 0x32, 0x02);
++           andSISIDXREG(SISCR, 0x32, ~0x05);
+              break;
+       case 0x04:
+-           /* TW: This should not happen */
+-           printk(KERN_INFO
+-              "sisfb: Chrontel: Detected TV connected to SCART output\n");
++           printk(KERN_INFO "%s SCART output\n", stdstr);
++           orSISIDXREG(SISCR, 0x32, 0x04);
++           andSISIDXREG(SISCR, 0x32, ~0x03);
+              break;
++      default:
++           andSISIDXREG(SISCR, 0x32, ~0x07);
+       }
+ #endif
+@@ -2845,8 +3297,8 @@ static int sisfb_heap_init(void)
+       unsigned long *write_port = 0;
+       SIS_CMDTYPE    cmd_type;
+ #ifndef AGPOFF
+-      struct agp_kern_info  *agp_info;
+-      struct agp_memory     *agp;
++      agp_kern_info  *agp_info;
++      agp_memory     *agp;
+       u32            agp_phys;
+ #endif
+ #endif
+@@ -2860,14 +3312,21 @@ static int sisfb_heap_init(void)
+  *     in XF86Config-4.
+  *     The heap start can also be specified by parameter "mem" when starting the sisfb
+  *     driver. sisfb mem=1024 lets heap starts at 1MB, etc.
++ *
++ *     On the 315 and Xabre series, the default is a 1MB heap since DRI is not
++ *     supported there.
+  */
+      if ((!sisfb_mem) || (sisfb_mem > (ivideo.video_size/1024))) {
+-        if (ivideo.video_size > 0x1000000) {
++        if(sisvga_engine == SIS_300_VGA) {
++           if (ivideo.video_size > 0x1000000) {
+               ivideo.heapstart = 0xc00000;
+-      } else if (ivideo.video_size > 0x800000) {
++         } else if (ivideo.video_size > 0x800000) {
+               ivideo.heapstart = 0x800000;
+-      } else {
++         } else {
+               ivideo.heapstart = 0x400000;
++         }
++      } else {
++         ivideo.heapstart = ivideo.video_size - 0x100000;
+       }
+      } else {
+            ivideo.heapstart = sisfb_mem * 1024;
+@@ -2883,7 +3342,7 @@ static int sisfb_heap_init(void)
+ #ifdef CONFIG_FB_SIS_315
+      if (sisvga_engine == SIS_315_VGA) {
+         /* TW: Now initialize the 310 series' command queue mode.
+-       * On 310/325, there are three queue modes available which
++       * On 315, there are three queue modes available which
+        * are chosen by setting bits 7:5 in SR26:
+        * 1. MMIO queue mode (bit 5, 0x20). The hardware will keep
+        *    track of the queue, the FIFO, command parsing and so
+@@ -2923,8 +3382,8 @@ static int sisfb_heap_init(void)
+ #ifndef AGPOFF
+       if (sisfb_queuemode == AGP_CMD_QUEUE) {
+-              agp_info = vmalloc(sizeof(*agp_info));
+-              memset((void*)agp_info, 0x00, sizeof(*agp_info));
++              agp_info = vmalloc(sizeof(agp_kern_info));
++              memset((void*)agp_info, 0x00, sizeof(agp_kern_info));
+               agp_copy_info(agp_info);
+               agp_backend_acquire();
+@@ -3025,10 +3484,6 @@ static int sisfb_heap_init(void)
+               break;
+          default:  /* MMIO */
+-              /* TW: This previously only wrote SIS_MMIO_CMD_ENABLE
+-               * to IND_SIS_CMDQUEUE_SET. I doubt that this is
+-               * enough. Reserve memory in any way.
+-               */
+               sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE;
+               sisfb_heap_size -= COMMAND_QUEUE_AREA_SIZE;
+@@ -3037,7 +3492,7 @@ static int sisfb_heap_init(void)
+               *write_port = *read_port;
+-              /* TW: Set Auto_Correction bit */
++              /* Set Auto_Correction bit */
+               temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
+               outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
+@@ -3333,7 +3788,6 @@ void sis_malloc(struct sis_memreq *req)
+               req->offset = poh->offset;
+               req->size = poh->size;
+       }
+-
+ }
+ void sis_free(unsigned long base)
+@@ -3352,35 +3806,70 @@ void sis_free(unsigned long base)
+ static void sisfb_pre_setmode(void)
+ {
+-      u8 cr30 = 0, cr31 = 0;
++      u8 cr30 = 0, cr31 = 0, cr33 = 0;
++
++      ivideo.currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
+       inSISIDXREG(SISCR, 0x31, cr31);
+       cr31 &= ~0x60;
++      cr31 |= 0x04;
+-      switch (ivideo.disp_state & DISPTYPE_DISP2) {
+-         case DISPTYPE_CRT2:
+-              cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
+-              cr31 |= SIS_DRIVER_MODE;
+-              break;
+-         case DISPTYPE_LCD:
+-              cr30  = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
+-              cr31 |= SIS_DRIVER_MODE;
+-              break;
+-         case DISPTYPE_TV:
+-              if (ivideo.TV_type == TVMODE_HIVISION)
++      cr33 = sisfb_rate_idx & 0x0F;
++
++      SiS_SetEnableDstn(&SiS_Pr, FALSE);
++      SiS_SetEnableFstn(&SiS_Pr, FALSE);
++
++      switch (ivideo.currentvbflags & VB_DISPTYPE_DISP2) {
++         case CRT2_TV:
++              ivideo.disp_state = DISPTYPE_TV;
++              if (ivideo.vbflags & TV_HIVISION) {
+                       cr30 = (SIS_VB_OUTPUT_HIVISION | SIS_SIMULTANEOUS_VIEW_ENABLE);
+-              else if (ivideo.TV_plug == TVPLUG_SVIDEO)
++                      ivideo.currentvbflags |= (TV_HIVISION | TV_SVIDEO);
++                      ivideo.TV_type = TVMODE_HIVISION;
++                      ivideo.TV_plug = TVPLUG_SVIDEO;
++              } else if (ivideo.vbflags & TV_SVIDEO) {
+                       cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
+-              else if (ivideo.TV_plug == TVPLUG_COMPOSITE)
++                      ivideo.currentvbflags |= TV_SVIDEO;
++                      ivideo.TV_plug = TVPLUG_SVIDEO;
++              } else if (ivideo.vbflags & TV_AVIDEO) {
+                       cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
+-              else if (ivideo.TV_plug == TVPLUG_SCART)
++                      ivideo.currentvbflags |= TV_AVIDEO;
++                      ivideo.TV_plug = TVPLUG_COMPOSITE;
++              } else if (ivideo.vbflags & TV_SCART) {
+                       cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
++                      ivideo.currentvbflags |= TV_SCART;
++                      ivideo.TV_plug = TVPLUG_SCART;
++              }
+               cr31 |= SIS_DRIVER_MODE;
+-              if (sisfb_tvmode == 1 || ivideo.TV_type == TVMODE_PAL)
+-                      cr31 |= 0x01;
+-                else
+-                        cr31 &= ~0x01;
++              if(!(ivideo.vbflags & TV_HIVISION)) {
++                      if (ivideo.vbflags & TV_PAL) {
++                              cr31 |= 0x01;
++                              ivideo.currentvbflags |= TV_PAL;
++                              ivideo.TV_type = TVMODE_PAL;
++                      } else {
++                              cr31 &= ~0x01;
++                              ivideo.currentvbflags |= TV_NTSC;
++                              ivideo.TV_type = TVMODE_NTSC;
++                      }
++              }
++              break;
++         case CRT2_LCD:
++              ivideo.disp_state = DISPTYPE_LCD;
++              cr30  = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
++              cr31 |= SIS_DRIVER_MODE;
++              SiS_SetEnableDstn(&SiS_Pr, sisfb_dstn);
++              SiS_SetEnableFstn(&SiS_Pr, sisfb_fstn);
++              break;
++         case CRT2_VGA:
++              ivideo.disp_state = DISPTYPE_CRT2;
++              cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
++              cr31 |= SIS_DRIVER_MODE;
++              if(sisfb_nocrt2rate) {
++                      cr33 |= (sisbios_mode[sisfb_mode_idx].rate_idx << 4);
++              } else {
++                      cr33 |= ((sisfb_rate_idx & 0x0F) << 4);
++              }
+               break;
+          default:     /* disable CRT2 */
+               cr30 = 0x00;
+@@ -3389,8 +3878,14 @@ static void sisfb_pre_setmode(void)
+       outSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR30, cr30);
+       outSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR31, cr31);
++      outSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR33, cr33);
+-        outSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR33, (sisfb_rate_idx & 0x0F));
++#ifdef CONFIG_FB_SIS_315
++        if(sisvga_engine == SIS_315_VGA) {
++         /* Clear LCDA and PAL-N/M bits */
++         andSISIDXREG(SISCR,0x38,~0xc3);
++      }
++#endif
+       if(ivideo.accel) sisfb_syncaccel();
+@@ -3400,67 +3895,89 @@ static void sisfb_pre_setmode(void)
+ static void sisfb_post_setmode(void)
+ {
+       u8 reg;
++      BOOLEAN crt1isoff = FALSE;
++#ifdef CONFIG_FB_SIS_315
++      u8 reg1;
++#endif
++#ifdef CONFIG_FB_SIS_300
+       BOOLEAN doit = TRUE;
+-#if 0 /* TW: Wrong: Is not in MMIO space, but in RAM */
+-      /* Backup mode number to MMIO space */
+-      if(ivideo.mmio_vbase) {
+-        *(volatile u8 *)(((u8*)ivideo.mmio_vbase) + 0x449) = (unsigned char)sisfb_mode_no;
+-      }
+-#endif        
+-
+-      if (ivideo.video_bpp == 8) {
+-              /* TW: We can't switch off CRT1 on LVDS/Chrontel in 8bpp Modes */
+-              if ((ivideo.hasVB == HASVB_LVDS) || (ivideo.hasVB == HASVB_LVDS_CHRONTEL)) {
+-                      doit = FALSE;
+-              }
+-              /* TW: We can't switch off CRT1 on 301B-DH in 8bpp Modes if using LCD */
+-              if ( (sishw_ext.Is301BDH) && (ivideo.disp_state & DISPTYPE_LCD) ) {
+-                      doit = FALSE;
+-              }
+-      }
+-
++#endif
+       /* TW: We can't switch off CRT1 if bridge is in slave mode */
+-      if(ivideo.hasVB != HASVB_NONE) {
+-              inSISIDXREG(SISPART1, 0x00, reg);
++      if(ivideo.vbflags & VB_VIDEOBRIDGE) {
++#ifdef CONFIG_FB_SIS_300
+               if(sisvga_engine == SIS_300_VGA) {
++                      inSISIDXREG(SISPART1, 0x00, reg);
+                       if((reg & 0xa0) == 0x20) {
+                               doit = FALSE;
+                       }
+               }
+-              if(sisvga_engine == SIS_315_VGA) {
+-                      if((reg & 0x50) == 0x10) {
+-                              doit = FALSE;
+-                      }
+-              }
++#endif
+       } else sisfb_crt1off = 0;
+-      inSISIDXREG(SISCR, 0x17, reg);
+-      if((sisfb_crt1off) && (doit))
+-              reg &= ~0x80;
+-      else          
+-              reg |= 0x80;
+-      outSISIDXREG(SISCR, 0x17, reg);
++      if(sisvga_engine == SIS_300_VGA) {
+-        andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
++#ifdef CONFIG_FB_SIS_300
++         if((sisfb_crt1off) && (doit)) {
++              crt1isoff = TRUE;
++              reg = 0x00;
++         } else {
++              crt1isoff = FALSE;
++              reg = 0x80;
++         }
++         setSISIDXREG(SISCR, 0x17, 0x7f, reg);
++#endif
++
++      } else {
++
++#ifdef CONFIG_FB_SIS_315
++         if(sisfb_crt1off) {
++              crt1isoff = TRUE;
++              reg  = 0x40;
++              reg1 = 0xc0;
++         } else {
++              crt1isoff = FALSE;
++              reg  = 0x00;
++              reg1 = 0x00;
+-      if((ivideo.disp_state & DISPTYPE_TV) && (ivideo.hasVB == HASVB_301)) {
++         }
++         setSISIDXREG(SISCR, 0x63, ~0x40, reg);
++         setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
++#endif
++
++      }
++
++      if(crt1isoff) {
++         ivideo.currentvbflags &= ~VB_DISPTYPE_CRT1;
++         ivideo.currentvbflags |= VB_SINGLE_MODE;
++         ivideo.disp_state |= DISPMODE_SINGLE;
++      } else {
++         ivideo.currentvbflags |= VB_DISPTYPE_CRT1;
++         ivideo.disp_state |= DISPTYPE_CRT1;
++         if(ivideo.currentvbflags & VB_DISPTYPE_CRT2) {
++              ivideo.currentvbflags |= VB_MIRROR_MODE;
++              ivideo.disp_state |= DISPMODE_MIRROR;
++         } else {
++              ivideo.currentvbflags |= VB_SINGLE_MODE;
++              ivideo.disp_state |= DISPMODE_SINGLE;
++         }
++      }
+-         inSISIDXREG(SISPART4, 0x01, reg);
++        andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
+-         if(reg < 0xB0) {             /* Set filter for SiS301 */
++      if((ivideo.currentvbflags & CRT2_TV) && (ivideo.vbflags & VB_301)) {  /* Set filter for SiS301 */
+               switch (ivideo.video_width) {
+                  case 320:
+-                      filter_tb = (ivideo.TV_type == TVMODE_NTSC) ? 4 : 12;
++                      filter_tb = (ivideo.vbflags & TV_NTSC) ? 4 : 12;
+                       break;
+                  case 640:
+-                      filter_tb = (ivideo.TV_type == TVMODE_NTSC) ? 5 : 13;
++                      filter_tb = (ivideo.vbflags & TV_NTSC) ? 5 : 13;
+                       break;
+                  case 720:
+-                      filter_tb = (ivideo.TV_type == TVMODE_NTSC) ? 6 : 14;
++                      filter_tb = (ivideo.vbflags & TV_NTSC) ? 6 : 14;
+                       break;
+                  case 800:
+-                      filter_tb = (ivideo.TV_type == TVMODE_NTSC) ? 7 : 15;
++                      filter_tb = (ivideo.vbflags & TV_NTSC) ? 7 : 15;
+                       break;
+                  default:
+                       filter = -1;
+@@ -3469,15 +3986,15 @@ static void sisfb_post_setmode(void)
+               orSISIDXREG(SISPART1, sisfb_CRT2_write_enable, 0x01);
+-              if(ivideo.TV_type == TVMODE_NTSC) {
++              if(ivideo.vbflags & TV_NTSC) {
+                       andSISIDXREG(SISPART2, 0x3a, 0x1f);
+-                      if (ivideo.TV_plug == TVPLUG_SVIDEO) {
++                      if (ivideo.vbflags & TV_SVIDEO) {
+                               andSISIDXREG(SISPART2, 0x30, 0xdf);
+-                      } else if (ivideo.TV_plug == TVPLUG_COMPOSITE) {
++                      } else if (ivideo.vbflags & TV_AVIDEO) {
+                               orSISIDXREG(SISPART2, 0x30, 0x20);
+@@ -3503,15 +4020,15 @@ static void sisfb_post_setmode(void)
+                               }
+                       }
+-              } else if(ivideo.TV_type == TVMODE_PAL) {
++              } else if(ivideo.vbflags & TV_PAL) {
+                       andSISIDXREG(SISPART2, 0x3A, 0x1F);
+-                      if (ivideo.TV_plug == TVPLUG_SVIDEO) {
++                      if (ivideo.vbflags & TV_SVIDEO) {
+                               andSISIDXREG(SISPART2, 0x30, 0xDF);
+-                      } else if (ivideo.TV_plug == TVPLUG_COMPOSITE) {
++                      } else if (ivideo.vbflags & TV_AVIDEO) {
+                               orSISIDXREG(SISPART2, 0x30, 0x20);
+@@ -3539,7 +4056,7 @@ static void sisfb_post_setmode(void)
+               }
+               if ((filter >= 0) && (filter <=7)) {
+-                      DPRINTK("FilterTable[%d]-%d: %02x %02x %02x %02x\n", filter_tb, filter, 
++                      DPRINTK("FilterTable[%d]-%d: %02x %02x %02x %02x\n", filter_tb, filter,
+                               sis_TV_filter[filter_tb].filter[filter][0],
+                               sis_TV_filter[filter_tb].filter[filter][1],
+                               sis_TV_filter[filter_tb].filter[filter][2],
+@@ -3550,8 +4067,6 @@ static void sisfb_post_setmode(void)
+                       outSISIDXREG(SISPART2, 0x37, (sis_TV_filter[filter_tb].filter[filter][2]));
+                       outSISIDXREG(SISPART2, 0x38, (sis_TV_filter[filter_tb].filter[filter][3]));
+               }
+-
+-           }
+         
+       }
+@@ -3567,8 +4082,10 @@ int sisfb_setup(char *options)
+ #endif        
+       ivideo.refresh_rate = 0;
++      SiS_Pr.SiS_CustomT = CUT_NONE;
++      SiS_Pr.UsePanelScaler = -1;
+-        printk(KERN_INFO "sisfb: Options %s\n", options);
++        printk(KERN_DEBUG "sisfb: Options %s\n", options);
+       if (!options || !*options)
+               return 0;
+@@ -3577,72 +4094,75 @@ int sisfb_setup(char *options)
+               if (!*this_opt) continue;
+-              if (!strncmp(this_opt, "mode:", 5)) {
+-                      sisfb_search_mode(this_opt + 5);
+-              } else if (!strncmp(this_opt, "vesa:", 5)) {
+-                      sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0));
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)                        
+-              } else if (!strcmp(this_opt, "inverse")) {
++              if (!strnicmp(this_opt, "mode:", 5)) {
++                      sisfb_search_mode(this_opt + 5, FALSE);
++              } else if (!strnicmp(this_opt, "vesa:", 5)) {
++                      sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), FALSE);
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
++              } else if (!strnicmp(this_opt, "inverse", 7)) {
+                       sisfb_inverse = 1;
+                       /* fb_invert_cmaps(); */
+-              } else if (!strncmp(this_opt, "font:", 5)) {
++              } else if (!strnicmp(this_opt, "font:", 5)) {
+                       strcpy(sis_fb_info.fontname, this_opt + 5);
+-#endif                        
+-              } else if (!strncmp(this_opt, "mode:", 5)) {
+-                      sisfb_search_mode(this_opt + 5);
+-              } else if (!strncmp(this_opt, "vesa:", 5)) {
+-                      sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0));
+-              } else if (!strncmp(this_opt, "vrate:", 6)) {
++#endif
++              } else if (!strnicmp(this_opt, "vrate:", 6)) {
+                       ivideo.refresh_rate = simple_strtoul(this_opt + 6, NULL, 0);
+-              } else if (!strncmp(this_opt, "rate:", 5)) {
++                      sisfb_parm_rate = ivideo.refresh_rate;
++              } else if (!strnicmp(this_opt, "rate:", 5)) {
+                       ivideo.refresh_rate = simple_strtoul(this_opt + 5, NULL, 0);
+-              } else if (!strncmp(this_opt, "off", 3)) {
++                      sisfb_parm_rate = ivideo.refresh_rate;
++              } else if (!strnicmp(this_opt, "off", 3)) {
+                       sisfb_off = 1;
+-              } else if (!strncmp(this_opt, "crt1off", 7)) {
++              } else if (!strnicmp(this_opt, "crt1off", 7)) {
+                       sisfb_crt1off = 1;
+-              } else if (!strncmp(this_opt, "filter:", 7)) {
++              } else if (!strnicmp(this_opt, "filter:", 7)) {
+                       filter = (int)simple_strtoul(this_opt + 7, NULL, 0);
+-              } else if (!strncmp(this_opt, "forcecrt2type:", 14)) {
++              } else if (!strnicmp(this_opt, "forcecrt2type:", 14)) {
+                       sisfb_search_crt2type(this_opt + 14);
+-              } else if (!strncmp(this_opt, "forcecrt1:", 10)) {
++              } else if (!strnicmp(this_opt, "forcecrt1:", 10)) {
+                       sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
+-                } else if (!strncmp(this_opt, "tvmode:",7)) {
++                } else if (!strnicmp(this_opt, "tvmode:",7)) {
+                       sisfb_search_tvstd(this_opt + 7);
+-                } else if (!strncmp(this_opt, "tvstandard:",11)) {
++                } else if (!strnicmp(this_opt, "tvstandard:",11)) {
+                       sisfb_search_tvstd(this_opt + 7);
+-                } else if (!strncmp(this_opt, "mem:",4)) {
++                } else if (!strnicmp(this_opt, "mem:",4)) {
+                       sisfb_mem = simple_strtoul(this_opt + 4, NULL, 0);
+-                } else if (!strncmp(this_opt, "dstn", 4)) {
+-                      enable_dstn = 1;
+-                      /* TW: DSTN overrules forcecrt2type */
+-                      sisfb_crt2type = DISPTYPE_LCD;
+-              } else if (!strncmp(this_opt, "queuemode:", 10)) {
++              } else if (!strnicmp(this_opt, "queuemode:", 10)) {
+                       sisfb_search_queuemode(this_opt + 10);
+-              } else if (!strncmp(this_opt, "pdc:", 4)) {
++              } else if (!strnicmp(this_opt, "pdc:", 4)) {
+                       sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
+                       if(sisfb_pdc & ~0x3c) {
+                          printk(KERN_INFO "sisfb: Illegal pdc parameter\n");
+                          sisfb_pdc = 0;
+                       }
+-              } else if (!strncmp(this_opt, "noaccel", 7)) {
++              } else if (!strnicmp(this_opt, "noaccel", 7)) {
+                       sisfb_accel = 0;
+-              } else if (!strncmp(this_opt, "noypan", 6)) {
++              } else if (!strnicmp(this_opt, "noypan", 6)) {
+                       sisfb_ypan = 0;
+-              } else if (!strncmp(this_opt, "userom:", 7)) {
++              } else if (!strnicmp(this_opt, "userom:", 7)) {
+                       sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
+-              } else if (!strncmp(this_opt, "useoem:", 7)) {
++              } 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)) {
++                         SiS_Pr.UsePanelScaler = temp ^ 1;
++                      }
++              } else if (!strnicmp(this_opt, "specialtiming:", 14)) {
++                      sisfb_search_specialtiming(this_opt + 14);
++              } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
++                      sisfb_search_mode(this_opt, TRUE);
+               } else {
+                       printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
+               }
+               /* TW: Acceleration only with MMIO mode */
+               if((sisfb_queuemode != -1) && (sisfb_queuemode != MMIO_CMD)) {
+-                      sisfb_ypan = 0;
+                       sisfb_accel = 0;
+               }
+-              /* TW: Panning only with acceleration */
+-              if(sisfb_accel == 0) sisfb_ypan = 0;
+       }
+       return 0;
+@@ -3661,14 +4181,14 @@ static char *sis_find_rom(void)
+         char *sis_sig_300[4] = {
+           "300", "540", "630", "730"
+         };
+-        char *sis_sig_310[7] = {
+-          "315", "315", "315", "5315", "6325", "6325", "Xabre"
++        char *sis_sig_310[9] = {
++          "315", "315", "315", "5315", "6325", "6325", "Xabre", "6330", "6330"
+         };
+       ushort sis_nums_300[4] = {
+         SIS_300, SIS_540, SIS_630, SIS_730
+       };
+-      unsigned short sis_nums_310[7] = {
+-        SIS_315PRO, SIS_315H, SIS_315, SIS_550, SIS_650, SIS_740, SIS_330
++      unsigned short sis_nums_310[9] = {
++        SIS_315PRO, SIS_315H, SIS_315, SIS_550, SIS_650, SIS_740, SIS_330, SIS_660, SIS_760
+       };
+         for(segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) {
+@@ -3705,7 +4225,7 @@ static char *sis_find_rom(void)
+                     }
+                 }
+               if(stage != 4) {
+-                   for(i = 0;(i < 7) && (stage != 4); i++) {
++                   for(i = 0;(i < 9) && (stage != 4); i++) {
+                       if(strncmp(sis_sig_310[i], rom, strlen(sis_sig_310[i])) == 0) {
+                         if(sis_nums_310[i] == ivideo.chip) {
+                              stage = 4;
+@@ -3735,7 +4255,7 @@ int __init sisfb_init(void)
+       int pdev_valid = 0;
+       u32 reg32;
+       u16 reg16;
+-      u8  reg, reg1;
++      u8  reg;
+       /* outb(0x77, 0x80); */  /* What is this? */
+@@ -3751,18 +4271,24 @@ int __init sisfb_init(void)
+       if (sisfb_off)
+               return -ENXIO;
+-      if (enable_dstn)
+-              SiS_SetEnableDstn(&SiS_Pr);
+-              
+       sisfb_registered = 0;
++      sisfb_thismonitor.datavalid = FALSE;
+       memset(&sis_fb_info, 0, sizeof(sis_fb_info));
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
++        memset(&sisfb_lastrates[0], 0, 128);
++#endif
+       
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)        
+       memset(&sis_disp, 0, sizeof(sis_disp));
+ #endif        
+-      while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,74)
++      pci_for_each_dev(pdev) {
++#else
++      while((pdev = pci_find_device(PCI_VENDOR_ID_SI, PCI_ANY_ID, pdev))) {
++#endif
+               for (b = sisdev_list; b->vendor; b++) {
+                       if ((b->vendor == pdev->vendor)
+                           && (b->device == pdev->device)) {
+@@ -3804,18 +4330,17 @@ int __init sisfb_init(void)
+               break;
+          case PCI_DEVICE_ID_SI_630_VGA:
+               {
++                      ivideo.chip = SIS_630;
+                       sisfb_set_reg4(0xCF8, 0x80000000);
+                       reg32 = sisfb_get_reg3(0xCFC);
+                       if(reg32 == 0x07301039) {
+                               ivideo.chip = SIS_730;
+-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)                               
++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
+                               strcpy(sis_fb_info.modename, "SIS 730");
+ #else
+                               strcpy(myid, "SIS 730");
+-#endif                                
+-                      } else
+-                              ivideo.chip = SIS_630;
+-
++#endif
++                      }
+                       sisvga_engine = SIS_300_VGA;
+                       sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_300 * 2;
+                       sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_300;
+@@ -3860,11 +4385,11 @@ int __init sisfb_init(void)
+                       reg32 = sisfb_get_reg3(0xCFC);
+                       if(reg32 == 0x07401039) {
+                               ivideo.chip = SIS_740;
+-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)                               
++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
+                               strcpy(sis_fb_info.modename, "SIS 740");
+ #else
+-                              strcpy(myid, "SIS 740");                                
+-#endif                                
++                              strcpy(myid, "SIS 740");
++#endif
+                       }
+                       sisvga_engine = SIS_315_VGA;
+                       sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2;
+@@ -3877,6 +4402,24 @@ int __init sisfb_init(void)
+               sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2;
+               sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315;
+               break;
++         case PCI_DEVICE_ID_SI_660_VGA:
++              {
++                      ivideo.chip = SIS_660;
++                      sisfb_set_reg4(0xCF8, 0x80000000);
++                      reg32 = sisfb_get_reg3(0xCFC);
++                      if(reg32 == 0x07601039) {
++                              ivideo.chip = SIS_760;
++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
++                              strcpy(sis_fb_info.modename, "SIS 760");
++#else
++                              strcpy(myid, "SIS 760");
++#endif
++                      }
++                      sisvga_engine = SIS_315_VGA;
++                      sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2;
++                      sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315;
++                      break;
++              }
+ #endif
+            default:
+               return -ENODEV;
+@@ -3903,29 +4446,31 @@ int __init sisfb_init(void)
+         SiS_Pr.SiS_CHOverScan = -1;
+         SiS_Pr.SiS_ChSW = FALSE;
+       SiS_Pr.SiS_UseLCDA = FALSE;
+-      SiS_Pr.UsePanelScaler = -1;
+       SiSRegInit(&SiS_Pr, (USHORT)sishw_ext.ulIOAddress);
+ #ifdef CONFIG_FB_SIS_300
+-      /* TW: Find PCI systems for Chrontel/ISA bridge manipulation */
++      /* TW: Find PCI systems for Chrontel/GPIO communication setup */
+       if(ivideo.chip == SIS_630) {
+-        int i=0;
+-          do {
+-          if(mychswtable[i].subsysVendor == ivideo.subsysvendor &&
+-             mychswtable[i].subsysCard   == ivideo.subsysdevice) {
+-              SiS_Pr.SiS_ChSW = TRUE;
+-            }
+-            i++;
+-          } while(mychswtable[i].subsysVendor != 0);
++         int i=0;
++           do {
++            if(mychswtable[i].subsysVendor == ivideo.subsysvendor &&
++               mychswtable[i].subsysCard   == ivideo.subsysdevice) {
++               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);
+       }
+ #endif
+         outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)                
+-#ifdef MODULE 
++#ifdef MODULE
+       inSISIDXREG(SISCR,0x34,reg);
+-      if(reg & 0x80) {
++      if((reg & 0x80) && (reg != 0xff)) {
+          if((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF) {
+             printk(KERN_INFO "sisfb: Cannot initialize display mode, X server is active\n");
+             return -EBUSY;
+@@ -3938,7 +4483,7 @@ int __init sisfb_init(void)
+ #ifdef CONFIG_FB_SIS_300
+       if (sisvga_engine == SIS_300_VGA) {
+-              outSISIDXREG(SISSR, 0x28, 0x37);
++              outSISIDXREG(SISSR, 0x28, 0x37);        /* Reset memory clock */
+                 outSISIDXREG(SISSR, 0x29, 0x61);
+@@ -3946,7 +4491,9 @@ int __init sisfb_init(void)
+       }
+ #endif
+ #ifdef CONFIG_FB_SIS_315
+-      if (ivideo.chip == SIS_550 || ivideo.chip == SIS_650 || ivideo.chip == SIS_740) {
++      if (ivideo.chip == SIS_550 || ivideo.chip == SIS_650 ||
++          ivideo.chip == SIS_740 || ivideo.chip == SIS_660 ||
++          ivideo.chip == SIS_760) {
+               outSISIDXREG(SISSR, 0x28, 0x5a);
+                 outSISIDXREG(SISSR, 0x29, 0x64);
+@@ -3967,6 +4514,8 @@ int __init sisfb_init(void)
+                  case SIS_550:
+                  case SIS_650:
+                  case SIS_740:
++                 case SIS_660:
++                 case SIS_760:
+                       sishw_ext.bIntegratedMMEnabled = TRUE;
+                       break;
+                  default:
+@@ -4006,13 +4555,56 @@ int __init sisfb_init(void)
+       sishw_ext.pQueryNorthBridgeSpace = &sisfb_query_north_bridge_space;
+       strcpy(sishw_ext.szVBIOSVer, "0.84");
+-      /* TW: Mode numbers for 1280x960 are different for 300 and 310/325 series */
++        /* Find systems for special custom timing */
++      if((sishw_ext.UseROM) && (SiS_Pr.SiS_CustomT == CUT_NONE)) {
++         int i=0,j;
++         unsigned char *biosver = sishw_ext.pjVirtualRomBase + 0x06;
++           unsigned char *biosdate = sishw_ext.pjVirtualRomBase + 0x2c;
++         BOOLEAN footprint;
++         unsigned long chksum = 0;
++
++           for(i=0; i<32768; i++) chksum += sishw_ext.pjVirtualRomBase[i];
++
++         i=0;
++           do {
++            if( (mycustomttable[i].chipID == ivideo.chip) &&
++                ((!strlen(mycustomttable[i].biosversion)) ||
++                 (!strncmp(mycustomttable[i].biosversion, biosver, strlen(mycustomttable[i].biosversion)))) &&
++                ((!strlen(mycustomttable[i].biosdate)) ||
++                 (!strncmp(mycustomttable[i].biosdate, biosdate, strlen(mycustomttable[i].biosdate)))) &&
++                ((!mycustomttable[i].bioschksum) ||
++                 (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(sishw_ext.pjVirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
++                              mycustomttable[i].biosFootprintData[j])
++                       footprint = FALSE;
++                 }
++               }
++               if(footprint) {
++                  SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
++                  printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
++                      mycustomttable[i].vendorName,
++                      mycustomttable[i].cardName);
++                  break;
++                 }
++            }
++              i++;
++           } while(mycustomttable[i].chipID);
++      }
++
++#ifdef CONFIG_FB_SIS_300
++      /* Mode numbers for 1280x768 are different for 300 and 315 series */
+       if(sisvga_engine == SIS_300_VGA) {
+-              sisbios_mode[MODEINDEX_1280x960].mode_no = 0x6e;
+-              sisbios_mode[MODEINDEX_1280x960+1].mode_no = 0x6f;
+-              sisbios_mode[MODEINDEX_1280x960+2].mode_no = 0x7b;
+-              sisbios_mode[MODEINDEX_1280x960+3].mode_no = 0x7b;
++              sisbios_mode[MODEINDEX_1280x768].mode_no = 0x55;
++              sisbios_mode[MODEINDEX_1280x768+1].mode_no = 0x5a;
++              sisbios_mode[MODEINDEX_1280x768+2].mode_no = 0x5b;
++              sisbios_mode[MODEINDEX_1280x768+3].mode_no = 0x5b;
+       }
++#endif
+       sishw_ext.pSR = vmalloc(sizeof(SIS_DSReg) * SR_BUFFER_SIZE);
+       if (sishw_ext.pSR == NULL) {
+@@ -4168,120 +4760,53 @@ int __init sisfb_init(void)
+       ivideo.mtrr = (unsigned int) 0;
+-      if((sisfb_mode_idx < 0) || ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF)) { 
+-
+-#ifdef CONFIG_FB_SIS_300
+-              if (sisvga_engine == SIS_300_VGA) {
+-                      sisfb_get_VB_type_300();
+-              }
+-#endif
++      ivideo.vbflags = 0;
+-#ifdef CONFIG_FB_SIS_315
+-              if (sisvga_engine == SIS_315_VGA) {
+-                      sisfb_get_VB_type_315();
+-              }
+-#endif
++      if((sisfb_mode_idx < 0) || ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF)) {
+               sishw_ext.ujVBChipID = VB_CHIP_UNKNOWN;
+               sishw_ext.Is301BDH = FALSE;
+               sishw_ext.usExternalChip = 0;
+-              switch (ivideo.hasVB) {
++              sisfb_get_VB_type();
+-              case HASVB_301:
+-                      inSISIDXREG(SISPART4, 0x01, reg);
+-                      if (reg >= 0xE0) {
+-                              sishw_ext.ujVBChipID = VB_CHIP_302LV;
+-                              printk(KERN_INFO "sisfb: SiS302LV bridge detected (revision 0x%02x)\n",reg);
+-                      } else if (reg >= 0xD0) {
+-                              sishw_ext.ujVBChipID = VB_CHIP_301LV;
+-                              printk(KERN_INFO "sisfb: SiS301LV bridge detected (revision 0x%02x)\n",reg);
+-                      } else if (reg >= 0xB0) {
+-                              sishw_ext.ujVBChipID = VB_CHIP_301B;
+-                              inSISIDXREG(SISPART4,0x23,reg1);
+-                              if(!(reg1 & 0x02)) sishw_ext.Is301BDH = TRUE;
+-                              printk(KERN_INFO "sisfb: SiS301B%s bridge detected (revision 0x%02x)\n",
+-                                      (sishw_ext.Is301BDH ? "-DH" : ""), reg);
+-                      } else {
+-                              sishw_ext.ujVBChipID = VB_CHIP_301;
+-                              printk(KERN_INFO "sisfb: SiS301 bridge detected\n");
+-                      }
+-                      break;
+-              case HASVB_302:
+-                      inSISIDXREG(SISPART4, 0x01, reg);
+-                      if (reg >= 0xE0) {
+-                              sishw_ext.ujVBChipID = VB_CHIP_302LV;
+-                              printk(KERN_INFO "sisfb: SiS302LV bridge detected (revision 0x%02x)\n",reg);
+-                      } else if (reg >= 0xD0) {
+-                              sishw_ext.ujVBChipID = VB_CHIP_301LV;
+-                              printk(KERN_INFO "sisfb: SiS302LV bridge detected (revision 0x%02x)\n",reg);
+-                      } else if (reg >= 0xB0) {
+-                              inSISIDXREG(SISPART4,0x23,reg1);
+-                              if(!(reg1 & 0x02)) sishw_ext.Is301BDH = TRUE;
+-                              sishw_ext.ujVBChipID = VB_CHIP_302B;
+-                              printk(KERN_INFO "sisfb: SiS302B%s bridge detected (revision 0x%02x)\n",
+-                                      (sishw_ext.Is301BDH ? "-DH" : ""), reg);
+-                      } else {
+-                              sishw_ext.ujVBChipID = VB_CHIP_302;
+-                              printk(KERN_INFO "sisfb: SiS302 bridge detected\n");
+-                      }
+-                      break;
+-              case HASVB_LVDS:
+-                      sishw_ext.usExternalChip = 0x1;
+-                      printk(KERN_INFO "sisfb: LVDS transmitter detected\n");
+-                      break;
+-              case HASVB_TRUMPION:
+-                      sishw_ext.usExternalChip = 0x2;
+-                      printk(KERN_INFO "sisfb: Trumpion Zurac LVDS scaler detected\n");
+-                      break;
+-              case HASVB_CHRONTEL:
+-                      sishw_ext.usExternalChip = 0x4;
+-                      printk(KERN_INFO "sisfb: Chrontel TV encoder detected\n");
+-                      break;
+-              case HASVB_LVDS_CHRONTEL:
+-                      sishw_ext.usExternalChip = 0x5;
+-                      printk(KERN_INFO "sisfb: LVDS transmitter and Chrontel TV encoder detected\n");
+-                      break;
+-              default:
+-                      printk(KERN_INFO "sisfb: No or unknown bridge type detected\n");
+-                      break;
++              if(ivideo.vbflags & VB_VIDEOBRIDGE) {
++                      sisfb_detect_VB_connect();
+               }
+-              if (ivideo.hasVB != HASVB_NONE) {
+-#ifdef CONFIG_FB_SIS_300
+-                    if (sisvga_engine == SIS_300_VGA) {
+-                              sisfb_detect_VB_connect_300();
+-                      }
+-#endif
+-#ifdef CONFIG_FB_SIS_315
+-                    if (sisvga_engine == SIS_315_VGA) {
+-                              sisfb_detect_VB_connect_315();
+-                      }
+-#endif
+-              }
++              ivideo.currentvbflags = ivideo.vbflags & VB_VIDEOBRIDGE;
+-              if (ivideo.disp_state & DISPTYPE_DISP2) {
+-                      if (sisfb_crt1off)
+-                              ivideo.disp_state |= DISPMODE_SINGLE;
+-                      else
+-                              ivideo.disp_state |= (DISPMODE_MIRROR | DISPTYPE_CRT1);
+-              } else {
+-                      ivideo.disp_state = DISPMODE_SINGLE | DISPTYPE_CRT1;
++              if(ivideo.vbflags & VB_VIDEOBRIDGE) {
++                 if(sisfb_crt2type != -1) {
++                    if((sisfb_crt2type == CRT2_LCD) && (ivideo.vbflags & CRT2_LCD)) {
++                       ivideo.currentvbflags |= CRT2_LCD;
++                    } else if(sisfb_crt2type != CRT2_LCD) {
++                       ivideo.currentvbflags |= sisfb_crt2type;
++                    }
++                 } else {
++                    /* Chrontel 700x TV detection often unreliable, therefore use a
++                     * different default order on such machines
++                     */
++                    if((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;
++                    }
++                 }
+               }
+-              if (ivideo.disp_state & DISPTYPE_LCD) {
+-                  if (!enable_dstn) {
+-                      inSISIDXREG(SISCR, IND_SIS_LCD_PANEL, reg);
+-                      reg &= 0x0f;
+-                      if (sisvga_engine == SIS_300_VGA) {
+-                          sishw_ext.ulCRT2LCDType = sis300paneltype[reg];
+-                      } else {
+-                          sishw_ext.ulCRT2LCDType = sis310paneltype[reg];
+-                      }
+-                  } else {
+-                      /* TW: FSTN/DSTN */
+-                      sishw_ext.ulCRT2LCDType = LCD_320x480;
+-                  }
++              if(ivideo.vbflags & CRT2_LCD) {
++                 inSISIDXREG(SISCR, IND_SIS_LCD_PANEL, reg);
++                 reg &= 0x0f;
++                 if(sisvga_engine == SIS_300_VGA) {
++                    sishw_ext.ulCRT2LCDType = sis300paneltype[reg];
++                 } else {
++                    sishw_ext.ulCRT2LCDType = sis310paneltype[reg];
++                 }
+               }
+               
+               sisfb_detectedpdc = 0;
+@@ -4289,9 +4814,7 @@ int __init sisfb_init(void)
+ #ifdef CONFIG_FB_SIS_300
+                 /* TW: Save the current PanelDelayCompensation if the LCD is currently used */
+               if(sisvga_engine == SIS_300_VGA) {
+-                if((sishw_ext.usExternalChip == 0x01) ||   /* LVDS */
+-                   (sishw_ext.usExternalChip == 0x05) ||   /* LVDS+Chrontel */
+-                   (sishw_ext.Is301BDH)) {                 /* 301B-DH */
++                if(ivideo.vbflags & (VB_LVDS | VB_30xBDH)) {
+                      int tmp;
+                      inSISIDXREG(SISCR,0x30,tmp);
+                      if(tmp & 0x20) {
+@@ -4320,54 +4843,57 @@ int __init sisfb_init(void)
+ #ifdef CONFIG_FB_SIS_315
+                 /* TW: Try to find about LCDA */
+               if(sisvga_engine == SIS_315_VGA) {
+-                if((sishw_ext.ujVBChipID == VB_CHIP_302B) ||
+-                   (sishw_ext.ujVBChipID == VB_CHIP_301LV) ||
+-                   (sishw_ext.ujVBChipID == VB_CHIP_302LV)) {
+-                     int tmp;
+-                     inSISIDXREG(SISCR,0x34,tmp);
+-                     if(tmp <= 0x13) {        
+-                        /* Currently on LCDA? (Some BIOSes leave CR38) */
+-                        inSISIDXREG(SISCR,0x38,tmp);
+-                        if((tmp & 0x03) == 0x03) {
+-                           SiS_Pr.SiS_UseLCDA = TRUE;
+-                        } else {
+-                           /* Currently on LCDA? (Some newer BIOSes set D0 in CR35) */
+-                           inSISIDXREG(SISCR,0x35,tmp);
+-                           if(tmp & 0x01) {
+-                              SiS_Pr.SiS_UseLCDA = TRUE;
+-                           } else {
+-                              /* Currently on LCD? If so, we can find out 
+-                                 by peeking the mode register 
+-                               */
+-                              inSISIDXREG(SISCR,0x30,tmp);
+-                              if(tmp & 0x20) {
+-                                 inSISIDXREG(SISPART1,0x13,tmp);
+-                                 if(tmp & 0x04) {
+-                                    SiS_Pr.SiS_UseLCDA = TRUE;
+-                                 }
+-                              }
+-                           }
+-                        }
+-                     } 
+-                     if(SiS_Pr.SiS_UseLCDA) {
+-                        sisfb_detectedlcda = 0x03;
+-                        printk(KERN_INFO
+-                               "sisfb: Bridge uses LCDA for low resolution and text modes\n");
+-                     }
++                 if(ivideo.vbflags & (VB_302B | VB_301LV | VB_302LV)) {
++                    int tmp;
++                    inSISIDXREG(SISCR,0x34,tmp);
++                    if((tmp <= 0x13) || (tmp == 0xff)) {
++                       /* Currently on LCDA? (Some BIOSes leave CR38) */
++                       inSISIDXREG(SISCR,0x38,tmp);
++                       if((tmp & 0x03) == 0x03)  SiS_Pr.SiS_UseLCDA = TRUE;
++                       else {
++                          /* Currently on LCDA? (Some newer BIOSes set D0 in CR35) */
++                          inSISIDXREG(SISCR,0x35,tmp);
++                          if(tmp & 0x01) SiS_Pr.SiS_UseLCDA = TRUE;
++                          else {
++                             /* Currently on LCD? If so, we can find out
++                              * by peeking the mode register
++                              */
++                             inSISIDXREG(SISCR,0x30,tmp);
++                             if(tmp & 0x20) {
++                                inSISIDXREG(SISPART1,0x13,tmp);
++                                if(tmp & 0x04) SiS_Pr.SiS_UseLCDA = TRUE;
++                             }
++                          }
++                       }
++                    }
++                    if(SiS_Pr.SiS_UseLCDA) {
++                       sisfb_detectedlcda = 0x03;
++                       printk(KERN_DEBUG
++                              "sisfb: Bridge uses LCDA for low resolution and text modes\n");
++                    }
+                 }
+               }
+ #endif
+ #endif
++              if (!sisfb_crt1off) {
++                      sisfb_handle_ddc(&sisfb_thismonitor, 0);
++              } else {
++                      if ((ivideo.vbflags & (VB_301|VB_301B|VB_302B)) &&
++                          (ivideo.vbflags & (CRT2_VGA | CRT2_LCD))) {
++                              sisfb_handle_ddc(&sisfb_thismonitor, 1);
++                      }
++              }
++
+               if (sisfb_mode_idx >= 0)
+-                      sisfb_mode_idx = sisfb_validate_mode(sisfb_mode_idx);
++                      sisfb_mode_idx = sisfb_validate_mode(sisfb_mode_idx, ivideo.currentvbflags);
+               if (sisfb_mode_idx < 0) {
+-                      switch (ivideo.disp_state & DISPTYPE_DISP2) {
+-                         case DISPTYPE_LCD:
++                      switch (ivideo.currentvbflags & VB_DISPTYPE_DISP2) {
++                         case CRT2_LCD:
+                               sisfb_mode_idx = DEFAULT_LCDMODE;
+                               break;
+-                         case DISPTYPE_TV:
++                         case CRT2_TV:
+                               sisfb_mode_idx = DEFAULT_TVMODE;
+                               break;
+                          default:
+@@ -4379,39 +4905,27 @@ int __init sisfb_init(void)
+               sisfb_mode_no = sisbios_mode[sisfb_mode_idx].mode_no;
+               if (ivideo.refresh_rate != 0)
+-                      sisfb_search_refresh_rate(ivideo.refresh_rate);
++                      sisfb_search_refresh_rate(ivideo.refresh_rate, sisfb_mode_idx);
+               if (sisfb_rate_idx == 0) {
+                       sisfb_rate_idx = sisbios_mode[sisfb_mode_idx].rate_idx;
+                       ivideo.refresh_rate = 60;
+               }
++              if (sisfb_thismonitor.datavalid) {
++                      if(!sisfb_verify_rate(&sisfb_thismonitor, sisfb_mode_idx,
++                                            sisfb_rate_idx, ivideo.refresh_rate)) {
++                              printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
++                      }
++              }
++
+               ivideo.video_bpp = sisbios_mode[sisfb_mode_idx].bpp;
+               ivideo.video_vwidth = ivideo.video_width = sisbios_mode[sisfb_mode_idx].xres;
+               ivideo.video_vheight = ivideo.video_height = sisbios_mode[sisfb_mode_idx].yres;
+               ivideo.org_x = ivideo.org_y = 0;
+               ivideo.video_linelength = ivideo.video_width * (ivideo.video_bpp >> 3);
+-              switch(ivideo.video_bpp) {
+-              case 8:
+-                      ivideo.DstColor = 0x0000;
+-                      ivideo.SiS310_AccelDepth = 0x00000000;
+-                      ivideo.video_cmap_len = 256;
+-                      break;
+-              case 16:
+-                      ivideo.DstColor = 0x8000;
+-                      ivideo.SiS310_AccelDepth = 0x00010000;
+-                      ivideo.video_cmap_len = 16;
+-                      break;
+-              case 32:
+-                      ivideo.DstColor = 0xC000;
+-                      ivideo.SiS310_AccelDepth = 0x00020000;
+-                      ivideo.video_cmap_len = 16;
+-                      break;
+-              default:
+-                      ivideo.video_cmap_len = 16;
+-                      printk(KERN_INFO "sisfb: Unsupported depth %d", ivideo.video_bpp);
+-                      break;
+-              }
++
++              sisfb_set_vparms();
+               
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)        
+@@ -4424,27 +4938,49 @@ int __init sisfb_init(void)
+               sisfb_pre_setmode();
+               if (SiSSetMode(&SiS_Pr, &sishw_ext, sisfb_mode_no) == 0) {
+-                      printk(KERN_ERR "sisfb: Setting mode[0x%x] failed, using default mode\n", 
++                      printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n",
+                               sisfb_mode_no);
+-                      return -1;
++                      vfree(sishw_ext.pSR);
++                      vfree(sishw_ext.pCR);
++                      release_mem_region(ivideo.video_base, ivideo.video_size);
++                      release_mem_region(ivideo.mmio_base, sisfb_mmio_size);
++                      return -EINVAL;
+               }
+               outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
+               sisfb_post_setmode();
++              ivideo.accel = 0;
++              if(sisfb_accel) {
++                 ivideo.accel = -1;
++                 default_var.accel_flags |= FB_ACCELF_TEXT;
++                 sisfb_initaccel();
++              }
++
+               sisfb_crtc_to_var(&default_var);
+               
++              sis_fb_info.node = -1;
++              sis_fb_info.flags = FBINFO_FLAG_DEFAULT;
++              sis_fb_info.blank = &sisfb_blank;
++              sis_fb_info.fbops = &sisfb_ops;
++              sis_fb_info.switch_con = &sisfb_switch;
++              sis_fb_info.updatevar = &sisfb_update_var;
++              sis_fb_info.changevar = NULL;
++              sis_fb_info.disp = &sis_disp;
++
++              sisfb_set_disp(-1, &default_var, &sis_fb_info);
++
+ #else         /* --------- For 2.5: 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.refresh_rate);
+-                      
++
+               default_var.xres = default_var.xres_virtual = ivideo.video_width;
+               default_var.yres = default_var.yres_virtual = ivideo.video_height;
+               default_var.bits_per_pixel = ivideo.video_bpp;
+-              
++
+               sisfb_bpp_to_var(&default_var);
+               
+               default_var.pixclock = (u32) (1E12 /
+@@ -4457,28 +4993,10 @@ int __init sisfb_init(void)
+                        &default_var.upper_margin, &default_var.lower_margin,
+                        &default_var.hsync_len, &default_var.vsync_len,
+                        &default_var.sync, &default_var.vmode)) {
+-                       
+-                 if((default_var.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+-                    default_var.yres <<= 1;
+-                    default_var.yres_virtual <<= 1;
+-                 } else if((default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
+-                    default_var.pixclock >>= 1;
+-                    default_var.yres >>= 1;
+-                    default_var.yres_virtual >>= 1;
+-                 }
+-                 
++                      if((default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
++                              default_var.pixclock <<= 1;
++                      }
+               }
+-#ifdef SISFB_PAN
+-              if(sisfb_ypan) {
+-                      default_var.yres_virtual = 
+-                              ivideo.heapstart / (default_var.xres * (default_var.bits_per_pixel >> 3));
+-                      if(default_var.yres_virtual <= default_var.yres) {
+-                              default_var.yres_virtual = default_var.yres;
+-                      }
+-              } 
+-#endif
+-              
+-#endif
+               ivideo.accel = 0;
+               if(sisfb_accel) {
+@@ -4487,20 +5005,14 @@ int __init sisfb_init(void)
+                  sisfb_initaccel();
+               }
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)                /* ---- 2.4 series init ---- */
+-              sis_fb_info.node = -1;
+-              sis_fb_info.flags = FBINFO_FLAG_DEFAULT;
+-              sis_fb_info.blank = &sisfb_blank;
+-              sis_fb_info.fbops = &sisfb_ops;
+-              sis_fb_info.switch_con = &sisfb_switch;
+-              sis_fb_info.updatevar = &sisfb_update_var;
+-              sis_fb_info.changevar = NULL;
+-              sis_fb_info.disp = &sis_disp;
+-                      
+-              sisfb_set_disp(-1, &default_var, &sis_fb_info);
+-#endif
++              if(sisfb_ypan) {
++                      default_var.yres_virtual =
++                              ivideo.heapstart / (default_var.xres * (default_var.bits_per_pixel >> 3));
++                      if(default_var.yres_virtual <= default_var.yres) {
++                              default_var.yres_virtual = default_var.yres;
++                      }
++              }
+-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)               /* ---- 2.5 series init ---- */
+               sis_fb_info.flags = FBINFO_FLAG_DEFAULT;
+               sis_fb_info.var = default_var;
+               sis_fb_info.fix = sisfb_fix;
+@@ -4513,6 +5025,8 @@ int __init sisfb_init(void)
+               fb_alloc_cmap(&sis_fb_info.cmap, 256 , 0);
+ #endif
++              printk(KERN_INFO "sisfb: Initial vbflags 0x%lx\n", ivideo.vbflags);
++
+ #ifdef CONFIG_MTRR
+               ivideo.mtrr = mtrr_add((unsigned int) ivideo.video_base,
+                               (unsigned int) ivideo.video_size,
+@@ -4520,20 +5034,28 @@ int __init sisfb_init(void)
+               if(ivideo.mtrr) {
+                       printk(KERN_INFO "sisfb: Added MTRRs\n");
+               }
++
+ #endif
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+               vc_resize_con(1, 1, 0);
+ #endif
+-              TWDEBUG("Before calling register_framebuffer");
+-              
+-              if(register_framebuffer(&sis_fb_info) < 0)
++              if(register_framebuffer(&sis_fb_info) < 0) {
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
++                      vfree(sishw_ext.pSR);
++                      vfree(sishw_ext.pCR);
++                      release_mem_region(ivideo.video_base, ivideo.video_size);
++                      release_mem_region(ivideo.mmio_base, sisfb_mmio_size);
++#endif
++                      printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
+                       return -EINVAL;
+-                      
++              }
++
+               sisfb_registered = 1;                   
+               printk(KERN_INFO "sisfb: Installed SISFB_GET_INFO ioctl (%x)\n", SISFB_GET_INFO);
++              printk(KERN_INFO "sisfb: Installed SISFB_GET_VBRSTATUS ioctl (%x)\n", SISFB_GET_VBRSTATUS);
+               
+               printk(KERN_INFO "sisfb: 2D acceleration is %s, scrolling mode %s\n",
+                    sisfb_accel ? "enabled" : "disabled",
+@@ -4547,9 +5069,11 @@ int __init sisfb_init(void)
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+               printk(KERN_INFO "fb%d: %s frame buffer device, Version %d.%d.%02d\n",
+-                      sis_fb_info.node, myid, VER_MAJOR, VER_MINOR, VER_LEVEL);                            
++                      sis_fb_info.node, myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
+ #endif
++              printk(KERN_INFO "sisfb: (C) 2001-2003 Thomas Winischhofer. All rights reserved.\n");
++
+       }       /* TW: if mode = "none" */
+       return 0;
+ }
+@@ -4562,7 +5086,6 @@ static int          vesa = -1;
+ static unsigned int rate = 0;
+ static unsigned int crt1off = 1;
+ static unsigned int mem = 0;
+-static unsigned int dstn = 0;
+ static char         *forcecrt2type = NULL;
+ static int          forcecrt1 = -1;
+ static char         *queuemode = NULL;
+@@ -4575,25 +5098,33 @@ static int          inverse = 0;
+ static int          userom = 1;
+ static int          useoem = -1;
+ static char         *tvstandard = NULL;
++static int        nocrt2rate = 0;
++static int          scalelcd = -1;
++static char       *specialtiming = NULL;
+-MODULE_DESCRIPTION("SiS 300/540/630/730/315/550/650/740/330 framebuffer driver");
++MODULE_DESCRIPTION("SiS 300/540/630/730/315/550/650/740/330/660/760 framebuffer driver");
+ MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("SiS; Thomas Winischhofer <thomas@winischhofer.net>; Various others");
++MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>; SiS; Various others");
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+ MODULE_PARM(mode, "s");
+ MODULE_PARM_DESC(mode,
+        "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
+-         "800x600x16 (default: none if sisfb is a module; this leaves the\n"
+-       "console untouched and the driver will only do the video memory\n"
+-       "management for eg. DRM/DRI; 800x600x8 if sisfb is in the kernel)");
++         "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)");
+ #endif
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)        
+ MODULE_PARM(mode, "s");
+ MODULE_PARM_DESC(mode,
+-       "\nSelects the desired default display mode in the format [X]x[Y]x[Depth],\n"
+-         "eg. 1024x768x16 (default: 800x600x8)");
+-#endif         
++       "\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)");
++#endif
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+ MODULE_PARM(vesa, "i");
+@@ -4603,17 +5134,18 @@ MODULE_PARM_DESC(vesa,
+        "and the driver will only do the video memory management for eg. DRM/DRI;\n"
+        "0x0103 if sisfb is in the kernel)");
+ #endif
+-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)        
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+ MODULE_PARM(vesa, "i");
+ MODULE_PARM_DESC(vesa,
+        "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
+          "0x117 (default: 0x0103)");
+-#endif         
++#endif
+ MODULE_PARM(rate, "i");
+ MODULE_PARM_DESC(rate,
+       "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
+-      "(default: 60)");
++        "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
++        "will be ignored (default: 60)");
+ MODULE_PARM(crt1off,   "i");
+ MODULE_PARM_DESC(crt1off,
+@@ -4624,14 +5156,9 @@ 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])");
+-MODULE_PARM(dstn,   "i");
+-MODULE_PARM_DESC(dstn,
+-      "\nSelects DSTN/FSTN display mode for SiS550. This sets CRT2 type to LCD and\n"
+-        "overrides forcecrt2type setting. (1=ON, 0=OFF) (default: 0)");
+-
+ MODULE_PARM(queuemode,   "s");
+ MODULE_PARM_DESC(queuemode,
+-      "\nSelects the queue mode on 315/550/650/740/330. Possible choices are AGP, VRAM or\n"
++      "\nSelects the queue mode on 315/550/650/740/330/660. Possible choices are AGP, VRAM,\n"
+         "MMIO. AGP is only available if the kernel has AGP support. The queue mode is\n"
+         "important to programs using the 2D/3D accelerator of the SiS chip. The modes\n"
+         "require a totally different way of programming the engines. If any mode than\n"
+@@ -4642,11 +5169,12 @@ MODULE_PARM_DESC(queuemode,
+ MODULE_PARM(mem,    "i");
+ 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. The default depends on the amount\n"
+-        "of video RAM available. If 8MB of video RAM or less is available, the heap\n"
+-        "starts at 4096KB, if between 8 and 16MB are available at 8192KB, otherwise\n"
+-        "at 12288KB. The value is to be specified without 'KB' and should match\n"
+-        "the MaxXFBMem setting for XFree 4.x (x>=2).");
++        "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 is 1MB by default. The\n"
++        "value is to be specified without 'KB' and should match the MaxXFBMem setting for\n"
++        "XFree 4.x (x>=2).");
+ MODULE_PARM(forcecrt2type, "s");
+ MODULE_PARM_DESC(forcecrt2type,
+@@ -4673,56 +5201,76 @@ MODULE_PARM_DESC(pdc,
+ MODULE_PARM(noaccel, "i");
+ MODULE_PARM_DESC(noaccel,
+         "\nIf set to anything other than 0, 2D acceleration and y-panning will be\n"
+-      "disabled. (default: 0)");
++        "disabled. (default: 0)");
+ MODULE_PARM(noypan, "i");
+ 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. This required 2D acceleration, so\n"
+-      "if the option noaccel is set, y-panning will be disabled. (default: 0)");
++        "will be performed by redrawing the screen. (default: 0)");
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)        
+ MODULE_PARM(inverse, "i");
+ MODULE_PARM_DESC(inverse,
+         "\nSetting this to anything but 0 should invert the display colors, but this\n"
+-      "does not seem to work. (default: 0)");
++        "does not seem to work. (default: 0)");
+ #endif        
+ MODULE_PARM(userom, "i");
+ MODULE_PARM_DESC(userom,
+         "\nSetting this to 0 keeps sisfb from using the video BIOS data which is needed\n"
+-      "for some LCD and TV setup. (default: 1)");
++        "for some LCD and TV setup. (default: 1)");
+ MODULE_PARM(useoem, "i");
+ MODULE_PARM_DESC(useoem,
+         "\nSetting this to 0 keeps sisfb from using its internel OEM data for some LCD\n"
+-      "panels and TV connector types. (default: auto)");
++        "panels and TV connector types. (default: [auto])");
+ MODULE_PARM(tvstandard, "s");
+ MODULE_PARM_DESC(tvstandard,
+       "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
+-      "pal and ntsc. (default: auto)");
++        "pal and ntsc. (default: [auto])");
++
++MODULE_PARM(nocrt2rate, "i");
++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)");
++
++MODULE_PARM(scalelcd, "i");
++MODULE_PARM_DESC(scalelcd,
++      "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
++        "native resolution. Setting it to 0 will disable scaling; if the panel can scale\n"
++        "by itself, it will probably do this, otherwise you will see a black bar around\n"
++        "the screen image. Default: [autodetect if panel can scale]");
++
++MODULE_PARM(specialtiming, "s");
+ int init_module(void)
+ {
+       int err;
+-      
++
++      SiS_Pr.UsePanelScaler = -1;
++      SiS_Pr.SiS_CustomT = CUT_NONE;
++
++      ivideo.refresh_rate = sisfb_parm_rate = rate;
++
++      if((scalelcd == 0) || (scalelcd == 1)) {
++         SiS_Pr.UsePanelScaler = scalelcd ^ 1;
++      }
++
+       if(mode)
+-              sisfb_search_mode(mode);
++              sisfb_search_mode(mode, FALSE);
+       else if(vesa != -1)
+-              sisfb_search_vesamode(vesa);
+-      else  
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)        
++              sisfb_search_vesamode(vesa, FALSE);
++      else
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+               /* For 2.4, set mode=none if no mode is given  */
+               sisfb_mode_idx = MODE_INDEX_NONE;
+ #endif
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+-              /* For 2.5, we don't need this "mode=none" stuff anymore */     
++              /* For 2.5, we don't need this "mode=none" stuff anymore */
+               sisfb_mode_idx = DEFAULT_MODE;
+ #endif
+-      ivideo.refresh_rate = rate;
+-
+       if(forcecrt2type)
+               sisfb_search_crt2type(forcecrt2type);
+@@ -4745,9 +5293,6 @@ int init_module(void)
+       if(noypan == 1)       sisfb_ypan = 0;
+       else if(noypan == 0)  sisfb_ypan = 1;
+-
+-      /* TW: Panning only with acceleration */
+-      if(sisfb_accel == 0)  sisfb_ypan = 0;
+       
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+       if(inverse)           sisfb_inverse = 1;
+@@ -4759,17 +5304,11 @@ int init_module(void)
+       sisfb_useoem = useoem;
+-      enable_dstn = dstn;
+-
+-      /* TW: DSTN overrules forcecrt2type */
+-      if (enable_dstn)      sisfb_crt2type = DISPTYPE_LCD;
+-
+       if (queuemode)        sisfb_search_queuemode(queuemode);
+       
+       /* TW: If other queuemode than MMIO, disable 2D accel and ypan */
+       if((sisfb_queuemode != -1) && (sisfb_queuemode != MMIO_CMD)) {
+               sisfb_accel = 0;
+-              sisfb_ypan = 0;
+       }
+         if(pdc) {
+@@ -4778,6 +5317,11 @@ int init_module(void)
+          }
+       }
++      sisfb_nocrt2rate = nocrt2rate;
++
++      if(specialtiming)
++              sisfb_search_specialtiming(specialtiming);
++
+       if((err = sisfb_init()) < 0) return err;
+       return 0;
+@@ -4788,7 +5332,7 @@ void cleanup_module(void)
+       /* TW: Release mem regions */
+       release_mem_region(ivideo.video_base, ivideo.video_size);
+       release_mem_region(ivideo.mmio_base, sisfb_mmio_size);
+-      
++
+ #ifdef CONFIG_MTRR
+       /* TW: Release MTRR region */
+       if(ivideo.mtrr) {
+@@ -4802,11 +5346,17 @@ void cleanup_module(void)
+       if(sisfb_registered) {
+               unregister_framebuffer(&sis_fb_info);
+       }
+-      
++
+       if(sishw_ext.pSR) vfree(sishw_ext.pSR);
+       if(sishw_ext.pCR) vfree(sishw_ext.pCR);
+       
+-      /* TODO: Restore the initial mode */
++      /* TODO: Restore the initial mode
++       * This sounds easy but is as good as impossible
++       * on many machines with SiS chip and video bridge
++       * since text modes are always set up differently
++       * from machine to machine. Depends on the type
++       * of integration between chipset and bridge.
++       */
+       
+       printk(KERN_INFO "sisfb: Module unloaded\n");
+ }
+--- linux-2.6.0-test6/drivers/video/sis/sis_main.h     2003-06-14 12:18:04.000000000 -0700
++++ 25/drivers/video/sis/sis_main.h    2003-10-05 00:34:22.000000000 -0700
+@@ -1,8 +1,6 @@
+ #ifndef _SISFB_MAIN
+ #define _SISFB_MAIN
+-/* Comments and changes marked with "TW" by Thomas Winischhofer <thomas@winischhofer.net> */
+-
+ #include "vstruct.h"
+ /* ------------------- Constant Definitions ------------------------- */
+@@ -14,11 +12,11 @@
+ #define VER_MAJOR                 1
+ #define VER_MINOR                 6
+-#define VER_LEVEL                 1
++#define VER_LEVEL                 13
+ #include "sis.h"
+-/* TW: To be included in pci_ids.h */
++/* To be included in pci_ids.h */
+ #ifndef PCI_DEVICE_ID_SI_650_VGA
+ #define PCI_DEVICE_ID_SI_650_VGA  0x6325
+ #endif
+@@ -31,13 +29,22 @@
+ #ifndef PCI_DEVICE_ID_SI_330
+ #define PCI_DEVICE_ID_SI_330      0x0330
+ #endif
++#ifndef PCI_DEVICE_ID_SI_660
++#define PCI_DEVICE_ID_SI_660      0x0660
++#endif
++#ifndef PCI_DEVICE_ID_SI_660_VGA
++#define PCI_DEVICE_ID_SI_660_VGA  0x6330
++#endif
++#ifndef PCI_DEVICE_ID_SI_760
++#define PCI_DEVICE_ID_SI_760      0x0760
++#endif
+ /* To be included in fb.h */
+ #ifndef FB_ACCEL_SIS_GLAMOUR_2
+ #define FB_ACCEL_SIS_GLAMOUR_2  40    /* SiS 315, 650, 740            */
+ #endif
+ #ifndef FB_ACCEL_SIS_XABRE
+-#define FB_ACCEL_SIS_XABRE      41    /* SiS 330 ("Xabre")            */
++#define FB_ACCEL_SIS_XABRE      41    /* SiS 330, 660, 760 ("Xabre")  */
+ #endif
+ #define MAX_ROM_SCAN              0x10000
+@@ -53,13 +60,12 @@
+ #define TURBO_QUEUE_AREA_SIZE     0x80000 /* 512K */
+ #endif
+-/* For 315 series */
++/* For 315/Xabre series */
+ #ifdef CONFIG_FB_SIS_315
+ #define COMMAND_QUEUE_AREA_SIZE   0x80000 /* 512K */
+ #define COMMAND_QUEUE_THRESHOLD   0x1F
+ #endif
+-/* TW */
+ #define HW_CURSOR_AREA_SIZE_315   0x4000  /* 16K */
+ #define HW_CURSOR_AREA_SIZE_300   0x1000  /* 4K */
+@@ -283,48 +289,46 @@
+ /* Fbcon variables */
+ static struct fb_info sis_fb_info;
+-static int    video_type = FB_TYPE_PACKED_PIXELS;
+-
+ static struct fb_var_screeninfo default_var = {
+-      .xres           = 0,
+-      .yres           = 0,
+-      .xres_virtual   = 0,
+-      .yres_virtual   = 0,
+-      .xoffset        = 0,
+-      .yoffset        = 0,
+-      .bits_per_pixel = 0,
+-      .grayscale      = 0,
+-      .red            = {0, 8, 0},
+-      .green          = {0, 8, 0},
+-      .blue           = {0, 8, 0},
+-      .transp         = {0, 0, 0},
+-      .nonstd         = 0,
+-      .activate       = FB_ACTIVATE_NOW,
+-      .height         = -1,
+-      .width          = -1,
+-      .accel_flags    = 0,
+-      .pixclock       = 0,
+-      .left_margin    = 0,
+-      .right_margin   = 0,
+-      .upper_margin   = 0,
+-      .lower_margin   = 0,
+-      .hsync_len      = 0,
+-      .vsync_len      = 0,
+-      .sync           = 0,
+-      .vmode          = FB_VMODE_NONINTERLACED,
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)        
+-      .reserved       = {0, 0, 0, 0, 0, 0}
+-#endif        
++      .xres            = 0,
++      .yres            = 0,
++      .xres_virtual    = 0,
++      .yres_virtual    = 0,
++      .xoffset         = 0,
++      .yoffset         = 0,
++      .bits_per_pixel  = 0,
++      .grayscale       = 0,
++      .red             = {0, 8, 0},
++      .green           = {0, 8, 0},
++      .blue            = {0, 8, 0},
++      .transp          = {0, 0, 0},
++      .nonstd          = 0,
++      .activate        = FB_ACTIVATE_NOW,
++      .height          = -1,
++      .width           = -1,
++      .accel_flags     = 0,
++      .pixclock        = 0,
++      .left_margin     = 0,
++      .right_margin    = 0,
++      .upper_margin    = 0,
++      .lower_margin    = 0,
++      .hsync_len       = 0,
++      .vsync_len       = 0,
++      .sync            = 0,
++      .vmode           = FB_VMODE_NONINTERLACED,
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
++      .reserved        = {0, 0, 0, 0, 0, 0}
++#endif
+ };
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+ static struct fb_fix_screeninfo sisfb_fix = {
+       .id             = "SiS",
+       .type           = FB_TYPE_PACKED_PIXELS,
+-      .xpanstep       = 1,
++      .xpanstep       = 0,
+       .ypanstep       = 1,
+ };
+-static char myid[20];
++static char myid[40];
+ static u32 pseudo_palette[17];
+ #endif
+@@ -347,26 +351,24 @@ static union {
+ } sis_fbcon_cmap;
+ static int sisfb_inverse = 0;
++static int currcon = 0;
+ #endif
+-/* display status */
++/* global flags */
+ static int sisfb_off = 0;
+ static int sisfb_crt1off = 0;
+ static int sisfb_forcecrt1 = -1;
+ static int sisvga_enabled = 0;
+ static int sisfb_userom = 1;
+ static int sisfb_useoem = -1;
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+-static int currcon = 0;
+-#endif
+-
+-/* global flags */
+-static int sisfb_registered;
+-static int sisfb_tvmode = 0;
++static int sisfb_parm_rate = -1;
++static int sisfb_registered = 0;
+ static int sisfb_mem = 0;
+ static int sisfb_pdc = 0;
+-static int enable_dstn = 0;
+ static int sisfb_ypan = -1;
++static int sisfb_nocrt2rate = 0;
++static int sisfb_dstn = 0;
++static int sisfb_fstn = 0;
+ VGA_ENGINE sisvga_engine = UNKNOWN_VGA;
+ int      sisfb_accel = -1;
+@@ -375,22 +377,22 @@ int         sisfb_accel = -1;
+ static int sisfb_hwcursor_size = 0;
+ static int sisfb_CRT2_write_enable = 0;
+-int sisfb_crt2type  = -1;     /* TW: CRT2 type (for overriding autodetection) */
+-int sisfb_tvplug    = -1;     /* PR: Tv plug type (for overriding autodetection) */
++int sisfb_crt2type  = -1;     /* CRT2 type (for overriding autodetection) */
++int sisfb_tvplug    = -1;     /* Tv plug type (for overriding autodetection) */
+-int sisfb_queuemode = -1;     /* TW: Use MMIO queue mode by default (310/325 series only) */
++int sisfb_queuemode = -1;     /* Use MMIO queue mode by default (315 series only) */
+ unsigned char sisfb_detectedpdc = 0;
+ unsigned char sisfb_detectedlcda = 0xff;
+-/* data for sis components */
++/* data for sis hardware ("par") */
+ struct video_info ivideo;
+-/* TW: For ioctl SISFB_GET_INFO */
++/* For ioctl SISFB_GET_INFO */
+ sisfb_info sisfbinfo;
+-/* TW: Hardware extension; contains data on hardware */
++/* Hardware extension; contains data on hardware */
+ HW_DEVICE_EXTENSION sishw_ext = {
+       NULL, NULL, FALSE, NULL, NULL,
+       0, 0, 0, 0, 0, 0, 0, 0, 0,
+@@ -399,10 +401,10 @@ HW_DEVICE_EXTENSION sishw_ext = {
+       0
+ };
+-/* TW: SiS private structure */
++/* SiS private structure */
+ SiS_Private  SiS_Pr;
+-/* card parameters */
++/* Card parameters */
+ static unsigned long sisfb_mmio_size = 0;
+ static u8            sisfb_caps = 0;
+@@ -412,7 +414,7 @@ typedef enum _SIS_CMDTYPE {
+       VM_CMD_QUEUE,
+ } SIS_CMDTYPE;
+-/* Supported SiS Chips list */
++/* List of supported chips */
+ static struct board {
+       u16 vendor, device;
+       const char *name;
+@@ -424,16 +426,17 @@ static struct board {
+       {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315,     "SIS 315"},
+       {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315PRO,  "SIS 315PRO"},
+       {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_550_VGA, "SIS 550 VGA"},
+-      {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_650_VGA, "SIS 650/M650/651/740 VGA"},
++      {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_650_VGA, "SIS 650/M650/651/M652/740 VGA"},
+       {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_330,     "SIS 330"},
++      {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_660_VGA, "SIS 660/M660/760/M760 VGA"},
+       {0, 0, NULL}
+ };
+ #define MD_SIS300 1
+ #define MD_SIS315 2
+-/* mode table */
+-/* NOT const - will be patched for 1280x960 mode number chaos reasons */
++/* Mode table */
++/* NOT const - will be patched for 1280x768 mode number chaos reasons */
+ struct _sisbios_mode {
+       char name[15];
+       u8 mode_no;
+@@ -447,14 +450,33 @@ struct _sisbios_mode {
+       u16 rows;
+       u8  chipset;
+ } sisbios_mode[] = {
+-#define MODE_INDEX_NONE           0  /* TW: index for mode=none */
+-      {"none",         0xFF, 0x0000, 0x0000,    0,    0,  0, 0,   0,  0, MD_SIS300|MD_SIS315},  /* TW: for mode "none" */
+-      {"320x240x16",   0x56, 0x0000, 0x0000,  320,  240, 16, 1,  40, 15,           MD_SIS315},
+-      {"320x480x8",    0x5A, 0x0000, 0x0000,  320,  480,  8, 1,  40, 30,           MD_SIS315},  /* TW: FSTN */
+-      {"320x480x16",   0x5B, 0x0000, 0x0000,  320,  480, 16, 1,  40, 30,           MD_SIS315},  /* TW: FSTN */
+-      {"640x480x8",    0x2E, 0x0101, 0x0101,  640,  480,  8, 1,  80, 30, MD_SIS300|MD_SIS315},
++#define MODE_INDEX_NONE           0  /* index for mode=none */
++      {"none",         0xff, 0x0000, 0x0000,    0,    0,  0, 0,   0,  0, MD_SIS300|MD_SIS315},
++      {"320x200x8",    0x59, 0x0138, 0x0000,  320,  200,  8, 1,  40, 12, MD_SIS300|MD_SIS315},
++      {"320x200x16",   0x41, 0x010e, 0x0000,  320,  200, 16, 1,  40, 12, MD_SIS300|MD_SIS315},
++      {"320x200x24",   0x4f, 0x0000, 0x0000,  320,  200, 32, 1,  40, 12, MD_SIS300|MD_SIS315},  /* TW: That's for people who mix up color- and fb depth */
++      {"320x200x32",   0x4f, 0x0000, 0x0000,  320,  200, 32, 1,  40, 12, MD_SIS300|MD_SIS315},
++      {"320x240x8",    0x50, 0x0132, 0x0000,  320,  240,  8, 1,  40, 15, MD_SIS300|MD_SIS315},
++      {"320x240x16",   0x56, 0x0135, 0x0000,  320,  240, 16, 1,  40, 15, MD_SIS300|MD_SIS315},
++      {"320x240x24",   0x53, 0x0000, 0x0000,  320,  240, 32, 1,  40, 15, MD_SIS300|MD_SIS315},
++      {"320x240x32",   0x53, 0x0000, 0x0000,  320,  240, 32, 1,  40, 15, MD_SIS300|MD_SIS315},
++      {"320x240x8",    0x5a, 0x0132, 0x0000,  320,  480,  8, 1,  40, 30,           MD_SIS315},  /* TW: FSTN */
++      {"320x240x16",   0x5b, 0x0135, 0x0000,  320,  480, 16, 1,  40, 30,           MD_SIS315},  /* TW: FSTN */
++      {"400x300x8",    0x51, 0x0133, 0x0000,  400,  300,  8, 1,  50, 18, MD_SIS300|MD_SIS315},
++      {"400x300x16",   0x57, 0x0136, 0x0000,  400,  300, 16, 1,  50, 18, MD_SIS300|MD_SIS315},
++      {"400x300x24",   0x54, 0x0000, 0x0000,  400,  300, 32, 1,  50, 18, MD_SIS300|MD_SIS315},
++      {"400x300x32",   0x54, 0x0000, 0x0000,  400,  300, 32, 1,  50, 18, MD_SIS300|MD_SIS315},
++      {"512x384x8",    0x52, 0x0000, 0x0000,  512,  384,  8, 1,  64, 24, MD_SIS300|MD_SIS315},
++      {"512x384x16",   0x58, 0x0000, 0x0000,  512,  384, 16, 1,  64, 24, MD_SIS300|MD_SIS315},
++      {"512x384x24",   0x5c, 0x0000, 0x0000,  512,  384, 32, 1,  64, 24, MD_SIS300|MD_SIS315},
++      {"512x384x32",   0x5c, 0x0000, 0x0000,  512,  384, 32, 1,  64, 24, MD_SIS300|MD_SIS315},
++      {"640x400x8",    0x2f, 0x0000, 0x0000,  640,  400,  8, 1,  80, 25, MD_SIS300|MD_SIS315},
++      {"640x400x16",   0x5d, 0x0000, 0x0000,  640,  400, 16, 1,  80, 25, MD_SIS300|MD_SIS315},
++      {"640x400x24",   0x5e, 0x0000, 0x0000,  640,  400, 32, 1,  80, 25, MD_SIS300|MD_SIS315},
++      {"640x400x32",   0x5e, 0x0000, 0x0000,  640,  400, 32, 1,  80, 25, MD_SIS300|MD_SIS315},
++      {"640x480x8",    0x2e, 0x0101, 0x0101,  640,  480,  8, 1,  80, 30, MD_SIS300|MD_SIS315},
+       {"640x480x16",   0x44, 0x0111, 0x0111,  640,  480, 16, 1,  80, 30, MD_SIS300|MD_SIS315},
+-      {"640x480x24",   0x62, 0x013a, 0x0112,  640,  480, 32, 1,  80, 30, MD_SIS300|MD_SIS315},  /* TW: That's for people who mix up color- and fb depth */
++      {"640x480x24",   0x62, 0x013a, 0x0112,  640,  480, 32, 1,  80, 30, MD_SIS300|MD_SIS315},
+       {"640x480x32",   0x62, 0x013a, 0x0112,  640,  480, 32, 1,  80, 30, MD_SIS300|MD_SIS315},
+       {"720x480x8",    0x31, 0x0000, 0x0000,  720,  480,  8, 1,  90, 30, MD_SIS300|MD_SIS315},
+       {"720x480x16",   0x33, 0x0000, 0x0000,  720,  480, 16, 1,  90, 30, MD_SIS300|MD_SIS315},
+@@ -464,63 +486,87 @@ struct _sisbios_mode {
+       {"720x576x16",   0x34, 0x0000, 0x0000,  720,  576, 16, 1,  90, 36, MD_SIS300|MD_SIS315},
+       {"720x576x24",   0x36, 0x0000, 0x0000,  720,  576, 32, 1,  90, 36, MD_SIS300|MD_SIS315},
+       {"720x576x32",   0x36, 0x0000, 0x0000,  720,  576, 32, 1,  90, 36, MD_SIS300|MD_SIS315},
++      {"768x576x8",    0x5f, 0x0000, 0x0000,  768,  576,  8, 1,  96, 36, MD_SIS300|MD_SIS315},
++      {"768x576x16",   0x60, 0x0000, 0x0000,  768,  576, 16, 1,  96, 36, MD_SIS300|MD_SIS315},
++      {"768x576x24",   0x61, 0x0000, 0x0000,  768,  576, 32, 1,  96, 36, MD_SIS300|MD_SIS315},
++      {"768x576x32",   0x61, 0x0000, 0x0000,  768,  576, 32, 1,  96, 36, MD_SIS300|MD_SIS315},
+       {"800x480x8",    0x70, 0x0000, 0x0000,  800,  480,  8, 1, 100, 30, MD_SIS300|MD_SIS315},
+       {"800x480x16",   0x7a, 0x0000, 0x0000,  800,  480, 16, 1, 100, 30, MD_SIS300|MD_SIS315},
+       {"800x480x24",   0x76, 0x0000, 0x0000,  800,  480, 32, 1, 100, 30, MD_SIS300|MD_SIS315},
+       {"800x480x32",   0x76, 0x0000, 0x0000,  800,  480, 32, 1, 100, 30, MD_SIS300|MD_SIS315},
+-#define DEFAULT_MODE              20 /* TW: index for 800x600x8 */
+-#define DEFAULT_LCDMODE           20 /* TW: index for 800x600x8 */
+-#define DEFAULT_TVMODE            20 /* TW: 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, 0x0103, 0x0103,  800,  600,  8, 2, 100, 37, MD_SIS300|MD_SIS315},
+       {"800x600x16",   0x47, 0x0114, 0x0114,  800,  600, 16, 2, 100, 37, MD_SIS300|MD_SIS315},
+       {"800x600x24",   0x63, 0x013b, 0x0115,  800,  600, 32, 2, 100, 37, MD_SIS300|MD_SIS315},
+       {"800x600x32",   0x63, 0x013b, 0x0115,  800,  600, 32, 2, 100, 37, MD_SIS300|MD_SIS315},
++      {"848x480x8",    0x39, 0x0000, 0x0000,  848,  480,  8, 2, 106, 30, MD_SIS300|MD_SIS315},
++      {"848x480x16",   0x3b, 0x0000, 0x0000,  848,  480, 16, 2, 106, 30, MD_SIS300|MD_SIS315},
++      {"848x480x24",   0x3e, 0x0000, 0x0000,  848,  480, 32, 2, 106, 30, MD_SIS300|MD_SIS315},
++      {"848x480x32",   0x3e, 0x0000, 0x0000,  848,  480, 32, 2, 106, 30, MD_SIS300|MD_SIS315},
++      {"856x480x8",    0x3f, 0x0000, 0x0000,  856,  480,  8, 2, 107, 30, MD_SIS300|MD_SIS315},
++      {"856x480x16",   0x42, 0x0000, 0x0000,  856,  480, 16, 2, 107, 30, MD_SIS300|MD_SIS315},
++      {"856x480x24",   0x45, 0x0000, 0x0000,  856,  480, 32, 2, 107, 30, MD_SIS300|MD_SIS315},
++      {"856x480x32",   0x45, 0x0000, 0x0000,  856,  480, 32, 2, 107, 30, MD_SIS300|MD_SIS315},
+       {"1024x576x8",   0x71, 0x0000, 0x0000, 1024,  576,  8, 1, 128, 36, MD_SIS300|MD_SIS315},
+       {"1024x576x16",  0x74, 0x0000, 0x0000, 1024,  576, 16, 1, 128, 36, MD_SIS300|MD_SIS315},
+       {"1024x576x24",  0x77, 0x0000, 0x0000, 1024,  576, 32, 1, 128, 36, MD_SIS300|MD_SIS315},
+       {"1024x576x32",  0x77, 0x0000, 0x0000, 1024,  576, 32, 1, 128, 36, MD_SIS300|MD_SIS315},
+-      {"1024x600x8",   0x20, 0x0000, 0x0000, 1024,  600,  8, 1, 128, 37, MD_SIS300          },  /* TW: 300 series only */
++      {"1024x600x8",   0x20, 0x0000, 0x0000, 1024,  600,  8, 1, 128, 37, MD_SIS300          },
+       {"1024x600x16",  0x21, 0x0000, 0x0000, 1024,  600, 16, 1, 128, 37, MD_SIS300          },
+       {"1024x600x24",  0x22, 0x0000, 0x0000, 1024,  600, 32, 1, 128, 37, MD_SIS300          },
+       {"1024x600x32",  0x22, 0x0000, 0x0000, 1024,  600, 32, 1, 128, 37, MD_SIS300          },
+       {"1024x768x8",   0x38, 0x0105, 0x0105, 1024,  768,  8, 2, 128, 48, MD_SIS300|MD_SIS315},
+-      {"1024x768x16",  0x4A, 0x0117, 0x0117, 1024,  768, 16, 2, 128, 48, MD_SIS300|MD_SIS315},
++      {"1024x768x16",  0x4a, 0x0117, 0x0117, 1024,  768, 16, 2, 128, 48, MD_SIS300|MD_SIS315},
+       {"1024x768x24",  0x64, 0x013c, 0x0118, 1024,  768, 32, 2, 128, 48, MD_SIS300|MD_SIS315},
+       {"1024x768x32",  0x64, 0x013c, 0x0118, 1024,  768, 32, 2, 128, 48, MD_SIS300|MD_SIS315},
+-      {"1152x768x8",   0x23, 0x0000, 0x0000, 1152,  768,  8, 1, 144, 48, MD_SIS300          },  /* TW: 300 series only */
++      {"1152x768x8",   0x23, 0x0000, 0x0000, 1152,  768,  8, 1, 144, 48, MD_SIS300          },
+       {"1152x768x16",  0x24, 0x0000, 0x0000, 1152,  768, 16, 1, 144, 48, MD_SIS300          },
+       {"1152x768x24",  0x25, 0x0000, 0x0000, 1152,  768, 32, 1, 144, 48, MD_SIS300          },
+       {"1152x768x32",  0x25, 0x0000, 0x0000, 1152,  768, 32, 1, 144, 48, MD_SIS300          },
++      {"1152x864x8",   0x29, 0x0000, 0x0000, 1152,  864,  8, 1, 144, 54, MD_SIS300|MD_SIS315},
++      {"1152x864x16",  0x2a, 0x0000, 0x0000, 1152,  864, 16, 1, 144, 54, MD_SIS300|MD_SIS315},
++      {"1152x864x24",  0x2b, 0x0000, 0x0000, 1152,  864, 32, 1, 144, 54, MD_SIS300|MD_SIS315},
++      {"1152x864x32",  0x2b, 0x0000, 0x0000, 1152,  864, 32, 1, 144, 54, MD_SIS300|MD_SIS315},
+       {"1280x720x8",   0x79, 0x0000, 0x0000, 1280,  720,  8, 1, 160, 45, MD_SIS300|MD_SIS315},
+       {"1280x720x16",  0x75, 0x0000, 0x0000, 1280,  720, 16, 1, 160, 45, MD_SIS300|MD_SIS315},
+       {"1280x720x24",  0x78, 0x0000, 0x0000, 1280,  720, 32, 1, 160, 45, MD_SIS300|MD_SIS315},
+       {"1280x720x32",  0x78, 0x0000, 0x0000, 1280,  720, 32, 1, 160, 45, MD_SIS300|MD_SIS315},
+-      {"1280x768x8",   0x23, 0x0000, 0x0000, 1280,  768,  8, 1, 160, 48,           MD_SIS315},  /* TW: 310/325 series only */
+-      {"1280x768x16",  0x24, 0x0000, 0x0000, 1280,  768, 16, 1, 160, 48,           MD_SIS315},
+-      {"1280x768x24",  0x25, 0x0000, 0x0000, 1280,  768, 32, 1, 160, 48,           MD_SIS315},
+-      {"1280x768x32",  0x25, 0x0000, 0x0000, 1280,  768, 32, 1, 160, 48,           MD_SIS315},
+-#define MODEINDEX_1280x960 48
+-      {"1280x960x8",   0x7C, 0x0000, 0x0000, 1280,  960,  8, 1, 160, 60, MD_SIS300|MD_SIS315},  /* TW: Modenumbers being patched */
+-      {"1280x960x16",  0x7D, 0x0000, 0x0000, 1280,  960, 16, 1, 160, 60, MD_SIS300|MD_SIS315},
+-      {"1280x960x24",  0x7E, 0x0000, 0x0000, 1280,  960, 32, 1, 160, 60, MD_SIS300|MD_SIS315},
+-      {"1280x960x32",  0x7E, 0x0000, 0x0000, 1280,  960, 32, 1, 160, 60, MD_SIS300|MD_SIS315},
+-      {"1280x1024x8",  0x3A, 0x0107, 0x0107, 1280, 1024,  8, 2, 160, 64, MD_SIS300|MD_SIS315},
+-      {"1280x1024x16", 0x4D, 0x011a, 0x011a, 1280, 1024, 16, 2, 160, 64, MD_SIS300|MD_SIS315},
++#define MODEINDEX_1280x768 79
++      {"1280x768x8",   0x23, 0x0000, 0x0000, 1280,  768,  8, 1, 160, 48, MD_SIS300|MD_SIS315},
++      {"1280x768x16",  0x24, 0x0000, 0x0000, 1280,  768, 16, 1, 160, 48, MD_SIS300|MD_SIS315},
++      {"1280x768x24",  0x25, 0x0000, 0x0000, 1280,  768, 32, 1, 160, 48, MD_SIS300|MD_SIS315},
++      {"1280x768x32",  0x25, 0x0000, 0x0000, 1280,  768, 32, 1, 160, 48, MD_SIS300|MD_SIS315},
++      {"1280x960x8",   0x7c, 0x0000, 0x0000, 1280,  960,  8, 1, 160, 60, MD_SIS300|MD_SIS315},
++      {"1280x960x16",  0x7d, 0x0000, 0x0000, 1280,  960, 16, 1, 160, 60, MD_SIS300|MD_SIS315},
++      {"1280x960x24",  0x7e, 0x0000, 0x0000, 1280,  960, 32, 1, 160, 60, MD_SIS300|MD_SIS315},
++      {"1280x960x32",  0x7e, 0x0000, 0x0000, 1280,  960, 32, 1, 160, 60, MD_SIS300|MD_SIS315},
++      {"1280x1024x8",  0x3a, 0x0107, 0x0107, 1280, 1024,  8, 2, 160, 64, MD_SIS300|MD_SIS315},
++      {"1280x1024x16", 0x4d, 0x011a, 0x011a, 1280, 1024, 16, 2, 160, 64, MD_SIS300|MD_SIS315},
+       {"1280x1024x24", 0x65, 0x013d, 0x011b, 1280, 1024, 32, 2, 160, 64, MD_SIS300|MD_SIS315},
+       {"1280x1024x32", 0x65, 0x013d, 0x011b, 1280, 1024, 32, 2, 160, 64, MD_SIS300|MD_SIS315},
+-      {"1400x1050x8",  0x26, 0x0000, 0x0000, 1400, 1050,  8, 1, 175, 65,           MD_SIS315},  /* TW: 310/325 series only */
++      {"1360x768x8",   0x48, 0x0000, 0x0000, 1360,  768,  8, 1, 170, 48, MD_SIS300|MD_SIS315},
++      {"1360x768x16",  0x4b, 0x0000, 0x0000, 1360,  768, 16, 1, 170, 48, MD_SIS300|MD_SIS315},
++      {"1360x768x24",  0x4e, 0x0000, 0x0000, 1360,  768, 32, 1, 170, 48, MD_SIS300|MD_SIS315},
++      {"1360x768x32",  0x4e, 0x0000, 0x0000, 1360,  768, 32, 1, 170, 48, MD_SIS300|MD_SIS315},
++      {"1360x1024x8",  0x67, 0x0000, 0x0000, 1360, 1024,  8, 1, 170, 64, MD_SIS300          },
++      {"1360x1024x16", 0x6f, 0x0000, 0x0000, 1360, 1024, 16, 1, 170, 64, MD_SIS300          },
++      {"1360x1024x24", 0x72, 0x0000, 0x0000, 1360, 1024, 32, 1, 170, 64, MD_SIS300          },
++      {"1360x1024x32", 0x72, 0x0000, 0x0000, 1360, 1024, 32, 1, 170, 64, MD_SIS300          },
++      {"1400x1050x8",  0x26, 0x0000, 0x0000, 1400, 1050,  8, 1, 175, 65,           MD_SIS315},
+       {"1400x1050x16", 0x27, 0x0000, 0x0000, 1400, 1050, 16, 1, 175, 65,           MD_SIS315},
+       {"1400x1050x24", 0x28, 0x0000, 0x0000, 1400, 1050, 32, 1, 175, 65,           MD_SIS315},
+       {"1400x1050x32", 0x28, 0x0000, 0x0000, 1400, 1050, 32, 1, 175, 65,           MD_SIS315},
+-      {"1600x1200x8",  0x3C, 0x0130, 0x011c, 1600, 1200,  8, 1, 200, 75, MD_SIS300|MD_SIS315},
+-      {"1600x1200x16", 0x3D, 0x0131, 0x011e, 1600, 1200, 16, 1, 200, 75, MD_SIS300|MD_SIS315},
++      {"1600x1200x8",  0x3c, 0x0130, 0x011c, 1600, 1200,  8, 1, 200, 75, MD_SIS300|MD_SIS315},
++      {"1600x1200x16", 0x3d, 0x0131, 0x011e, 1600, 1200, 16, 1, 200, 75, MD_SIS300|MD_SIS315},
+       {"1600x1200x24", 0x66, 0x013e, 0x011f, 1600, 1200, 32, 1, 200, 75, MD_SIS300|MD_SIS315},
+       {"1600x1200x32", 0x66, 0x013e, 0x011f, 1600, 1200, 32, 1, 200, 75, MD_SIS300|MD_SIS315},
+       {"1920x1440x8",  0x68, 0x013f, 0x0000, 1920, 1440,  8, 1, 240, 75, MD_SIS300|MD_SIS315},
+       {"1920x1440x16", 0x69, 0x0140, 0x0000, 1920, 1440, 16, 1, 240, 75, MD_SIS300|MD_SIS315},
+-      {"1920x1440x24", 0x6B, 0x0141, 0x0000, 1920, 1440, 32, 1, 240, 75, MD_SIS300|MD_SIS315},
+-      {"1920x1440x32", 0x6B, 0x0141, 0x0000, 1920, 1440, 32, 1, 240, 75, MD_SIS300|MD_SIS315},
+-      {"2048x1536x8",  0x6c, 0x0000, 0x0000, 2048, 1536,  8, 1, 256, 96,           MD_SIS315},  /* TW: 310/325 series only */
++      {"1920x1440x24", 0x6b, 0x0141, 0x0000, 1920, 1440, 32, 1, 240, 75, MD_SIS300|MD_SIS315},
++      {"1920x1440x32", 0x6b, 0x0141, 0x0000, 1920, 1440, 32, 1, 240, 75, MD_SIS300|MD_SIS315},
++      {"2048x1536x8",  0x6c, 0x0000, 0x0000, 2048, 1536,  8, 1, 256, 96,           MD_SIS315},
+       {"2048x1536x16", 0x6d, 0x0000, 0x0000, 2048, 1536, 16, 1, 256, 96,           MD_SIS315},
+       {"2048x1536x24", 0x6e, 0x0000, 0x0000, 2048, 1536, 32, 1, 256, 96,           MD_SIS315},
+       {"2048x1536x32", 0x6e, 0x0000, 0x0000, 2048, 1536, 32, 1, 256, 96,           MD_SIS315},
+@@ -538,37 +584,36 @@ u8  sisfb_rate_idx = 0;
+ /* TW: CR36 evaluation */
+ const USHORT sis300paneltype[] =
+-    { LCD_UNKNOWN,   LCD_800x600,  LCD_1024x768,  LCD_1280x1024,
+-      LCD_1280x960,  LCD_640x480,  LCD_1024x600,  LCD_1152x768,
+-      LCD_320x480,   LCD_1024x768, LCD_1024x768,  LCD_1024x768,
+-      LCD_1024x768,  LCD_1024x768, LCD_1024x768,  LCD_1024x768 };
++    { LCD_UNKNOWN,   LCD_800x600,   LCD_1024x768,  LCD_1280x1024,
++      LCD_1280x960,  LCD_640x480,   LCD_1024x600,  LCD_1152x768,
++      LCD_1024x768,  LCD_1024x768,  LCD_1024x768,  LCD_1024x768,
++      LCD_1024x768,  LCD_1024x768,  LCD_320x480,   LCD_1024x768 };
+ 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_320x480,   LCD_1024x768, LCD_1024x768,  LCD_1024x768 };
++    { 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_320x480,   LCD_1024x768 };
++
++#define FL_550_DSTN 0x01
++#define FL_550_FSTN 0x02
+ static const struct _sis_crt2type {
+       char name[10];
+       int type_no;
+       int tvplug_no;
++      unsigned short flags;
+ } sis_crt2type[] = {
+-      {"NONE",        0,              -1},
+-      {"LCD",         DISPTYPE_LCD,   -1},
+-      {"TV",          DISPTYPE_TV,    -1},
+-      {"VGA",         DISPTYPE_CRT2,  -1},
+-      {"SVIDEO",      DISPTYPE_TV,    TVPLUG_SVIDEO},
+-      {"COMPOSITE",   DISPTYPE_TV,    TVPLUG_COMPOSITE},
+-      {"SCART",       DISPTYPE_TV,    TVPLUG_SCART},
+-      {"none",        0,              -1},
+-      {"lcd",         DISPTYPE_LCD,   -1},
+-      {"tv",          DISPTYPE_TV,    -1},
+-      {"vga",         DISPTYPE_CRT2,  -1},
+-      {"svideo",      DISPTYPE_TV,    TVPLUG_SVIDEO},
+-      {"composite",   DISPTYPE_TV,    TVPLUG_COMPOSITE},
+-      {"scart",       DISPTYPE_TV,    TVPLUG_SCART},
+-      {"\0",          -1,             -1}
++      {"NONE",        0,              -1,        0},
++      {"LCD",         CRT2_LCD,       -1,        0},
++      {"TV",          CRT2_TV,        -1,        0},
++      {"VGA",         CRT2_VGA,       -1,        0},
++      {"SVIDEO",      CRT2_TV,        TV_SVIDEO, 0},
++      {"COMPOSITE",   CRT2_TV,        TV_AVIDEO, 0},
++      {"SCART",       CRT2_TV,        TV_SCART,  0},
++      {"DSTN",        CRT2_LCD,       -1,        FL_550_DSTN},
++      {"FSTN",        CRT2_LCD,       -1,        FL_550_FSTN},
++      {"\0",          -1,             -1,        0}
+ };
+ /* Queue mode selection for 310 series */
+@@ -579,9 +624,6 @@ static const struct _sis_queuemode {
+       {"AGP",         AGP_CMD_QUEUE},
+       {"VRAM",        VM_CMD_QUEUE},
+       {"MMIO",        MMIO_CMD},
+-      {"agp",         AGP_CMD_QUEUE},
+-      {"vram",        VM_CMD_QUEUE},
+-      {"mmio",        MMIO_CMD},
+       {"\0",          -1}
+ };
+@@ -590,10 +632,8 @@ static const struct _sis_tvtype {
+       char name[6];
+       int type_no;
+ } sis_tvtype[] = {
+-      {"PAL",         1},
+-      {"NTSC",        2},
+-      {"pal",         1},
+-      {"ntsc",        2},
++      {"PAL",         TV_PAL},
++      {"NTSC",        TV_NTSC},
+       {"\0",          -1}
+ };
+@@ -602,33 +642,102 @@ static const struct _sis_vrate {
+       u16 xres;
+       u16 yres;
+       u16 refresh;
++      BOOLEAN SiS730valid32bpp;
+ } sisfb_vrate[] = {
+-      {1,  640,  480, 60}, {2,  640,  480,  72}, {3, 640,   480,  75}, {4,  640, 480,  85},
+-      {5,  640,  480,100}, {6,  640,  480, 120}, {7, 640,   480, 160}, {8,  640, 480, 200},
+-      {1,  720,  480, 60},
+-      {1,  720,  576, 58},
+-      {1,  800,  480, 60}, {2,  800,  480,  75}, {3, 800,   480,  85},
+-      {1,  800,  600, 56}, {2,  800,  600,  60}, {3, 800,   600,  72}, {4,  800, 600,  75},
+-      {5,  800,  600, 85}, {6,  800,  600, 100}, {7, 800,   600, 120}, {8,  800, 600, 160},
+-      {1, 1024,  768, 43}, {2, 1024,  768,  60}, {3, 1024,  768,  70}, {4, 1024, 768,  75},
+-      {5, 1024,  768, 85}, {6, 1024,  768, 100}, {7, 1024,  768, 120},
+-      {1, 1024,  576, 60}, {2, 1024,  576,  75}, {3, 1024,  576,  85},
+-      {1, 1024,  600, 60},
+-      {1, 1152,  768, 60},
+-      {1, 1280,  720, 60}, {2, 1280,  720,  75}, {3, 1280,  720,  85},
+-      {1, 1280,  768, 60},
+-      {1, 1280, 1024, 43}, {2, 1280, 1024,  60}, {3, 1280, 1024,  75}, {4, 1280, 1024,  85},
+-      {1, 1280,  960, 70},
+-      {1, 1400, 1050, 60},
+-      {1, 1600, 1200, 60}, {2, 1600, 1200,  65}, {3, 1600, 1200,  70}, {4, 1600, 1200,  75},
+-      {5, 1600, 1200, 85}, {6, 1600, 1200, 100}, {7, 1600, 1200, 120},
+-      {1, 1920, 1440, 60}, {2, 1920, 1440,  65}, {3, 1920, 1440,  70}, {4, 1920, 1440,  75},
+-      {5, 1920, 1440, 85}, {6, 1920, 1440, 100},
+-      {1, 2048, 1536, 60}, {2, 2048, 1536,  65}, {3, 2048, 1536,  70}, {4, 2048, 1536,  75},
+-      {5, 2048, 1536, 85},
+-      {0, 0, 0, 0}
++      {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},
++      {1,  640,  480,  60,  TRUE}, {2,  640,  480,  72,  TRUE}, {3,  640,  480,  75,  TRUE},
++      {4,  640,  480,  85,  TRUE}, {5,  640,  480, 100,  TRUE}, {6,  640,  480, 120,  TRUE},
++      {7,  640,  480, 160,  TRUE}, {8,  640,  480, 200,  TRUE},
++      {1,  720,  480,  60,  TRUE},
++      {1,  720,  576,  58,  TRUE},
++      {1,  800,  480,  60,  TRUE}, {2,  800,  480,  75,  TRUE}, {3,  800,  480,  85,  TRUE},
++      {1,  800,  600,  56,  TRUE}, {2,  800,  600,  60,  TRUE}, {3,  800,  600,  72,  TRUE},
++      {4,  800,  600,  75,  TRUE}, {5,  800,  600,  85,  TRUE}, {6,  800,  600, 105,  TRUE},
++      {7,  800,  600, 120,  TRUE}, {8,  800,  600, 160,  TRUE},
++      {1,  848,  480,  39,  TRUE}, {2,  848,  480,  60,  TRUE},
++      {1,  856,  480,  39,  TRUE}, {2,  856,  480,  60,  TRUE},
++      {1, 1024,  576,  60,  TRUE}, {2, 1024,  576,  75,  TRUE}, {3, 1024,  576,  85,  TRUE},
++      {1, 1024,  600,  60,  TRUE},
++      {1, 1024,  768,  43,  TRUE}, {2, 1024,  768,  60,  TRUE}, {3, 1024,  768,  70, FALSE},
++      {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,  75,  TRUE}, {2, 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,  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},
++      {1, 1360,  768,  60,  TRUE},
++      {1, 1360, 1024,  59,  TRUE},
++      {1, 1400, 1050,  60,  TRUE}, {2, 1400, 1050,  75,  TRUE},
++      {1, 1600, 1200,  60,  TRUE}, {2, 1600, 1200,  65,  TRUE}, {3, 1600, 1200,  70,  TRUE},
++      {4, 1600, 1200,  75,  TRUE}, {5, 1600, 1200,  85,  TRUE}, {6, 1600, 1200, 100,  TRUE},
++      {7, 1600, 1200, 120,  TRUE},
++      {1, 1920, 1440,  60,  TRUE}, {2, 1920, 1440,  65,  TRUE}, {3, 1920, 1440,  70,  TRUE},
++      {4, 1920, 1440,  75,  TRUE}, {5, 1920, 1440,  85,  TRUE}, {6, 1920, 1440, 100,  TRUE},
++      {1, 2048, 1536,  60,  TRUE}, {2, 2048, 1536,  65,  TRUE}, {3, 2048, 1536,  70,  TRUE},
++      {4, 2048, 1536,  75,  TRUE}, {5, 2048, 1536,  85,  TRUE},
++      {0,    0,    0,   0, FALSE}
+ };
++static struct sisfb_monitor {
++      u16 hmin;
++      u16 hmax;
++      u16 vmin;
++      u16 vmax;
++      u32 dclockmax;
++      u8  feature;
++      BOOLEAN datavalid;
++} sisfb_thismonitor;
++
++static const struct _sisfbddcsmodes {
++      u32 mask;
++      u16 h;
++      u16 v;
++      u32 d;
++} sisfb_ddcsmodes[] = {
++      { 0x10000, 67, 75, 108000},
++      { 0x08000, 48, 72,  50000},
++      { 0x04000, 46, 75,  49500},
++      { 0x01000, 35, 43,  44900},
++      { 0x00800, 48, 60,  65000},
++      { 0x00400, 56, 70,  75000},
++      { 0x00200, 60, 75,  78800},
++      { 0x00100, 80, 75, 135000},
++      { 0x00020, 31, 60,  25200},
++      { 0x00008, 38, 72,  31500},
++      { 0x00004, 37, 75,  31500},
++      { 0x00002, 35, 56,  36000},
++      { 0x00001, 38, 60,  40000}
++};
++
++static const 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}
++};
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
++static u8 sisfb_lastrates[128];
++#endif
++
+ static const struct _chswtable {
+     int subsysVendor;
+     int subsysCard;
+@@ -636,9 +745,61 @@ static const struct _chswtable {
+     char *cardName;
+ } mychswtable[] = {
+         { 0x1631, 0x1002, "Mitachi", "0x1002" },
++      { 0x1071, 0x7521, "Mitac"  , "7521P"  },
+       { 0,      0,      ""       , ""       }
+ };
++static const struct _customttable {
++    unsigned short chipID;
++    char *biosversion;
++    char *biosdate;
++    unsigned long bioschksum;
++    unsigned short biosFootprintAddr[5];
++    unsigned char biosFootprintData[5];
++    unsigned short pcisubsysvendor;
++    unsigned short pcisubsyscard;
++    char *vendorName;
++    char *cardName;
++    unsigned long SpecialID;
++    char *optionName;
++} mycustomttable[] = {
++        { SIS_630, "2.00.07", "09/27/2002-13:38:25",
++        0x3240A8,
++        { 0x220, 0x227, 0x228, 0x229, 0x22a },
++        {  0x01,  0xe3,  0x9a,  0x6a,  0x00 },
++        0x1039, 0x6300,
++        "Barco", "iQ R200L/300/400", CUT_BARCO1366, "BARCO1366"
++      },
++      { SIS_630, "2.00.07", "09/27/2002-13:38:25",
++        0x323FBD,
++        { 0x220, 0x227, 0x228, 0x229, 0x22a },
++        {  0x00,  0x5a,  0x64,  0x41,  0x00 },
++        0x1039, 0x6300,
++        "Barco", "iQ G200L/300/400/500", CUT_BARCO1024, "BARCO1024"
++      },
++      { SIS_650, "", "",
++        0,
++        { 0, 0, 0, 0, 0 },
++        { 0, 0, 0, 0, 0 },
++        0x0e11, 0x083c,
++        "Compaq", "Presario 3045US", CUT_COMPAQ12802, "COMPAQ1280"
++      },
++      { 4321, "", "",                 /* This is hopefully NEVER autodetected */
++        0,
++        { 0, 0, 0, 0, 0 },
++        { 0, 0, 0, 0, 0 },
++        0, 0,
++        "Generic", "LVDS/Parallel 848x480", CUT_PANEL848, "PANEL848x480"
++      },
++      { 0, "", "",
++        0,
++        { 0, 0, 0, 0 },
++        { 0, 0, 0, 0 },
++        0, 0,
++        "", "", CUT_NONE, ""
++      }
++};
++
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+ /* Offscreen layout */
+ typedef struct _SIS_GLYINFO {
+@@ -677,7 +838,6 @@ static unsigned long sisfb_heap_end;
+ static unsigned long sisfb_heap_size;
+ static SIS_HEAP      sisfb_heap;
+-// Eden Chen
+ static const struct _sis_TV_filter {
+       u8 filter[9][4];
+ } sis_TV_filter[] = {
+@@ -829,9 +989,8 @@ static const struct _sis_TV_filter {
+ static int           filter = -1;
+ static unsigned char filter_tb;
+-//~Eden Chen
+-/* ---------------------- Routine prototypes ------------------------- */
++/* ---------------------- Prototypes ------------------------- */
+ /* Interface used by the world */
+ #ifndef MODULE
+@@ -894,10 +1053,6 @@ extern void     fbcon_sis_fillrect(struc
+                                    const struct fb_fillrect *rect);
+ extern void     fbcon_sis_copyarea(struct fb_info *info, 
+                                    const struct fb_copyarea *area);
+-#if 0                            
+-extern void     cfb_imageblit(struct fb_info *info, 
+-                              const struct fb_image *image);
+-#endif                              
+ extern int      fbcon_sis_sync(struct fb_info *info);
+ static int      sisfb_ioctl(struct inode *inode, 
+                           struct file *file,
+@@ -912,7 +1067,7 @@ extern int      sisfb_mode_rate_to_ddata
+                        unsigned int *left_margin, unsigned int *right_margin, 
+                        unsigned int *upper_margin, unsigned int *lower_margin,
+                        unsigned int *hsync_len, unsigned int *vsync_len,
+-                       unsigned int *sync, unsigned int *vmode);                                                                    
++                       unsigned int *sync, unsigned int *vmode);
+ #endif
+                       
+ static int      sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+@@ -923,9 +1078,9 @@ extern int      sisfb_initaccel(void);
+ extern void     sisfb_syncaccel(void);
+ /* Internal general routines */
+-static void     sisfb_search_mode(const char *name);
+-static int      sisfb_validate_mode(int modeindex);
+-static u8       sisfb_search_refresh_rate(unsigned int rate);
++static void     sisfb_search_mode(char *name, BOOLEAN quiet);
++static int      sisfb_validate_mode(int modeindex, unsigned long vbflags);
++static u8       sisfb_search_refresh_rate(unsigned int rate, int index);
+ static int      sisfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+                       unsigned blue, unsigned transp,
+                       struct fb_info *fb_info);
+@@ -939,6 +1094,12 @@ static BOOLEAN  sisfb_CheckVBRetrace(voi
+ static BOOLEAN  sisfbcheckvretracecrt2(void);
+ static BOOLEAN  sisfbcheckvretracecrt1(void);
+ static BOOLEAN  sisfb_bridgeisslave(void);
++static void     sisfb_detect_VB_connect(void);
++static void     sisfb_get_VB_type(void);
++
++static void     sisfb_handle_ddc(struct sisfb_monitor *monitor, int crtno);
++static BOOLEAN  sisfb_interpret_edid(struct sisfb_monitor *monitor, unsigned char *buffer);
++
+ /* SiS-specific Export functions */
+ void            sis_dispinfo(struct ap_data *rec);
+@@ -952,15 +1113,9 @@ u32             sisfb_get_reg3(u16 port)
+ /* Chipset-dependent internal routines */
+ #ifdef CONFIG_FB_SIS_300
+ static int      sisfb_get_dram_size_300(void);
+-static void     sisfb_detect_VB_connect_300(void);
+-static void     sisfb_get_VB_type_300(void);
+-static int      sisfb_has_VB_300(void);
+ #endif
+ #ifdef CONFIG_FB_SIS_315
+ static int      sisfb_get_dram_size_315(void);
+-static void     sisfb_detect_VB_connect_315(void);
+-static void     sisfb_get_VB_type_315(void);
+-static int      sisfb_has_VB_315(void);
+ #endif
+ /* Internal heap routines */
+@@ -978,23 +1133,33 @@ BOOLEAN         sisfb_query_VGA_config_s
+ BOOLEAN         sisfb_query_north_bridge_space(PSIS_HW_DEVICE_INFO psishw_ext,
+                       unsigned long offset, unsigned long set, unsigned long *value);
+-
+ /* Routines from init.c/init301.c */
+ extern void   SiSRegInit(SiS_Private *SiS_Pr, USHORT BaseAddr);
+ extern BOOLEAN  SiSInit(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+ extern BOOLEAN  SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT ModeNo);
+-extern void     SiS_SetEnableDstn(SiS_Private *SiS_Pr);
++extern void     SiS_SetEnableDstn(SiS_Private *SiS_Pr, int enable);
++extern void     SiS_SetEnableFstn(SiS_Private *SiS_Pr, int enable);
+ extern void     SiS_LongWait(SiS_Private *SiS_Pr);
+-/* TW: Chrontel TV functions */
++extern BOOLEAN  sisfb_gettotalfrommode(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
++                     unsigned char modeno, int *htotal, int *vtotal, unsigned char rateindex);
++
++/* Chrontel TV 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, unsigned long VBFlags, int VGAEngine,
++                            USHORT adaptnum, USHORT DDCdatatype, unsigned char *buffer);
++extern void SiS_Chrontel701xBLOn(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
++extern void SiS_Chrontel701xBLOff(SiS_Private *SiS_Pr);
++extern void SiS_SiS30xBLOn(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
++extern void SiS_SiS30xBLOff(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+-/* TW: Sensing routines */
++/* Sensing routines */
+ void            SiS_Sense30x(void);
+ int             SISDoSense(int tempbl, int tempbh, int tempcl, int tempch);
+ void            SiS_SenseCh(void);                    
+--- linux-2.6.0-test6/drivers/video/sis/vgatypes.h     2003-06-14 12:17:55.000000000 -0700
++++ 25/drivers/video/sis/vgatypes.h    2003-10-05 00:34:22.000000000 -0700
+@@ -1,3 +1,36 @@
++/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/sis/vgatypes.h,v 1.0 2001/06/15 21:23:00 dawes Exp $ */
++/*
++ * General type definitions for universal mode switching modules
++ *
++ * Copyright 2002, 2003 by Thomas Winischhofer, Vienna, Austria
++ *
++ * If distributed as part of the linux kernel, the contents of this file
++ * is entirely covered by the GPL.
++ *
++ * Otherwise, the following terms apply:
++ *
++ * Permission to use, copy, modify, distribute, and sell this software and its
++ * documentation for any purpose is hereby granted without fee, provided that
++ * the above copyright notice appear in all copies and that both that
++ * copyright notice and this permission notice appear in supporting
++ * documentation, and that the name of the copyright holder not be used in
++ * advertising or publicity pertaining to distribution of the software without
++ * specific, written prior permission.  The copyright holder makes no representations
++ * about the suitability of this software for any purpose.  It is provided
++ * "as is" without express or implied warranty.
++ *
++ * THE COPYRIGHT HOLDER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
++ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
++ * EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR
++ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
++ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
++ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ *
++ * Authors:   Thomas Winischhofer <thomas@winischhofer.net>
++ *            Silicon Integrated Systems
++ *
++ */
+ #ifndef _VGATYPES_
+ #define _VGATYPES_
+@@ -5,7 +38,7 @@
+ #include "xf86Pci.h"
+ #endif
+-#ifdef LINUX_KERNEL  /* TW: We don't want the X driver to depend on kernel source */
++#ifdef LINUX_KERNEL  /* We don't want the X driver to depend on kernel source */
+ #include <linux/ioctl.h>
+ #endif
+@@ -72,18 +105,15 @@ typedef void VOID;
+ typedef UCHAR BOOLEAN;
+ #endif
+-#ifndef WINCE_HEADER
+ #ifndef bool
+ typedef UCHAR bool;
+ #endif
+-#endif /*WINCE_HEADER*/
+ #ifndef VBIOS_VER_MAX_LENGTH
+ #define VBIOS_VER_MAX_LENGTH         4
+ #endif
+ #ifndef LINUX_KERNEL   /* For kernel, this is defined in sisfb.h */
+-#ifndef WIN2000
+ #ifndef SIS_CHIP_TYPE
+ typedef enum _SIS_CHIP_TYPE {
+     SIS_VGALegacy = 0,
+@@ -101,19 +131,19 @@ typedef enum _SIS_CHIP_TYPE {
+     SIS_550,
+     SIS_650,
+     SIS_740,
+-    SIS_330, 
++    SIS_330,
++    SIS_660,
++    SIS_760,
+     MAX_SIS_CHIP
+ } SIS_CHIP_TYPE;
+ #endif
+ #endif
+-#endif
+-#ifndef WIN2000
+ #ifndef SIS_VB_CHIP_TYPE
+ typedef enum _SIS_VB_CHIP_TYPE {
+     VB_CHIP_Legacy = 0,
+     VB_CHIP_301,
+-    VB_CHIP_301B,      
++    VB_CHIP_301B,
+     VB_CHIP_301LV,
+     VB_CHIP_302,
+     VB_CHIP_302B,
+@@ -122,9 +152,7 @@ typedef enum _SIS_VB_CHIP_TYPE {
+     MAX_VB_CHIP
+ } SIS_VB_CHIP_TYPE;
+ #endif
+-#endif
+-#ifndef WIN2000
+ #ifndef SIS_LCD_TYPE
+ typedef enum _SIS_LCD_TYPE {
+     LCD_INVALID = 0,
+@@ -136,18 +164,20 @@ typedef enum _SIS_LCD_TYPE {
+     LCD_1600x1200,
+     LCD_1920x1440,
+     LCD_2048x1536,
+-    LCD_320x480,       /* TW: FSTN */
++    LCD_320x480,       /* FSTN, DSTN */
+     LCD_1400x1050,
+     LCD_1152x864,
+     LCD_1152x768,
+     LCD_1280x768,
+     LCD_1024x600,
++    LCD_640x480_2,     /* FSTN, DSTN */
++    LCD_640x480_3,     /* FSTN, DSTN */
++    LCD_848x480,
++    LCD_CUSTOM,
+     LCD_UNKNOWN
+ } SIS_LCD_TYPE;
+ #endif
+-#endif
+-#ifndef WIN2000 /* mark by Paul, Move definition to sisv.h*/
+ #ifndef PSIS_DSReg
+ typedef struct _SIS_DSReg
+ {
+@@ -162,7 +192,6 @@ typedef struct _SIS_HW_DEVICE_INFO  SIS_
+ typedef BOOLEAN (*PSIS_QUERYSPACE)   (PSIS_HW_DEVICE_INFO, ULONG, ULONG, ULONG *);
+-
+ struct _SIS_HW_DEVICE_INFO
+ {
+     PVOID  pDevice;              /* The pointer to the physical device data structure
+@@ -173,7 +202,7 @@ struct _SIS_HW_DEVICE_INFO
+                                  /* Note:ROM image file is the file of VBIOS ROM */
+     BOOLEAN UseROM;            /* TW: Use the ROM image if provided */
+- 
++
+     UCHAR  *pjCustomizedROMImage;/* base virtual address of ROM image file. */
+                                  /* wincE:ROM image file is the file for OEM */
+                                  /*       customized table */
+@@ -195,7 +224,7 @@ struct _SIS_HW_DEVICE_INFO
+                                  /* defined in the data structure type */
+                                  /* "SIS_VB_CHIP_TYPE" */
+-    USHORT usExternalChip;       /* NO VB or other video bridge(not  */
++    USHORT usExternalChip;       /* NO VB or other video bridge (other than  */
+                                  /* SiS video bridge) */
+                                  /* if ujVBChipID = VB_CHIP_UNKNOWN, */
+                                  /* then bit0=1 : LVDS,bit1=1 : trumpion, */
+@@ -207,7 +236,7 @@ struct _SIS_HW_DEVICE_INFO
+                                  /*             011:Trumpion LVDS Scaling Chip */
+                                  /*             100:LVDS(LCD-out)+Chrontel 7005 */
+                                  /*             101:Single Chrontel 7005 */
+-                               /* TW: This has changed on 310/325 series! */
++                               /* TW: This has changed on 315 series! */
+     ULONG  ulCRT2LCDType;        /* defined in the data structure type */
+                                  /* "SIS_LCD_TYPE" */
+@@ -244,7 +273,6 @@ struct _SIS_HW_DEVICE_INFO
+ #endif
+ };
+ #endif
+-#endif 
+ /* TW: Addtional IOCTL for communication sisfb <> X driver        */
+@@ -284,12 +312,16 @@ struct _SISFB_INFO {
+       
+       unsigned char sisfb_lcda;
+-      char reserved[235];             /* for future use */
++      unsigned long sisfb_vbflags;
++      unsigned long sisfb_currentvbflags;
++
++      int sisfb_scalelcd;
++      unsigned long sisfb_specialtiming;
++
++      char reserved[219];             /* for future use */
+ };
+ #endif
+-#ifndef WIN2000
+-#ifndef WINCE_HEADER
+ #ifndef BUS_DATA_TYPE
+ typedef enum _BUS_DATA_TYPE {
+     ConfigurationSpaceUndefined = -1,
+@@ -307,7 +339,6 @@ typedef enum _BUS_DATA_TYPE {
+     MaximumBusDataType
+ } BUS_DATA_TYPE, *PBUS_DATA_TYPE;
+ #endif
+-#endif /* WINCE_HEADER */
+ #ifndef PCI_TYPE0_ADDRESSES
+ #define PCI_TYPE0_ADDRESSES             6
+@@ -317,7 +348,6 @@ typedef enum _BUS_DATA_TYPE {
+ #define PCI_TYPE1_ADDRESSES             2
+ #endif
+-#ifndef WINCE_HEADER
+ #ifndef PCI_COMMON_CONFIG
+ typedef struct _PCI_COMMON_CONFIG {
+     USHORT  VendorID;                   /* (ro)                 */
+@@ -355,7 +385,6 @@ typedef struct _PCI_COMMON_CONFIG {
+ } PCI_COMMON_CONFIG, *PPCI_COMMON_CONFIG;
+ #endif
+-#endif /* WINCE_HEADER */
+ #ifndef FIELD_OFFSET
+ #define FIELD_OFFSET(type, field)    ((LONG)&(((type *)0)->field))
+@@ -364,6 +393,6 @@ typedef struct _PCI_COMMON_CONFIG {
+ #ifndef PCI_COMMON_HDR_LENGTH
+ #define PCI_COMMON_HDR_LENGTH (FIELD_OFFSET (PCI_COMMON_CONFIG, DeviceSpecific))
+ #endif
+-#endif
+ #endif
++
+--- linux-2.6.0-test6/drivers/video/sis/vstruct.h      2003-06-14 12:18:25.000000000 -0700
++++ 25/drivers/video/sis/vstruct.h     2003-10-05 00:34:22.000000000 -0700
+@@ -1,3 +1,37 @@
++/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/sis/vstruct.h,v 1.0 2001/06/15 21:23:00 dawes Exp $ */
++/*
++ * General structure definitions for universal mode switching modules
++ *
++ * Copyright 2002, 2003 by Thomas Winischhofer, Vienna, Austria
++ *
++ * If distributed as part of the linux kernel, the contents of this file
++ * is entirely covered by the GPL.
++ *
++ * Otherwise, the following terms apply:
++ *
++ * Permission to use, copy, modify, distribute, and sell this software and its
++ * documentation for any purpose is hereby granted without fee, provided that
++ * the above copyright notice appear in all copies and that both that
++ * copyright notice and this permission notice appear in supporting
++ * documentation, and that the name of the copyright holder not be used in
++ * advertising or publicity pertaining to distribution of the software without
++ * specific, written prior permission.  The copyright holder makes no representations
++ * about the suitability of this software for any purpose.  It is provided
++ * "as is" without express or implied warranty.
++ *
++ * THE COPYRIGHT HOLDER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
++ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
++ * EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR
++ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
++ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
++ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ *
++ * Authors:   Thomas Winischhofer <thomas@winischhofer.net>
++ *              Silicon Integrated Systems
++ *
++ */
++
+ #ifdef _INIT_
+ #define EXTERN
+ #else
+@@ -58,7 +92,6 @@ typedef struct _SiS_LVDSCRT1DataStruct
+       UCHAR  CR[15];
+ } SiS_LVDSCRT1DataStruct;
+-/*add for LCDA*/
+ typedef struct _SiS_LCDACRT1DataStruct
+ {
+       UCHAR  CR[17];
+@@ -111,9 +144,7 @@ typedef struct _SiS_ExtStruct
+       UCHAR  Ext_ModeID;
+       USHORT Ext_ModeFlag;
+       USHORT Ext_ModeInfo;
+-      USHORT Ext_Point;
+       USHORT Ext_VESAID;
+-      UCHAR  Ext_VESAMEMSize;
+       UCHAR  Ext_RESINFO;
+       UCHAR  VB_ExtTVFlickerIndex;
+       UCHAR  VB_ExtTVEdgeIndex;
+@@ -130,7 +161,6 @@ typedef struct _SiS_Ext2Struct
+       UCHAR  ModeID;
+       USHORT XRes;
+       USHORT YRes;
+-      USHORT ROM_OFFSET;
+ } SiS_Ext2Struct;
+ typedef struct _SiS_Part2PortTblStruct
+@@ -183,6 +213,15 @@ typedef struct _SiS_ModeResInfoStruct
+ typedef UCHAR DRAM4Type[4];
++/* Defines for SiS_Customt */
++#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
++
+ typedef struct _SiS_Private
+ {
+ #ifdef LINUX_KERNEL
+@@ -198,25 +237,34 @@ typedef struct _SiS_Private
+       USHORT SiS_P3c7;
+       USHORT SiS_P3c8;
+       USHORT SiS_P3c9;
++      USHORT SiS_P3cb;
++      USHORT SiS_P3cd;
+       USHORT SiS_P3da;
+       USHORT SiS_Part1Port;
+       USHORT SiS_Part2Port;
+       USHORT SiS_Part3Port;
+       USHORT SiS_Part4Port;
+       USHORT SiS_Part5Port;
++      USHORT SiS_VidCapt;
++      USHORT SiS_VidPlay;
+       USHORT SiS_IF_DEF_LVDS;
+       USHORT SiS_IF_DEF_TRUMPION;
+       USHORT SiS_IF_DEF_DSTN;
+       USHORT SiS_IF_DEF_FSTN;
+       USHORT SiS_IF_DEF_CH70xx;
+       USHORT SiS_IF_DEF_HiVision;
++      USHORT SiS_SysFlags;
+       UCHAR  SiS_VGAINFO;
++#ifndef LINUX_KERNEL
++        USHORT SiS_CP1, SiS_CP2, SiS_CP3, SiS_CP4;
++#endif
+       BOOLEAN SiS_UseROM;
+       int    SiS_CHOverScan;
+       BOOLEAN SiS_CHSOverScan;
+       BOOLEAN SiS_ChSW;
+       BOOLEAN SiS_UseLCDA;
+       int    SiS_UseOEM;
++      ULONG  SiS_CustomT;
+       USHORT SiS_Backup70xx;
+       USHORT SiS_CRT1Mode;
+       USHORT SiS_flag_clearbuffer;
+@@ -270,15 +318,18 @@ typedef struct _SiS_Private
+       USHORT SiS_Panel1280x768;
+       USHORT SiS_Panel1024x600;
+       USHORT SiS_Panel640x480;
++      USHORT SiS_Panel640x480_2;
++      USHORT SiS_Panel640x480_3;
+       USHORT SiS_Panel1152x864;
++      USHORT SiS_PanelCustom;
++      USHORT SiS_PanelBarco1366;
+       USHORT SiS_PanelMax;
+       USHORT SiS_PanelMinLVDS;
+       USHORT SiS_PanelMin301;
+       USHORT SiS_ChrontelInit;
+       
+-      /* Pointers: */
+       const SiS_StStruct          *SiS_SModeIDTable;
+-      const SiS_StandTableStruct  *SiS_StandTable;
++      SiS_StandTableStruct        *SiS_StandTable;
+       const SiS_ExtStruct         *SiS_EModeIDTable;
+       const SiS_Ext2Struct        *SiS_RefIndex;
+       const SiS_VBModeStruct      *SiS_VBModeIDTable;
+@@ -316,7 +367,7 @@ typedef struct _SiS_Private
+       const USHORT *pSiS_RGBSenseData;
+       const USHORT *pSiS_VideoSenseData;
+       const USHORT *pSiS_YCSenseData;
+-      const USHORT *pSiS_RGBSenseData2; /*301b*/
++      const USHORT *pSiS_RGBSenseData2;
+       const USHORT *pSiS_VideoSenseData2;
+       const USHORT *pSiS_YCSenseData2;
+ #endif
+@@ -340,15 +391,18 @@ typedef struct _SiS_Private
+       const SiS_LCDDataStruct  *SiS_LCD1280x960Data;
+       const SiS_LCDDataStruct  *SiS_NoScaleData1400x1050;
+       const SiS_LCDDataStruct  *SiS_NoScaleData1600x1200;
++      const SiS_LCDDataStruct  *SiS_NoScaleData1280x768;
+       const SiS_LCDDataStruct  *SiS_StLCD1400x1050Data;
+       const SiS_LCDDataStruct  *SiS_StLCD1600x1200Data;
++      const SiS_LCDDataStruct  *SiS_StLCD1280x768Data;
+       const SiS_LCDDataStruct  *SiS_ExtLCD1400x1050Data;
+       const SiS_LCDDataStruct  *SiS_ExtLCD1600x1200Data;
++      const SiS_LCDDataStruct  *SiS_ExtLCD1280x768Data;
++      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 UCHAR *SiS_NTSCTiming;
+@@ -381,12 +435,19 @@ typedef struct _SiS_Private
+       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_LCDA1400x1050Data_1;
+       const SiS_LVDSDataStruct  *SiS_LCDA1400x1050Data_2;
+       const SiS_LVDSDataStruct  *SiS_LCDA1600x1200Data_1;
+       const SiS_LVDSDataStruct  *SiS_LCDA1600x1200Data_2;
+       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;
+@@ -478,6 +539,12 @@ typedef struct _SiS_Private
+       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_CHTVCRT1UNTSC;
+       const SiS_LVDSCRT1DataStruct  *SiS_CHTVCRT1ONTSC;
+       const SiS_LVDSCRT1DataStruct  *SiS_CHTVCRT1UPAL;
+@@ -507,7 +574,6 @@ typedef struct _SiS_Private
+       const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11400x1050_2_H;
+       const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11600x1200_2_H;
+-      /* TW: New for 650/301LV */
+       const SiS_Part2PortTblStruct *SiS_CRT2Part2_1024x768_1;
+       const SiS_Part2PortTblStruct *SiS_CRT2Part2_1280x1024_1;
+       const SiS_Part2PortTblStruct *SiS_CRT2Part2_1400x1050_1;
+@@ -539,6 +605,9 @@ typedef struct _SiS_Private
+       const UCHAR *SiS_CHTVVCLKUPALN;
+       const UCHAR *SiS_CHTVVCLKOPALN;
+       const UCHAR *SiS_CHTVVCLKSOPAL;
++
++      USHORT  PanelXRes;
++      USHORT  PanelYRes;
+       
+       BOOLEAN UseCustomMode;
+       BOOLEAN CRT1UsesCustomMode;
+@@ -560,8 +629,11 @@ typedef struct _SiS_Private
+       UCHAR   CSR2B;
+       UCHAR   CSR2C;
+       USHORT  CSRClock;
++      USHORT  CSRClock_CRT1;
+       USHORT  CModeFlag;
++      USHORT  CModeFlag_CRT1;
+       USHORT  CInfoFlag;
++
+       BOOLEAN SiS_CHPALM;
+       BOOLEAN SiS_CHPALN;
+       
+@@ -578,7 +650,21 @@ typedef struct _SiS_Private
+       UCHAR Backup_1c;
+       UCHAR Backup_1d;
+       
+-      int    UsePanelScaler;
++      int     UsePanelScaler;
++
++      USHORT  CP_Vendor, CP_Product;
++      BOOLEAN CP_HaveCustomData;
++      int     CP_PreferredX, CP_PreferredY;
++      int     CP_MaxX, CP_MaxY, CP_MaxClock;
++      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;
+ #endif
+--- linux-2.6.0-test6/drivers/video/skeletonfb.c       2003-06-14 12:17:59.000000000 -0700
++++ 25/drivers/video/skeletonfb.c      2003-10-05 00:34:22.000000000 -0700
+@@ -1,7 +1,7 @@
+ /*
+  * linux/drivers/video/skeletonfb.c -- Skeleton for a frame buffer device
+  *
+- *  Modified to new api Jan 2001 by James Simmons (jsimmons@transvirtual.com)
++ *  Modified to new api Jan 2001 by James Simmons (jsimmons@infradead.org)
+  *
+  *  Created 28 Dec 1997 by Geert Uytterhoeven
+  *
+@@ -469,15 +469,71 @@ void xxxfb_imageblit(struct fb_info *p, 
+ int xxxfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+ {
+ /*
+- *      @set:         Which fields we are altering in struct fb_cursor 
++ *      @set:          Which fields we are altering in struct fb_cursor
+  *    @enable: Disable or enable the cursor 
+- *      @rop:         The bit operation we want to do. 
+- *      @mask:  This is the cursor mask bitmap. 
+- *      @dest:  A image of the area we are going to display the cursor.
+- *            Used internally by the driver.   
+- *      @hot: The hot spot. 
+- *    @image: The actual data for the cursor image.
+- */
++ *      @rop:          The bit operation we want to do.
++ *      @hot:  The hot spot.
++ *    @image:  The actual data for the cursor image.
++ *      @mask:   This is the cursor mask bitmap.
++ */
++
++   /* Disable hardware cursor. We don't want to display the cursor
++      while changing it. Note we use the enable and rop fields in
++      struct fb_cursor that is apart of struct fb_info. Not the
++      cursor data passed in from userland. */
++
++   if (cursor->set & FB_CUR_SETHOT) {
++      info->cursor.hot = cursor->hot;
++      /* Set the hardware cursor's hot spot  */
++   }
++
++   if (cursor->set & FB_CUR_SETPOS) {
++      info->cursor.image.dx = cursor->image.dx;
++      info->cursor.image.dy = cursor->image.dy;
++      /* Set the hardware cursor's position */
++   }
++
++   if (cursor->set & FB_CUR_SETSIZE) {
++      info->cursor.image.height = cursor->image.height;
++      info->cursor.image.width = cursor->image.width;
++      /* Set the hardware cursor's size */
++   }
++
++   if (cursor->set & FB_CUR_SETCMAP) {
++      if (cursor->image.depth == 1) {
++              info->cursor.image.fg_color = cursor->image.fg_color;
++              info->cursor.image.bg_color = cursor->image.bg_color;
++      } else {
++              if (cursor->image.cmap.len)
++                      fb_copy_cmap(&cursor->image.cmap, &info->cursor.image.cmap, 0);
++      }
++      info->curosr.image.depth = cursor->image.depth;
++
++      /* Set the hardware cursor's color map */
++   }
++
++   /*
++    * Set the cursor shape. The two pieces needed to create
++    * the final image is mask and image.data. The mask is
++    * combined with image.data according to the rop field.
++    */
++   if (cursor->set & FB_CUR_SETSHAPE) {
++      switch (info->cursor.rop) {
++      case ROP_XOR:
++              /* ... */
++              break;
++      case ROP_COPY:
++      default:
++              /* ... */
++              break;
++      }
++      /* ... */
++   }
++
++   if (info->cursor.enable) {
++      /* Now we turn the hardware cursor on */
++   }
++   return 0;
+ }
+ /**
+--- linux-2.6.0-test6/drivers/video/softcursor.c       2003-06-14 12:18:22.000000000 -0700
++++ 25/drivers/video/softcursor.c      2003-10-05 00:34:28.000000000 -0700
+@@ -21,8 +21,13 @@ int soft_cursor(struct fb_info *info, st
+ {
+       unsigned int scan_align = info->pixmap.scan_align - 1;
+       unsigned int buf_align = info->pixmap.buf_align - 1;
+-      unsigned int i, size, dsize, s_pitch, d_pitch;
+-      u8 *dst, src[64];
++      u8 *dst = (u8 *) info->cursor.image.data;
++      unsigned int i, size, pitch;
++
++      pitch = ((info->cursor.image.width + 7) >> 3) + scan_align;
++      pitch &= ~scan_align;
++      size = pitch * info->cursor.image.height + buf_align;
++      size &= ~buf_align;
+       if (cursor->set & FB_CUR_SETSIZE) {
+               info->cursor.image.height = cursor->image.height;
+@@ -48,34 +53,33 @@ int soft_cursor(struct fb_info *info, st
+               info->cursor.image.depth = cursor->image.depth;
+       }       
+-      s_pitch = (info->cursor.image.width + 7) >> 3;
+-      dsize = s_pitch * info->cursor.image.height;
+-      d_pitch = (s_pitch + scan_align) & ~scan_align;
+-      size = d_pitch * info->cursor.image.height + buf_align;
+-      size &= ~buf_align;
+-      dst = info->pixmap.addr + fb_get_buffer_offset(info, size);
+-
+-      if (info->cursor.enable) {
++      if (cursor->set & FB_CUR_SETSHAPE) {
+               switch (info->cursor.rop) {
+               case ROP_XOR:
+-                      for (i = 0; i < dsize; i++)
+-                              src[i] = cursor->image.data[i] ^ info->cursor.mask[i]; 
++                      for (i = 0; i < size; i++)
++                              dst[i] ^= info->cursor.mask[i];
+                       break;
+               case ROP_COPY:
+               default:
+-                      for (i = 0; i < dsize; i++)
+-                              src[i] = cursor->image.data[i] & info->cursor.mask[i];
++                      for (i = 0; i < size; i++)
++                              dst[i] &= info->cursor.mask[i];
+                       break;
+               }
+-      } else 
+-              memcpy(src, cursor->image.data, dsize);
+-      
+-      move_buf_aligned(info, dst, src, d_pitch, s_pitch, info->cursor.image.height);
+-      info->cursor.image.data = dst;
++      }
+       
+-      info->fbops->fb_imageblit(info, &info->cursor.image);
+-      atomic_dec(&info->pixmap.count);
+-      smp_mb__after_atomic_dec();
++      if (!info->cursor.enable) {
++              for (i = 0; i < size; i++)
++                      dst[i] ^= info->cursor.mask[i];
++      }
++
++      if (info->cursor.image.data)
++              info->fbops->fb_imageblit(info, &info->cursor.image);
++
++      if (!info->cursor.enable) {
++              for (i = 0; i < size; i++)
++                      dst[i] ^= info->cursor.mask[i];
++      }
++
+       return 0;
+ }
+--- linux-2.6.0-test6/drivers/video/sstfb.c    2003-08-08 22:55:13.000000000 -0700
++++ 25/drivers/video/sstfb.c   2003-10-05 00:33:24.000000000 -0700
+@@ -94,7 +94,6 @@
+ #include <linux/pci.h>
+ #include <linux/delay.h>
+ #include <linux/init.h>
+-#include <linux/version.h>
+ #include <linux/slab.h>
+ #include <asm/io.h>
+ #include <asm/ioctl.h>
+--- linux-2.6.0-test6/drivers/video/stifb.c    2003-09-08 13:58:58.000000000 -0700
++++ 25/drivers/video/stifb.c   2003-10-05 00:33:24.000000000 -0700
+@@ -1238,7 +1238,7 @@ stifb_init_fb(struct sti_struct *sti, in
+       /* get framebuffer physical and virtual base addr & len (64bit ready) */
+-      fix->smem_start = fb->sti->regions_phys[1] | 0xffffffff00000000;
++      fix->smem_start = F_EXTEND(fb->sti->regions_phys[1]);
+       fix->smem_len = fb->sti->regions[1].region_desc.length * 4096;
+       fix->line_length = (fb->sti->glob_cfg->total_x * bpp) / 8;
+--- linux-2.6.0-test6/drivers/video/valkyriefb.c       2003-07-27 12:14:40.000000000 -0700
++++ 25/drivers/video/valkyriefb.c      2003-10-05 00:34:22.000000000 -0700
+@@ -51,7 +51,6 @@
+ #include <linux/delay.h>
+ #include <linux/interrupt.h>
+ #include <linux/fb.h>
+-#include <linux/selection.h>
+ #include <linux/init.h>
+ #include <linux/pci.h>
+ #include <linux/nvram.h>
+--- linux-2.6.0-test6/fs/adfs/super.c  2003-09-08 13:58:58.000000000 -0700
++++ 25/fs/adfs/super.c 2003-10-05 00:33:24.000000000 -0700
+@@ -18,6 +18,7 @@
+ #include <linux/init.h>
+ #include <linux/buffer_head.h>
+ #include <linux/vfs.h>
++#include <linux/parser.h>
+ #include <asm/bitops.h>
+ #include <asm/uaccess.h>
+@@ -133,50 +134,56 @@ static void adfs_put_super(struct super_
+       sb->s_fs_info = NULL;
+ }
++enum {Opt_uid, Opt_gid, Opt_ownmask, Opt_othmask, Opt_err};
++
++static match_table_t tokens = {
++      {Opt_uid, "uid=%u"},
++      {Opt_gid, "gid=%u"},
++      {Opt_ownmask, "ownmask=%o"},
++      {Opt_othmask, "othmask=%o"},
++      {Opt_err, NULL}
++};
++
+ static int parse_options(struct super_block *sb, char *options)
+ {
+-      char *value, *opt;
++      char *p;
+       struct adfs_sb_info *asb = ADFS_SB(sb);
++      int option;
+       if (!options)
+               return 0;
+-      while ((opt = strsep(&options, ",")) != NULL) {
+-              if (!*opt)
++      while ((p = strsep(&options, ",")) != NULL) {
++              substring_t args[MAX_OPT_ARGS];
++              int token;
++              if (!*p)
+                       continue;
+-              value = strchr(opt, '=');
+-              if (value)
+-                      *value++ = '\0';
+-              if (!strcmp(opt, "uid")) {      /* owner of all files */
+-                      if (!value || !*value)
+-                              return -EINVAL;
+-                      asb->s_uid = simple_strtoul(value, &value, 0);
+-                      if (*value)
+-                              return -EINVAL;
+-              } else
+-              if (!strcmp(opt, "gid")) {      /* group owner of all files */
+-                      if (!value || !*value)
+-                              return -EINVAL;
+-                      asb->s_gid = simple_strtoul(value, &value, 0);
+-                      if (*value)
+-                              return -EINVAL;
+-              } else
+-              if (!strcmp(opt, "ownmask")) {  /* owner permission mask */
+-                      if (!value || !*value)
++              token = match_token(p, tokens, args);
++              switch (token) {
++              case Opt_uid:
++                      if (match_int(args, &option))
+                               return -EINVAL;
+-                      asb->s_owner_mask = simple_strtoul(value, &value, 8);
+-                      if (*value)
++                      asb->s_uid = option;
++                      break;
++              case Opt_gid:
++                      if (match_int(args, &option))
+                               return -EINVAL;
+-              } else
+-              if (!strcmp(opt, "othmask")) {  /* others permission mask */
+-                      if (!value || !*value)
++                      asb->s_gid = option;
++                      break;
++              case Opt_ownmask:
++                      if (match_octal(args, &option))
+                               return -EINVAL;
+-                      asb->s_other_mask = simple_strtoul(value, &value, 8);
+-                      if (*value)
++                      asb->s_owner_mask = option;
++                      break;
++              case Opt_othmask:
++                      if (match_octal(args, &option))
+                               return -EINVAL;
+-              } else {                        /* eh? say again. */
+-                      printk("ADFS-fs: unrecognised mount option %s\n", opt);
++                      asb->s_other_mask = option;
++                      break;
++              default:
++                      printk("ADFS-fs: unrecognised mount option \"%s\" "
++                                      "or missing value\n", p);
+                       return -EINVAL;
+               }
+       }
+--- linux-2.6.0-test6/fs/affs/file.c   2003-09-08 13:58:58.000000000 -0700
++++ 25/fs/affs/file.c  2003-10-05 00:33:24.000000000 -0700
+@@ -39,7 +39,7 @@ static int affs_grow_extcache(struct ino
+ static struct buffer_head *affs_alloc_extblock(struct inode *inode, struct buffer_head *bh, u32 ext);
+ static inline struct buffer_head *affs_get_extblock(struct inode *inode, u32 ext);
+ static struct buffer_head *affs_get_extblock_slow(struct inode *inode, u32 ext);
+-static ssize_t affs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos);
++static ssize_t affs_file_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos);
+ static int affs_file_open(struct inode *inode, struct file *filp);
+ static int affs_file_release(struct inode *inode, struct file *filp);
+@@ -491,7 +491,8 @@ affs_getemptyblk_ino(struct inode *inode
+ }
+ static ssize_t
+-affs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
++affs_file_write(struct file *file, const char __user *buf,
++              size_t count, loff_t *ppos)
+ {
+       ssize_t retval;
+--- linux-2.6.0-test6/fs/affs/super.c  2003-06-22 12:04:44.000000000 -0700
++++ 25/fs/affs/super.c 2003-10-05 00:33:24.000000000 -0700
+@@ -28,6 +28,7 @@
+ #include <linux/smp_lock.h>
+ #include <linux/buffer_head.h>
+ #include <linux/vfs.h>
++#include <linux/parser.h>
+ #include <asm/system.h>
+ #include <asm/uaccess.h>
+@@ -142,12 +143,37 @@ static struct super_operations affs_sops
+       .remount_fs     = affs_remount,
+ };
++enum {
++      Opt_bs, Opt_mode, Opt_mufs, Opt_prefix, Opt_protect,
++      Opt_reserved, Opt_root, Opt_setgid, Opt_setuid,
++      Opt_verbose, Opt_volume, Opt_ignore, Opt_err,
++};
++
++static match_table_t tokens = {
++      {Opt_bs, "bs=%d"},
++      {Opt_mode, "mode=%o"},
++      {Opt_mufs, "mufs"},
++      {Opt_prefix, "prefix=%s"},
++      {Opt_protect, "protect"},
++      {Opt_reserved, "reserved=%d"},
++      {Opt_root, "root=%d"},
++      {Opt_setgid, "setgid=%d"},
++      {Opt_setuid, "setuid=%d"},
++      {Opt_verbose, "verbose"},
++      {Opt_volume, "volume=%s"},
++      {Opt_ignore, "grpquota"},
++      {Opt_ignore, "noquota"},
++      {Opt_ignore, "quota"},
++      {Opt_ignore, "usrquota"},
++      {Opt_err, NULL},
++};
++
+ static int
+ parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, s32 *root,
+               int *blocksize, char **prefix, char *volume, unsigned long *mount_opts)
+ {
+-      char    *this_char, *value, *optn;
+-      int      f;
++      char *p;
++      substring_t args[MAX_OPT_ARGS];
+       /* Fill in defaults */
+@@ -161,109 +187,85 @@ parse_options(char *options, uid_t *uid,
+       *mount_opts = 0;
+       if (!options)
+               return 1;
+-      while ((this_char = strsep(&options, ",")) != NULL) {
+-              if (!*this_char)
++
++      while ((p = strsep(&options, ",")) != NULL) {
++              int token, n, option;
++              if (!*p)
+                       continue;
+-              f = 0;
+-              if ((value = strchr(this_char,'=')) != NULL)
+-                      *value++ = 0;
+-              if ((optn = "protect") && !strcmp(this_char, optn)) {
+-                      if (value)
+-                              goto out_inv_arg;
+-                      *mount_opts |= SF_IMMUTABLE;
+-              } else if ((optn = "verbose") && !strcmp(this_char, optn)) {
+-                      if (value)
+-                              goto out_inv_arg;
+-                      *mount_opts |= SF_VERBOSE;
+-              } else if ((optn = "mufs") && !strcmp(this_char, optn)) {
+-                      if (value)
+-                              goto out_inv_arg;
+-                      *mount_opts |= SF_MUFS;
+-              } else if ((f = !strcmp(this_char,"setuid")) || !strcmp(this_char,"setgid")) {
+-                      if (value) {
+-                              if (!*value) {
+-                                      printk("AFFS: Argument for set[ug]id option missing\n");
+-                                      return 0;
+-                              } else {
+-                                      (f ? *uid : *gid) = simple_strtoul(value,&value,0);
+-                                      if (*value) {
+-                                              printk("AFFS: Bad set[ug]id argument\n");
+-                                              return 0;
+-                                      }
+-                                      *mount_opts |= f ? SF_SETUID : SF_SETGID;
+-                              }
++
++              token = match_token(p, tokens, args);
++              switch (token) {
++              case Opt_bs:
++                      if (match_int(&args[0], &n))
++                              return -EINVAL;
++                      if (n != 512 && n != 1024 && n != 2048
++                          && n != 4096) {
++                              printk ("AFFS: Invalid blocksize (512, 1024, 2048, 4096 allowed)\n");
++                              return 0;
+                       }
+-              } else if (!strcmp(this_char,"prefix")) {
+-                      optn = "prefix";
+-                      if (!value || !*value)
+-                              goto out_no_arg;
++                      *blocksize = n;
++                      break;
++              case Opt_mode:
++                      if (match_octal(&args[0], &option))
++                              return 1;
++                      *mode = option & 0777;
++                      *mount_opts |= SF_SETMODE;
++                      break;
++              case Opt_mufs:
++                      *mount_opts |= SF_MUFS;
++                      break;
++              case Opt_prefix:
+                       if (*prefix) {          /* Free any previous prefix */
+                               kfree(*prefix);
+                               *prefix = NULL;
+                       }
+-                      *prefix = kmalloc(strlen(value) + 1,GFP_KERNEL);
++                      *prefix = match_strdup(&args[0]);
+                       if (!*prefix)
+                               return 0;
+-                      strcpy(*prefix,value);
+                       *mount_opts |= SF_PREFIX;
+-              } else if (!strcmp(this_char,"volume")) {
+-                      optn = "volume";
+-                      if (!value || !*value)
+-                              goto out_no_arg;
+-                      strlcpy(volume,value,31);
+-              } else if (!strcmp(this_char,"mode")) {
+-                      optn = "mode";
+-                      if (!value || !*value)
+-                              goto out_no_arg;
+-                      *mode = simple_strtoul(value,&value,8) & 0777;
+-                      if (*value)
+-                              return 0;
+-                      *mount_opts |= SF_SETMODE;
+-              } else if (!strcmp(this_char,"reserved")) {
+-                      optn = "reserved";
+-                      if (!value || !*value)
+-                              goto out_no_arg;
+-                      *reserved = simple_strtoul(value,&value,0);
+-                      if (*value)
+-                              return 0;
+-              } else if (!strcmp(this_char,"root")) {
+-                      optn = "root";
+-                      if (!value || !*value)
+-                              goto out_no_arg;
+-                      *root = simple_strtoul(value,&value,0);
+-                      if (*value)
+-                              return 0;
+-              } else if (!strcmp(this_char,"bs")) {
+-                      optn = "bs";
+-                      if (!value || !*value)
+-                              goto out_no_arg;
+-                      *blocksize = simple_strtoul(value,&value,0);
+-                      if (*value)
+-                              return 0;
+-                      if (*blocksize != 512 && *blocksize != 1024 && *blocksize != 2048
+-                          && *blocksize != 4096) {
+-                              printk ("AFFS: Invalid blocksize (512, 1024, 2048, 4096 allowed)\n");
+-                              return 0;
+-                      }
+-              } else if (!strcmp (this_char, "grpquota")
+-                       || !strcmp (this_char, "noquota")
+-                       || !strcmp (this_char, "quota")
+-                       || !strcmp (this_char, "usrquota"))
+-                       /* Silently ignore the quota options */
+-                      ;
+-              else {
+-                      printk("AFFS: Unrecognized mount option %s\n", this_char);
++                      break;
++              case Opt_protect:
++                      *mount_opts |= SF_IMMUTABLE;
++                      break;
++              case Opt_reserved:
++                      if (match_int(&args[0], reserved))
++                              return 1;
++                      break;
++              case Opt_root:
++                      if (match_int(&args[0], root))
++                              return 1;
++                      break;
++              case Opt_setgid:
++                      if (match_int(&args[0], &option))
++                              return 1;
++                      *gid = option;
++                      *mount_opts |= SF_SETGID;
++                      break;
++              case Opt_setuid:
++                      if (match_int(&args[0], &option))
++                              return -EINVAL;
++                      *uid = option;
++                      *mount_opts |= SF_SETUID;
++                      break;
++              case Opt_verbose:
++                      *mount_opts |= SF_VERBOSE;
++                      break;
++              case Opt_volume: {
++                      char *vol = match_strdup(&args[0]);
++                      strlcpy(volume, vol, 32);
++                      kfree(vol);
++                      break;
++              }
++              case Opt_ignore:
++                      /* Silently ignore the quota options */
++                      break;
++              default:
++                      printk("AFFS: Unrecognized mount option \"%s\" "
++                                      "or missing value\n", p);
+                       return 0;
+               }
+       }
+       return 1;
+-
+-out_no_arg:
+-      printk("AFFS: The %s option requires an argument\n", optn);
+-      return 0;
+-out_inv_arg:
+-      printk("AFFS: Option %s does not take an argument\n", optn);
+-      return 0;
+ }
+ /* This function definitely needs to be split up. Some fine day I'll
+--- linux-2.6.0-test6/fs/aio.c 2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/aio.c        2003-10-05 00:37:05.000000000 -0700
+@@ -27,6 +27,8 @@
+ #include <linux/aio.h>
+ #include <linux/highmem.h>
+ #include <linux/workqueue.h>
++#include <linux/writeback.h>
++#include <linux/pagemap.h>
+ #include <asm/kmap_types.h>
+ #include <asm/uaccess.h>
+@@ -38,6 +40,9 @@
+ #define dprintk(x...) do { ; } while (0)
+ #endif
++long aio_run = 0; /* for testing only */
++long aio_wakeups = 0; /* for testing only */
++
+ /*------ sysctl variables----*/
+ atomic_t aio_nr = ATOMIC_INIT(0);     /* current system wide number of aio requests */
+ unsigned aio_max_nr = 0x10000;        /* system wide maximum number of aio requests */
+@@ -47,6 +52,7 @@ static kmem_cache_t  *kiocb_cachep;
+ static kmem_cache_t   *kioctx_cachep;
+ static struct workqueue_struct *aio_wq;
++static struct workqueue_struct *aio_fput_wq;
+ /* Used for rare fput completion. */
+ static void aio_fput_routine(void *);
+@@ -74,6 +80,7 @@ static int __init aio_setup(void)
+               panic("unable to create kioctx cache");
+       aio_wq = create_workqueue("aio");
++      aio_fput_wq = create_workqueue("aio_fput");
+       pr_debug("aio_setup: sizeof(struct page) = %d\n", (int)sizeof(struct page));
+@@ -281,6 +288,7 @@ static void aio_cancel_all(struct kioctx
+               struct kiocb *iocb = list_kiocb(pos);
+               list_del_init(&iocb->ki_list);
+               cancel = iocb->ki_cancel;
++              kiocbSetCancelled(iocb);
+               if (cancel) {
+                       iocb->ki_users++;
+                       spin_unlock_irq(&ctx->ctx_lock);
+@@ -341,6 +349,11 @@ void exit_aio(struct mm_struct *mm)
+               aio_cancel_all(ctx);
+               wait_for_all_aios(ctx);
++              /*
++               * this is an overkill, but ensures we don't leave
++               * the ctx on the aio_wq
++               */
++              flush_workqueue(aio_wq);
+               if (1 != atomic_read(&ctx->users))
+                       printk(KERN_DEBUG
+@@ -395,6 +408,7 @@ static struct kiocb *__aio_get_req(struc
+       req->ki_cancel = NULL;
+       req->ki_retry = NULL;
+       req->ki_user_obj = NULL;
++      INIT_LIST_HEAD(&req->ki_run_list);
+       /* Check if the completion queue has enough free space to
+        * accept an event from this io.
+@@ -494,7 +508,7 @@ static int __aio_put_req(struct kioctx *
+               spin_lock(&fput_lock);
+               list_add(&req->ki_list, &fput_head);
+               spin_unlock(&fput_lock);
+-              queue_work(aio_wq, &fput_work);
++              queue_work(aio_fput_wq, &fput_work);
+       } else
+               really_put_req(ctx, req);
+       return 1;
+@@ -536,65 +550,307 @@ struct kioctx *lookup_ioctx(unsigned lon
+       return ioctx;
+ }
++/*
++ * use_mm
++ *    Makes the calling kernel thread take on the specified
++ *    mm context.
++ *    Called by the retry thread execute retries within the
++ *    iocb issuer's mm context, so that copy_from/to_user
++ *    operations work seamlessly for aio.
++ *    (Note: this routine is intended to be called only
++ *    from a kernel thread context)
++ */
+ static void use_mm(struct mm_struct *mm)
+ {
+-      struct mm_struct *active_mm = current->active_mm;
++      struct mm_struct *active_mm;
++      struct task_struct *tsk = current;
++
++      task_lock(tsk);
++      active_mm = tsk->active_mm;
+       atomic_inc(&mm->mm_count);
+-      current->mm = mm;
+-      if (mm != active_mm) {
+-              current->active_mm = mm;
+-              activate_mm(active_mm, mm);
+-      }
++      tsk->mm = mm;
++      tsk->active_mm = mm;
++      activate_mm(active_mm, mm);
++      task_unlock(tsk);
++
+       mmdrop(active_mm);
+ }
+-static void unuse_mm(struct mm_struct *mm)
++/*
++ * unuse_mm
++ *    Reverses the effect of use_mm, i.e. releases the
++ *    specified mm context which was earlier taken on
++ *    by the calling kernel thread
++ *    (Note: this routine is intended to be called only
++ *    from a kernel thread context)
++ *
++ * Comments: Called with ctx->ctx_lock held. This nests
++ * task_lock instead ctx_lock.
++ */
++void unuse_mm(struct mm_struct *mm)
+ {
+-      current->mm = NULL;
++      struct task_struct *tsk = current;
++
++      task_lock(tsk);
++      tsk->mm = NULL;
+       /* active_mm is still 'mm' */
+-      enter_lazy_tlb(mm, current);
++      enter_lazy_tlb(mm, tsk);
++      task_unlock(tsk);
+ }
+-/* Run on kevent's context.  FIXME: needs to be per-cpu and warn if an
+- * operation blocks.
++/*
++ * Queue up a kiocb to be retried. Assumes that the kiocb
++ * has already been marked as kicked, and places it on
++ * the retry run list for the corresponding ioctx, if it
++ * isn't already queued. Returns 1 if it actually queued
++ * the kiocb (to tell the caller to activate the work
++ * queue to process it), or 0, if it found that it was
++ * already queued.
++ *
++ * Should be called with the spin lock iocb->ki_ctx->ctx_lock
++ * held
+  */
+-static void aio_kick_handler(void *data)
++static inline int __queue_kicked_iocb(struct kiocb *iocb)
+ {
+-      struct kioctx *ctx = data;
++      struct kioctx   *ctx = iocb->ki_ctx;
+-      use_mm(ctx->mm);
++      if (list_empty(&iocb->ki_run_list)) {
++              list_add_tail(&iocb->ki_run_list,
++                      &ctx->run_list);
++              iocb->ki_queued++;
++              return 1;
++      }
++      return 0;
++}
+-      spin_lock_irq(&ctx->ctx_lock);
+-      while (!list_empty(&ctx->run_list)) {
+-              struct kiocb *iocb;
+-              long ret;
++/* aio_run_iocb
++ *     This is the core aio execution routine. It is
++ *     invoked both for initial i/o submission and
++ *     subsequent retries via the aio_kick_handler.
++ *       Expects to be invoked with iocb->ki_ctx->lock
++ *       already held. The lock is released and reaquired
++ *       as needed during processing.
++ *
++ * Calls the iocb retry method (already setup for the
++ * iocb on initial submission) for operation specific
++ * handling, but takes care of most of common retry
++ * execution details for a given iocb. The retry method
++ * needs to be non-blocking as far as possible, to avoid
++ * holding up other iocbs waiting to be serviced by the
++ * retry kernel thread.
++ *
++ * The trickier parts in this code have to do with
++ * ensuring that only one retry instance is in progress
++ * for a given iocb at any time. Providing that guarantee
++ * simplifies the coding of individual aio operations as
++ * it avoids various potential races.
++ */
++static ssize_t aio_run_iocb(struct kiocb *iocb)
++{
++      struct kioctx   *ctx = iocb->ki_ctx;
++      ssize_t (*retry)(struct kiocb *);
++      ssize_t ret;
+-              iocb = list_entry(ctx->run_list.next, struct kiocb,
+-                                ki_run_list);
+-              list_del(&iocb->ki_run_list);
+-              iocb->ki_users ++;
+-              spin_unlock_irq(&ctx->ctx_lock);
++      if (iocb->ki_retried++ > 1024*1024) {
++              printk("Maximal retry count.  Bytes done %Zd\n",
++                      iocb->ki_nbytes - iocb->ki_left);
++              return -EAGAIN;
++      }
++
++      if (!(iocb->ki_retried & 0xff)) {
++              pr_debug("%ld retry: %d of %d (kick %ld, Q %ld run %ld, wake %ld)\n",
++                      iocb->ki_retried,
++                      iocb->ki_nbytes - iocb->ki_left, iocb->ki_nbytes,
++                      iocb->ki_kicked, iocb->ki_queued, aio_run, aio_wakeups);
++      }
++
++      if (!(retry = iocb->ki_retry)) {
++              printk("aio_run_iocb: iocb->ki_retry = NULL\n");
++              return 0;
++      }
++
++      /*
++       * We don't want the next retry iteration for this
++       * operation to start until this one has returned and
++       * updated the iocb state. However, wait_queue functions
++       * can trigger a kick_iocb from interrupt context in the
++       * meantime, indicating that data is available for the next
++       * iteration. We want to remember that and enable the
++       * next retry iteration _after_ we are through with
++       * this one.
++       *
++       * So, in order to be able to register a "kick", but
++       * prevent it from being queued now, we clear the kick
++       * flag, but make the kick code *think* that the iocb is
++       * still on the run list until we are actually done.
++       * When we are done with this iteration, we check if
++       * the iocb was kicked in the meantime and if so, queue
++       * it up afresh.
++       */
++
++      kiocbClearKicked(iocb);
++
++      /*
++       * This is so that aio_complete knows it doesn't need to
++       * pull the iocb off the run list (We can't just call
++       * INIT_LIST_HEAD because we don't want a kick_iocb to
++       * queue this on the run list yet)
++       */
++      iocb->ki_run_list.next = iocb->ki_run_list.prev = NULL;
++      iocb->ki_retry = NULL;
++      spin_unlock_irq(&ctx->ctx_lock);
++
++      /* Quit retrying if the i/o has been cancelled */
++      if (kiocbIsCancelled(iocb)) {
++              ret = -EINTR;
++              aio_complete(iocb, ret, 0);
++              /* must not access the iocb after this */
++              goto out;
++      }
++
++      /*
++       * Now we are all set to call the retry method in async
++       * context. By setting this thread's io_wait context
++       * to point to the wait queue entry inside the currently
++       * running iocb for the duration of the retry, we ensure
++       * that async notification wakeups are queued by the
++       * operation instead of blocking waits, and when notified,
++       * cause the iocb to be kicked for continuation (through
++       * the aio_wake_function callback).
++       */
++      BUG_ON(current->io_wait != NULL);
++      current->io_wait = &iocb->ki_wait;
++      ret = retry(iocb);
++      current->io_wait = NULL;
+-              kiocbClearKicked(iocb);
+-              ret = iocb->ki_retry(iocb);
++      if (-EIOCBRETRY != ret) {
+               if (-EIOCBQUEUED != ret) {
++                      BUG_ON(!list_empty(&iocb->ki_wait.task_list));
+                       aio_complete(iocb, ret, 0);
+-                      iocb = NULL;
++                      /* must not access the iocb after this */
+               }
++      } else {
++              /*
++               * Issue an additional retry to avoid waiting forever if
++               * no waits were queued (e.g. in case of a short read).
++               */
++              if (list_empty(&iocb->ki_wait.task_list))
++                      kiocbSetKicked(iocb);
++      }
++out:
++      spin_lock_irq(&ctx->ctx_lock);
+-              spin_lock_irq(&ctx->ctx_lock);
+-              if (NULL != iocb)
+-                      __aio_put_req(ctx, iocb);
++      if (-EIOCBRETRY == ret) {
++              /*
++               * OK, now that we are done with this iteration
++               * and know that there is more left to go,
++               * this is where we let go so that a subsequent
++               * "kick" can start the next iteration
++               */
++              iocb->ki_retry = retry;
++              /* will make __queue_kicked_iocb succeed from here on */
++              INIT_LIST_HEAD(&iocb->ki_run_list);
++              /* we must queue the next iteration ourselves, if it
++               * has already been kicked */
++              if (kiocbIsKicked(iocb)) {
++                      __queue_kicked_iocb(iocb);
++              }
+       }
++      return ret;
++}
++
++/*
++ * __aio_run_iocbs:
++ *    Process all pending retries queued on the ioctx
++ *    run list.
++ * Assumes it is operating within the aio issuer's mm
++ * context. Expects to be called with ctx->ctx_lock held
++ */
++static void __aio_run_iocbs(struct kioctx *ctx)
++{
++      struct kiocb *iocb;
++      int count = 0;
++
++      while (!list_empty(&ctx->run_list)) {
++              iocb = list_entry(ctx->run_list.next, struct kiocb,
++                      ki_run_list);
++              list_del(&iocb->ki_run_list);
++              /*
++               * Hold an extra reference while retrying i/o.
++               */
++              iocb->ki_users++;       /* grab extra reference */
++              aio_run_iocb(iocb);
++              if (__aio_put_req(ctx, iocb))  /* drop extra ref */
++                      put_ioctx(ctx);
++              count++;
++      }
++      aio_run++;
++}
++
++/*
++ * aio_run_iocbs:
++ *    Process all pending retries queued on the ioctx
++ *    run list.
++ * Assumes it is operating within the aio issuer's mm
++ * context.
++ */
++static inline void aio_run_iocbs(struct kioctx *ctx)
++{
++      spin_lock_irq(&ctx->ctx_lock);
++      __aio_run_iocbs(ctx);
+       spin_unlock_irq(&ctx->ctx_lock);
++}
++
++/*
++ * aio_kick_handler:
++ *    Work queue handler triggered to process pending
++ *    retries on an ioctx. Takes on the aio issuer's
++ *    mm context before running the iocbs.
++ * Run on aiod's context.
++ */
++static void aio_kick_handler(void *data)
++{
++      struct kioctx *ctx = data;
++      use_mm(ctx->mm);
++      spin_lock_irq(&ctx->ctx_lock);
++      __aio_run_iocbs(ctx);
+       unuse_mm(ctx->mm);
++      spin_unlock_irq(&ctx->ctx_lock);
+ }
+-void kick_iocb(struct kiocb *iocb)
++
++/*
++ * Called by kick_iocb to queue the kiocb for retry
++ * and if required activate the aio work queue to process
++ * it
++ */
++void queue_kicked_iocb(struct kiocb *iocb)
+ {
+       struct kioctx   *ctx = iocb->ki_ctx;
++      unsigned long flags;
++      int run = 0;
++      WARN_ON((!list_empty(&iocb->ki_wait.task_list)));
++
++      spin_lock_irqsave(&ctx->ctx_lock, flags);
++      run = __queue_kicked_iocb(iocb);
++      spin_unlock_irqrestore(&ctx->ctx_lock, flags);
++      if (run) {
++              queue_work(aio_wq, &ctx->wq);
++              aio_wakeups++;
++      }
++}
++
++/*
++ * kick_iocb:
++ *    Called typically from a wait queue callback context
++ *    (aio_wake_function) to trigger a retry of the iocb.
++ *    The retry is usually executed by aio workqueue
++ *    threads (See aio_kick_handler).
++ */
++void kick_iocb(struct kiocb *iocb)
++{
+       /* sync iocbs are easy: they can only ever be executing from a 
+        * single context. */
+       if (is_sync_kiocb(iocb)) {
+@@ -603,12 +859,10 @@ void kick_iocb(struct kiocb *iocb)
+               return;
+       }
++      iocb->ki_kicked++;
++      /* If its already kicked we shouldn't queue it again */
+       if (!kiocbTryKick(iocb)) {
+-              unsigned long flags;
+-              spin_lock_irqsave(&ctx->ctx_lock, flags);
+-              list_add_tail(&iocb->ki_run_list, &ctx->run_list);
+-              spin_unlock_irqrestore(&ctx->ctx_lock, flags);
+-              schedule_work(&ctx->wq);
++              queue_kicked_iocb(iocb);
+       }
+ }
+@@ -661,6 +915,9 @@ int aio_complete(struct kiocb *iocb, lon
+        */
+       spin_lock_irqsave(&ctx->ctx_lock, flags);
++      if (iocb->ki_run_list.prev && !list_empty(&iocb->ki_run_list))
++              list_del_init(&iocb->ki_run_list);
++
+       ring = kmap_atomic(info->ring_pages[0], KM_IRQ1);
+       tail = info->tail;
+@@ -689,6 +946,11 @@ int aio_complete(struct kiocb *iocb, lon
+       pr_debug("added to ring %p at [%lu]\n", iocb, tail);
++      pr_debug("%ld retries: %d of %d (kicked %ld, Q %ld run %ld wake %ld)\n",
++              iocb->ki_retried,
++              iocb->ki_nbytes - iocb->ki_left, iocb->ki_nbytes,
++              iocb->ki_kicked, iocb->ki_queued, aio_run, aio_wakeups);
++
+       /* everything turned out well, dispose of the aiocb. */
+       ret = __aio_put_req(ctx, iocb);
+@@ -803,6 +1065,7 @@ static int read_events(struct kioctx *ct
+       int                     i = 0;
+       struct io_event         ent;
+       struct timeout          to;
++      int                     event_loop = 0; /* testing only */
+       /* needed to zero any padding within an entry (there shouldn't be 
+        * any, but C is fun!
+@@ -852,7 +1115,6 @@ static int read_events(struct kioctx *ct
+               add_wait_queue_exclusive(&ctx->wait, &wait);
+               do {
+                       set_task_state(tsk, TASK_INTERRUPTIBLE);
+-
+                       ret = aio_read_evt(ctx, &ent);
+                       if (ret)
+                               break;
+@@ -862,6 +1124,7 @@ static int read_events(struct kioctx *ct
+                       if (to.timed_out)       /* Only check after read evt */
+                               break;
+                       schedule();
++                      event_loop++;
+                       if (signal_pending(tsk)) {
+                               ret = -EINTR;
+                               break;
+@@ -889,6 +1152,9 @@ static int read_events(struct kioctx *ct
+       if (timeout)
+               clear_timeout(&to);
+ out:
++      pr_debug("event loop executed %d times\n", event_loop);
++      pr_debug("aio_run %ld\n", aio_run);
++      pr_debug("aio_wakeups %ld\n", aio_wakeups);
+       return i ? i : ret;
+ }
+@@ -918,6 +1184,11 @@ static void io_destroy(struct kioctx *io
+       aio_cancel_all(ioctx);
+       wait_for_all_aios(ioctx);
++      /*
++       * this is an overkill, but ensures we don't leave
++       * the ctx on the aio_wq
++       */
++      flush_workqueue(aio_wq);
+       put_ioctx(ioctx);       /* once for the lookup */
+ }
+@@ -980,13 +1251,192 @@ asmlinkage long sys_io_destroy(aio_conte
+       return -EINVAL;
+ }
++/*
++ * Retry method for aio_read (also used for first time submit)
++ * Responsible for updating iocb state as retries progress
++ */
++static ssize_t aio_pread(struct kiocb *iocb)
++{
++      struct file *file = iocb->ki_filp;
++      ssize_t ret = 0;
++
++      ret = file->f_op->aio_read(iocb, iocb->ki_buf,
++              iocb->ki_left, iocb->ki_pos);
++
++      /*
++       * Can't just depend on iocb->ki_left to determine
++       * whether we are done. This may have been a short read.
++       */
++      if (ret > 0) {
++              iocb->ki_buf += ret;
++              iocb->ki_left -= ret;
++
++              ret = -EIOCBRETRY;
++      }
++
++      /* This means we must have transferred all that we could */
++      /* No need to retry anymore */
++      if ((ret == 0) || (iocb->ki_left == 0))
++              ret = iocb->ki_nbytes - iocb->ki_left;
++
++      return ret;
++}
++
++/*
++ * Retry method for aio_write (also used for first time submit)
++ * Responsible for updating iocb state as retries progress
++ */
++static ssize_t aio_pwrite(struct kiocb *iocb)
++{
++      struct file *file = iocb->ki_filp;
++      struct address_space *mapping = file->f_mapping;
++      struct inode *inode = mapping->host;
++      ssize_t ret = 0;
++
++      ret = file->f_op->aio_write(iocb, iocb->ki_buf,
++                              iocb->ki_left, iocb->ki_pos);
++
++      /*
++       * Even if iocb->ki_left = 0, we may need to wait
++       * for a balance_dirty_pages to complete
++       */
++      if (ret > 0) {
++              iocb->ki_buf += iocb->ki_buf ? ret : 0;
++              iocb->ki_left -= ret;
++
++              ret = -EIOCBRETRY;
++      }
++
++      /* This means we must have transferred all that we could */
++      /* No need to retry anymore unless we need to osync data */
++      if (ret == 0) {
++              ret = iocb->ki_nbytes - iocb->ki_left;
++              if (!iocb->ki_buf)
++                      return ret;
++
++              /* Set things up for potential O_SYNC */
++              if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) {
++                      iocb->ki_buf = NULL;
++                      iocb->ki_pos -= ret; /* back up fpos */
++                      iocb->ki_left = ret; /* sync what we have written out */
++                      iocb->ki_nbytes = ret;
++                      ret = -EIOCBRETRY;
++              }
++      }
++
++      return ret;
++}
++
++static ssize_t aio_fdsync(struct kiocb *iocb)
++{
++      struct file *file = iocb->ki_filp;
++      ssize_t ret = -EINVAL;
++
++      if (file->f_op->aio_fsync)
++              ret = file->f_op->aio_fsync(iocb, 1);
++      return ret;
++}
++
++static ssize_t aio_fsync(struct kiocb *iocb)
++{
++      struct file *file = iocb->ki_filp;
++      ssize_t ret = -EINVAL;
++
++      if (file->f_op->aio_fsync)
++              ret = file->f_op->aio_fsync(iocb, 0);
++      return ret;
++}
++
++/*
++ * aio_setup_iocb:
++ *    Performs the initial checks and aio retry method
++ *    setup for the kiocb at the time of io submission.
++ */
++ssize_t aio_setup_iocb(struct kiocb *kiocb)
++{
++      struct file *file = kiocb->ki_filp;
++      ssize_t ret = 0;
++
++      switch (kiocb->ki_opcode) {
++      case IOCB_CMD_PREAD:
++              ret = -EBADF;
++              if (unlikely(!(file->f_mode & FMODE_READ)))
++                      break;
++              ret = -EFAULT;
++              if (unlikely(!access_ok(VERIFY_WRITE, kiocb->ki_buf,
++                      kiocb->ki_left)))
++                      break;
++              ret = -EINVAL;
++              if (file->f_op->aio_read)
++                      kiocb->ki_retry = aio_pread;
++              break;
++      case IOCB_CMD_PWRITE:
++              ret = -EBADF;
++              if (unlikely(!(file->f_mode & FMODE_WRITE)))
++                      break;
++              ret = -EFAULT;
++              if (unlikely(!access_ok(VERIFY_READ, kiocb->ki_buf,
++                      kiocb->ki_left)))
++                      break;
++              ret = -EINVAL;
++              if (file->f_op->aio_write)
++                      kiocb->ki_retry = aio_pwrite;
++              break;
++      case IOCB_CMD_FDSYNC:
++              ret = -EINVAL;
++              if (file->f_op->aio_fsync)
++                      kiocb->ki_retry = aio_fdsync;
++              break;
++      case IOCB_CMD_FSYNC:
++              ret = -EINVAL;
++              if (file->f_op->aio_fsync)
++                      kiocb->ki_retry = aio_fsync;
++              break;
++      default:
++              dprintk("EINVAL: io_submit: no operation provided\n");
++              ret = -EINVAL;
++      }
++
++      if (!kiocb->ki_retry)
++              return ret;
++
++      return 0;
++}
++
++/*
++ * aio_wake_function:
++ *    wait queue callback function for aio notification,
++ *    Simply triggers a retry of the operation via kick_iocb.
++ *
++ *    This callback is specified in the wait queue entry in
++ *    a kiocb (current->io_wait points to this wait queue
++ *    entry when an aio operation executes; it is used
++ *    instead of a synchronous wait when an i/o blocking
++ *    condition is encountered during aio).
++ *
++ * Note:
++ * This routine is executed with the wait queue lock held.
++ * Since kick_iocb acquires iocb->ctx->ctx_lock, it nests
++ * the ioctx lock inside the wait queue lock. This is safe
++ * because this callback isn't used for wait queues which
++ * are nested inside ioctx lock (i.e. ctx->wait)
++ */
++int aio_wake_function(wait_queue_t *wait, unsigned mode, int sync)
++{
++      struct kiocb *iocb = container_of(wait, struct kiocb, ki_wait);
++
++      list_del_init(&wait->task_list);
++      kick_iocb(iocb);
++      return 1;
++}
++
+ int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
+                        struct iocb *iocb)
+ {
+       struct kiocb *req;
+       struct file *file;
+       ssize_t ret;
+-      char *buf;
++      int need_putctx;
+       /* enforce forwards compatibility on users */
+       if (unlikely(iocb->aio_reserved1 || iocb->aio_reserved2 ||
+@@ -1027,51 +1477,41 @@ int io_submit_one(struct kioctx *ctx, st
+       req->ki_user_data = iocb->aio_data;
+       req->ki_pos = iocb->aio_offset;
+-      buf = (char *)(unsigned long)iocb->aio_buf;
++      req->ki_buf = (char *)(unsigned long)iocb->aio_buf;
++      req->ki_left = req->ki_nbytes = iocb->aio_nbytes;
++      req->ki_opcode = iocb->aio_lio_opcode;
++      init_waitqueue_func_entry(&req->ki_wait, aio_wake_function);
++      INIT_LIST_HEAD(&req->ki_wait.task_list);
++      req->ki_run_list.next = req->ki_run_list.prev = NULL;
++      req->ki_retry = NULL;
++      req->ki_retried = 0;
++      req->ki_kicked = 0;
++      req->ki_queued = 0;
++      aio_run = 0;
++      aio_wakeups = 0;
+-      switch (iocb->aio_lio_opcode) {
+-      case IOCB_CMD_PREAD:
+-              ret = -EBADF;
+-              if (unlikely(!(file->f_mode & FMODE_READ)))
+-                      goto out_put_req;
+-              ret = -EFAULT;
+-              if (unlikely(!access_ok(VERIFY_WRITE, buf, iocb->aio_nbytes)))
+-                      goto out_put_req;
+-              ret = -EINVAL;
+-              if (file->f_op->aio_read)
+-                      ret = file->f_op->aio_read(req, buf,
+-                                      iocb->aio_nbytes, req->ki_pos);
+-              break;
+-      case IOCB_CMD_PWRITE:
+-              ret = -EBADF;
+-              if (unlikely(!(file->f_mode & FMODE_WRITE)))
+-                      goto out_put_req;
+-              ret = -EFAULT;
+-              if (unlikely(!access_ok(VERIFY_READ, buf, iocb->aio_nbytes)))
+-                      goto out_put_req;
+-              ret = -EINVAL;
+-              if (file->f_op->aio_write)
+-                      ret = file->f_op->aio_write(req, buf,
+-                                      iocb->aio_nbytes, req->ki_pos);
+-              break;
+-      case IOCB_CMD_FDSYNC:
+-              ret = -EINVAL;
+-              if (file->f_op->aio_fsync)
+-                      ret = file->f_op->aio_fsync(req, 1);
+-              break;
+-      case IOCB_CMD_FSYNC:
+-              ret = -EINVAL;
+-              if (file->f_op->aio_fsync)
+-                      ret = file->f_op->aio_fsync(req, 0);
+-              break;
+-      default:
+-              dprintk("EINVAL: io_submit: no operation provided\n");
+-              ret = -EINVAL;
+-      }
++      ret = aio_setup_iocb(req);
++
++      if (ret)
++              goto out_put_req;
++
++      spin_lock_irq(&ctx->ctx_lock);
++      /*
++       * Hold an extra reference while submitting the i/o.
++       * This prevents races between the aio code path referencing the
++       * req (after submitting it) and aio_complete() freeing the req.
++       */
++      req->ki_users++;                        /* grab extra reference */
++      ret = aio_run_iocb(req);
++      need_putctx = __aio_put_req(ctx, req);  /* drop the extra reference */
++      spin_unlock_irq(&ctx->ctx_lock);
++
++      if (-EIOCBRETRY == ret)
++              queue_work(aio_wq, &ctx->wq);
++
++      if (need_putctx)
++              put_ioctx(ctx);
+-      if (likely(-EIOCBQUEUED == ret))
+-              return 0;
+-      aio_complete(req, ret, 0);
+       return 0;
+ out_put_req:
+--- linux-2.6.0-test6/fs/autofs4/inode.c       2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/autofs4/inode.c      2003-10-05 00:33:24.000000000 -0700
+@@ -14,6 +14,7 @@
+ #include <linux/slab.h>
+ #include <linux/file.h>
+ #include <linux/pagemap.h>
++#include <linux/parser.h>
+ #include <asm/bitops.h>
+ #include "autofs_i.h"
+ #include <linux/module.h>
+@@ -94,11 +95,25 @@ static struct super_operations autofs4_s
+       .statfs         = simple_statfs,
+ };
++enum {Opt_err, Opt_fd, Opt_uid, Opt_gid, Opt_pgrp, Opt_minproto, Opt_maxproto};
++
++static match_table_t tokens = {
++      {Opt_fd, "fd=%d"},
++      {Opt_uid, "uid=%d"},
++      {Opt_gid, "gid=%d"},
++      {Opt_pgrp, "pgrp=%d"},
++      {Opt_minproto, "minproto=%d"},
++      {Opt_maxproto, "maxproto=%d"},
++      {Opt_err, NULL}
++};
++
+ static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid,
+                        pid_t *pgrp, int *minproto, int *maxproto)
+ {
+-      char *this_char, *value;
+-      
++      char *p;
++      substring_t args[MAX_OPT_ARGS];
++      int option;
++
+       *uid = current->uid;
+       *gid = current->gid;
+       *pgrp = process_group(current);
+@@ -108,55 +123,48 @@ static int parse_options(char *options, 
+       *pipefd = -1;
+-      if ( !options ) return 1;
+-      while ((this_char = strsep(&options,",")) != NULL) {
+-              if (!*this_char)
++      if (!options)
++              return 1;
++
++      while ((p = strsep(&options, ",")) != NULL) {
++              int token;
++              if (!*p)
+                       continue;
+-              if ((value = strchr(this_char,'=')) != NULL)
+-                      *value++ = 0;
+-              if (!strcmp(this_char,"fd")) {
+-                      if (!value || !*value)
+-                              return 1;
+-                      *pipefd = simple_strtoul(value,&value,0);
+-                      if (*value)
+-                              return 1;
+-              }
+-              else if (!strcmp(this_char,"uid")) {
+-                      if (!value || !*value)
+-                              return 1;
+-                      *uid = simple_strtoul(value,&value,0);
+-                      if (*value)
+-                              return 1;
+-              }
+-              else if (!strcmp(this_char,"gid")) {
+-                      if (!value || !*value)
+-                              return 1;
+-                      *gid = simple_strtoul(value,&value,0);
+-                      if (*value)
+-                              return 1;
+-              }
+-              else if (!strcmp(this_char,"pgrp")) {
+-                      if (!value || !*value)
+-                              return 1;
+-                      *pgrp = simple_strtoul(value,&value,0);
+-                      if (*value)
+-                              return 1;
+-              }
+-              else if (!strcmp(this_char,"minproto")) {
+-                      if (!value || !*value)
+-                              return 1;
+-                      *minproto = simple_strtoul(value,&value,0);
+-                      if (*value)
+-                              return 1;
+-              }
+-              else if (!strcmp(this_char,"maxproto")) {
+-                      if (!value || !*value)
+-                              return 1;
+-                      *maxproto = simple_strtoul(value,&value,0);
+-                      if (*value)
+-                              return 1;
++
++              token = match_token(p, tokens, args);
++              switch (token) {
++              case Opt_fd:
++                      if (match_int(args, pipefd))
++                              return 1;
++                      break;
++              case Opt_uid:
++                      if (match_int(args, &option))
++                              return 1;
++                      *uid = option;
++                      break;
++              case Opt_gid:
++                      if (match_int(args, &option))
++                              return 1;
++                      *gid = option;
++                      break;
++              case Opt_pgrp:
++                      if (match_int(args, &option))
++                              return 1;
++                      *pgrp = option;
++                      break;
++              case Opt_minproto:
++                      if (match_int(args, &option))
++                              return 1;
++                      *minproto = option;
++                      break;
++              case Opt_maxproto:
++                      if (match_int(args, &option))
++                              return 1;
++                      *maxproto = option;
++                      break;
++              default:
++                      return 1;
+               }
+-              else break;
+       }
+       return (*pipefd < 0);
+ }
+--- linux-2.6.0-test6/fs/autofs/inode.c        2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/autofs/inode.c       2003-10-05 00:33:24.000000000 -0700
+@@ -14,6 +14,7 @@
+ #include <linux/mm.h>
+ #include <linux/slab.h>
+ #include <linux/file.h>
++#include <linux/parser.h>
+ #include <asm/bitops.h>
+ #include "autofs_i.h"
+ #include <linux/module.h>
+@@ -45,10 +46,24 @@ static struct super_operations autofs_so
+       .statfs         = simple_statfs,
+ };
++enum {Opt_err, Opt_fd, Opt_uid, Opt_gid, Opt_pgrp, Opt_minproto, Opt_maxproto};
++
++static match_table_t autofs_tokens = {
++      {Opt_fd, "fd=%d"},
++      {Opt_uid, "uid=%d"},
++      {Opt_gid, "gid=%d"},
++      {Opt_pgrp, "pgrp=%d"},
++      {Opt_minproto, "minproto=%d"},
++      {Opt_maxproto, "maxproto=%d"},
++      {Opt_err, NULL}
++};
++
+ static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, pid_t *pgrp, int *minproto, int *maxproto)
+ {
+-      char *this_char, *value;
+-      
++      char *p;
++      substring_t args[MAX_OPT_ARGS];
++      int option;
++
+       *uid = current->uid;
+       *gid = current->gid;
+       *pgrp = process_group(current);
+@@ -57,55 +72,49 @@ static int parse_options(char *options, 
+       *pipefd = -1;
+-      if ( !options ) return 1;
+-      while ((this_char = strsep(&options,",")) != NULL) {
+-              if (!*this_char)
++      if (!options)
++              return 1;
++
++      while ((p = strsep(&options, ",")) != NULL) {
++              int token;
++              if (!*p)
+                       continue;
+-              if ((value = strchr(this_char,'=')) != NULL)
+-                      *value++ = 0;
+-              if (!strcmp(this_char,"fd")) {
+-                      if (!value || !*value)
+-                              return 1;
+-                      *pipefd = simple_strtoul(value,&value,0);
+-                      if (*value)
+-                              return 1;
+-              }
+-              else if (!strcmp(this_char,"uid")) {
+-                      if (!value || !*value)
+-                              return 1;
+-                      *uid = simple_strtoul(value,&value,0);
+-                      if (*value)
+-                              return 1;
+-              }
+-              else if (!strcmp(this_char,"gid")) {
+-                      if (!value || !*value)
+-                              return 1;
+-                      *gid = simple_strtoul(value,&value,0);
+-                      if (*value)
+-                              return 1;
+-              }
+-              else if (!strcmp(this_char,"pgrp")) {
+-                      if (!value || !*value)
+-                              return 1;
+-                      *pgrp = simple_strtoul(value,&value,0);
+-                      if (*value)
+-                              return 1;
+-              }
+-              else if (!strcmp(this_char,"minproto")) {
+-                      if (!value || !*value)
+-                              return 1;
+-                      *minproto = simple_strtoul(value,&value,0);
+-                      if (*value)
+-                              return 1;
+-              }
+-              else if (!strcmp(this_char,"maxproto")) {
+-                      if (!value || !*value)
+-                              return 1;
+-                      *maxproto = simple_strtoul(value,&value,0);
+-                      if (*value)
+-                              return 1;
++
++              token = match_token(p, autofs_tokens, args);
++              switch (token) {
++              case Opt_fd:
++                      if (match_int(&args[0], &option))
++                              return 1;
++                      *pipefd = option;
++                      break;
++              case Opt_uid:
++                      if (match_int(&args[0], &option))
++                              return 1;
++                      *uid = option;
++                      break;
++              case Opt_gid:
++                      if (match_int(&args[0], &option))
++                              return 1;
++                      *gid = option;
++                      break;
++              case Opt_pgrp:
++                      if (match_int(&args[0], &option))
++                              return 1;
++                      *pgrp = option;
++                      break;
++              case Opt_minproto:
++                      if (match_int(&args[0], &option))
++                              return 1;
++                      *minproto = option;
++                      break;
++              case Opt_maxproto:
++                      if (match_int(&args[0], &option))
++                              return 1;
++                      *maxproto = option;
++                      break;
++              default:
++                      return 1;
+               }
+-              else break;
+       }
+       return (*pipefd < 0);
+ }
+--- linux-2.6.0-test6/fs/befs/linuxvfs.c       2003-07-10 18:50:31.000000000 -0700
++++ 25/fs/befs/linuxvfs.c      2003-10-05 00:33:24.000000000 -0700
+@@ -13,6 +13,7 @@
+ #include <linux/nls.h>
+ #include <linux/buffer_head.h>
+ #include <linux/vfs.h>
++#include <linux/parser.h>
+ #include "befs.h"
+ #include "btree.h"
+@@ -39,7 +40,7 @@ static struct inode *befs_alloc_inode(st
+ static void befs_destroy_inode(struct inode *inode);
+ static int befs_init_inodecache(void);
+ static void befs_destroy_inodecache(void);
+-static int befs_readlink(struct dentry *, char *, int);
++static int befs_readlink(struct dentry *, char __user *, int);
+ static int befs_follow_link(struct dentry *, struct nameidata *nd);
+ static int befs_utf2nls(struct super_block *sb, const char *in, int in_len,
+                       char **out, int *out_len);
+@@ -494,7 +495,7 @@ befs_follow_link(struct dentry *dentry, 
+ }
+ static int
+-befs_readlink(struct dentry *dentry, char *buffer, int buflen)
++befs_readlink(struct dentry *dentry, char __user *buffer, int buflen)
+ {
+       struct super_block *sb = dentry->d_sb;
+       befs_inode_info *befs_ino = BEFS_I(dentry->d_inode);
+@@ -667,12 +668,27 @@ befs_nls2utf(struct super_block *sb, con
+       return -EILSEQ;
+ }
++/**
++ * Use the
++ *
++ */
++enum {
++      Opt_uid, Opt_gid, Opt_charset, Opt_debug,
++};
++
++static match_table_t befs_tokens = {
++      {Opt_uid, "uid=%d"},
++      {Opt_gid, "gid=%d"},
++      {Opt_charset, "iocharset=%s"},
++      {Opt_debug, "debug"}
++};
++
+ static int
+ parse_options(char *options, befs_mount_options * opts)
+ {
+-      char *this_char;
+-      char *value;
+-      int ret = 1;
++      char *p;
++      substring_t args[MAX_OPT_ARGS];
++      int option;
+       /* Initialize options */
+       opts->uid = 0;
+@@ -683,64 +699,56 @@ parse_options(char *options, befs_mount_
+       opts->debug = 0;
+       if (!options)
+-              return ret;
+-
+-      while ((this_char = strsep(&options, ",")) != NULL) {
+-
+-              if ((value = strchr(this_char, '=')) != NULL)
+-                      *value++ = 0;
++              return 1;
+-              if (!strcmp(this_char, "uid")) {
+-                      if (!value || !*value) {
+-                              ret = 0;
+-                      } else {
+-                              opts->uid = simple_strtoul(value, &value, 0);
+-                              opts->use_uid = 1;
+-                              if (*value) {
+-                                      printk(KERN_ERR "BEFS: Invalid uid "
+-                                             "option: %s\n", value);
+-                                      ret = 0;
+-                              }
++      while ((p = strsep(&options, ",")) != NULL) {
++              int token;
++              if (!*p)
++                      continue;
++
++              token = match_token(p, befs_tokens, args);
++              switch (token) {
++              case Opt_uid:
++                      if (match_int(&args[0], &option))
++                              return 0;
++                      if (option < 0) {
++                              printk(KERN_ERR "BeFS: Invalid uid %d, "
++                                              "using default\n", option);
++                              break;
+                       }
+-              } else if (!strcmp(this_char, "gid")) {
+-                      if (!value || !*value)
+-                              ret = 0;
+-                      else {
+-                              opts->gid = simple_strtoul(value, &value, 0);
+-                              opts->use_gid = 1;
+-                              if (*value) {
+-                                      printk(KERN_ERR
+-                                             "BEFS: Invalid gid option: "
+-                                             "%s\n", value);
+-                                      ret = 0;
+-                              }
++                      opts->uid = option;
++                      opts->use_uid = 1;
++                      break;
++              case Opt_gid:
++                      if (match_int(&args[0], &option))
++                              return 0;
++                      if (option < 0) {
++                              printk(KERN_ERR "BeFS: Invalid gid %d, "
++                                              "using default\n", option);
++                              break;
+                       }
+-              } else if (!strcmp(this_char, "iocharset") && value) {
+-                      char *p = value;
+-                      int len;
+-
+-                      while (*value && *value != ',')
+-                              value++;
+-                      len = value - p;
+-                      if (len) {
+-                              char *buffer = kmalloc(len + 1, GFP_NOFS);
+-                              if (buffer) {
+-                                      opts->iocharset = buffer;
+-                                      memcpy(buffer, p, len);
+-                                      buffer[len] = 0;
+-
+-                              } else {
+-                                      printk(KERN_ERR "BEFS: "
+-                                             "cannot allocate memory\n");
+-                                      ret = 0;
+-                              }
++                      opts->gid = option;
++                      opts->use_gid = 1;
++                      break;
++              case Opt_charset:
++                      kfree(opts->iocharset);
++                      opts->iocharset = match_strdup(&args[0]);
++                      if (!opts->iocharset) {
++                              printk(KERN_ERR "BeFS: allocation failure for "
++                                              "iocharset string\n");
++                              return 0;
+                       }
+-              } else if (!strcmp(this_char, "debug")) {
++                      break;
++              case Opt_debug:
+                       opts->debug = 1;
++                      break;
++              default:
++                      printk(KERN_ERR "BeFS: Unrecognized mount option \"%s\" "
++                                      "or missing value\n", p);
++                      return 0;
+               }
+       }
+-
+-      return ret;
++      return 1;
+ }
+ /* This function has the responsibiltiy of getting the
+@@ -939,9 +947,19 @@ init_befs_fs(void)
+       err = befs_init_inodecache();
+       if (err)
+-              return err;
++              goto unaquire_none;
++
++      err = register_filesystem(&befs_fs_type);
++      if (err)
++              goto unaquire_inodecache;
++
++      return 0;
++
++unaquire_inodecache:
++      befs_destroy_inodecache();
+-      return register_filesystem(&befs_fs_type);
++unaquire_none:
++      return err;
+ }
+ static void __exit
+--- linux-2.6.0-test6/fs/binfmt_elf.c  2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/binfmt_elf.c 2003-10-05 00:36:15.000000000 -0700
+@@ -134,7 +134,7 @@ create_elf_tables(struct linux_binprm *b
+       elf_addr_t *sp, *u_platform;
+       const char *k_platform = ELF_PLATFORM;
+       int items;
+-      elf_addr_t elf_info[40];
++      elf_addr_t *elf_info;
+       int ei_index = 0;
+       struct task_struct *tsk = current;
+@@ -169,6 +169,7 @@ create_elf_tables(struct linux_binprm *b
+       }
+       /* Create the ELF interpreter info */
++      elf_info = (elf_addr_t *) current->mm->saved_auxv;
+ #define NEW_AUX_ENT(id, val) \
+       do { elf_info[ei_index++] = id; elf_info[ei_index++] = val; } while (0)
+@@ -196,8 +197,13 @@ create_elf_tables(struct linux_binprm *b
+       if (k_platform) {
+               NEW_AUX_ENT(AT_PLATFORM, (elf_addr_t)(long)u_platform);
+       }
+-      NEW_AUX_ENT(AT_NULL, 0);
+ #undef NEW_AUX_ENT
++      /* AT_NULL is zero; clear the rest too */
++      memset(&elf_info[ei_index], 0,
++             sizeof current->mm->saved_auxv - ei_index * sizeof elf_info[0]);
++
++      /* And advance past the AT_NULL entry.  */
++      ei_index += 2;
+       sp = STACK_ADD(p, ei_index);
+@@ -1078,7 +1084,7 @@ static void fill_prstatus(struct elf_prs
+       prstatus->pr_pid = p->pid;
+       prstatus->pr_ppid = p->parent->pid;
+       prstatus->pr_pgrp = process_group(p);
+-      prstatus->pr_sid = p->session;
++      prstatus->pr_sid = process_session(p);
+       jiffies_to_timeval(p->utime, &prstatus->pr_utime);
+       jiffies_to_timeval(p->stime, &prstatus->pr_stime);
+       jiffies_to_timeval(p->cutime, &prstatus->pr_cutime);
+@@ -1106,7 +1112,7 @@ static void fill_psinfo(struct elf_prpsi
+       psinfo->pr_pid = p->pid;
+       psinfo->pr_ppid = p->parent->pid;
+       psinfo->pr_pgrp = process_group(p);
+-      psinfo->pr_sid = p->session;
++      psinfo->pr_sid = process_session(p);
+       i = p->state ? ffz(~p->state) + 1 : 0;
+       psinfo->pr_state = i;
+@@ -1186,7 +1192,7 @@ static int elf_dump_thread_status(long s
+  */
+ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file)
+ {
+-#define       NUM_NOTES       5
++#define       NUM_NOTES       6
+       int has_dumped = 0;
+       mm_segment_t fs;
+       int segs;
+@@ -1196,7 +1202,7 @@ static int elf_core_dump(long signr, str
+       struct elfhdr *elf = NULL;
+       off_t offset = 0, dataoff;
+       unsigned long limit = current->rlim[RLIMIT_CORE].rlim_cur;
+-      int numnote = NUM_NOTES;
++      int numnote;
+       struct memelfnote *notes = NULL;
+       struct elf_prstatus *prstatus = NULL;   /* NT_PRSTATUS */
+       struct elf_prpsinfo *psinfo = NULL;     /* NT_PRPSINFO */
+@@ -1208,6 +1214,7 @@ static int elf_core_dump(long signr, str
+       elf_fpxregset_t *xfpu = NULL;
+ #endif
+       int thread_status_size = 0;
++      elf_addr_t *auxv;
+       /*
+        * We no longer stop all VM operations.
+@@ -1287,18 +1294,25 @@ static int elf_core_dump(long signr, str
+       
+       fill_note(notes +2, "CORE", NT_TASKSTRUCT, sizeof(*current), current);
+   
++      numnote = 3;
++
++      auxv = (elf_addr_t *) current->mm->saved_auxv;
++
++      i = 0;
++      do
++              i += 2;
++      while (auxv[i - 2] != AT_NULL);
++      fill_note(&notes[numnote++], "CORE", NT_AUXV,
++                i * sizeof (elf_addr_t), auxv);
++
+       /* Try to dump the FPU. */
+       if ((prstatus->pr_fpvalid = elf_core_copy_task_fpregs(current, regs, fpu)))
+-              fill_note(notes +3, "CORE", NT_PRFPREG, sizeof(*fpu), fpu);
+-      else
+-              --numnote;
++              fill_note(notes + numnote++,
++                        "CORE", NT_PRFPREG, sizeof(*fpu), fpu);
+ #ifdef ELF_CORE_COPY_XFPREGS
+       if (elf_core_copy_task_xfpregs(current, xfpu))
+-              fill_note(notes +4, "LINUX", NT_PRXFPREG, sizeof(*xfpu), xfpu);
+-      else
+-              --numnote;
+-#else
+-      numnote--;
++              fill_note(notes + numnote++,
++                        "LINUX", NT_PRXFPREG, sizeof(*xfpu), xfpu);
+ #endif        
+   
+       fs = get_fs();
+--- linux-2.6.0-test6/fs/block_dev.c   2003-09-08 13:58:58.000000000 -0700
++++ 25/fs/block_dev.c  2003-10-05 00:34:12.000000000 -0700
+@@ -25,6 +25,22 @@
+ #include <linux/namei.h>
+ #include <asm/uaccess.h>
++struct bdev_inode {
++      struct block_device bdev;
++      struct inode vfs_inode;
++};
++
++static inline struct bdev_inode *BDEV_I(struct inode *inode)
++{
++      return container_of(inode, struct bdev_inode, vfs_inode);
++}
++
++inline struct block_device *I_BDEV(struct inode *inode)
++{
++      return &BDEV_I(inode)->bdev;
++}
++
++EXPORT_SYMBOL(I_BDEV);
+ static sector_t max_block(struct block_device *bdev)
+ {
+@@ -70,6 +86,8 @@ int set_blocksize(struct block_device *b
+       return 0;
+ }
++EXPORT_SYMBOL(set_blocksize);
++
+ int sb_set_blocksize(struct super_block *sb, int size)
+ {
+       int bits;
+@@ -82,6 +100,8 @@ int sb_set_blocksize(struct super_block 
+       return sb->s_blocksize;
+ }
++EXPORT_SYMBOL(sb_set_blocksize);
++
+ int sb_min_blocksize(struct super_block *sb, int size)
+ {
+       int minsize = bdev_hardsect_size(sb->s_bdev);
+@@ -90,14 +110,16 @@ int sb_min_blocksize(struct super_block 
+       return sb_set_blocksize(sb, size);
+ }
++EXPORT_SYMBOL(sb_min_blocksize);
++
+ static int
+ blkdev_get_block(struct inode *inode, sector_t iblock,
+               struct buffer_head *bh, int create)
+ {
+-      if (iblock >= max_block(inode->i_bdev))
++      if (iblock >= max_block(I_BDEV(inode)))
+               return -EIO;
+-      bh->b_bdev = inode->i_bdev;
++      bh->b_bdev = I_BDEV(inode);
+       bh->b_blocknr = iblock;
+       set_buffer_mapped(bh);
+       return 0;
+@@ -107,10 +129,10 @@ static int
+ blkdev_get_blocks(struct inode *inode, sector_t iblock,
+               unsigned long max_blocks, struct buffer_head *bh, int create)
+ {
+-      if ((iblock + max_blocks) > max_block(inode->i_bdev))
++      if ((iblock + max_blocks) > max_block(I_BDEV(inode)))
+               return -EIO;
+-      bh->b_bdev = inode->i_bdev;
++      bh->b_bdev = I_BDEV(inode);
+       bh->b_blocknr = iblock;
+       bh->b_size = max_blocks << inode->i_blkbits;
+       set_buffer_mapped(bh);
+@@ -122,9 +144,9 @@ blkdev_direct_IO(int rw, struct kiocb *i
+                       loff_t offset, unsigned long nr_segs)
+ {
+       struct file *file = iocb->ki_filp;
+-      struct inode *inode = file->f_dentry->d_inode->i_mapping->host;
++      struct inode *inode = file->f_mapping->host;
+-      return blockdev_direct_IO(rw, iocb, inode, inode->i_bdev, iov, offset,
++      return blockdev_direct_IO(rw, iocb, inode, I_BDEV(inode), iov, offset,
+                               nr_segs, blkdev_get_blocks, NULL);
+ }
+@@ -155,11 +177,10 @@ static int blkdev_commit_write(struct fi
+  */
+ static loff_t block_llseek(struct file *file, loff_t offset, int origin)
+ {
+-      struct inode *bd_inode;
++      struct inode *bd_inode = file->f_mapping->host;
+       loff_t size;
+       loff_t retval;
+-      bd_inode = file->f_dentry->d_inode->i_bdev->bd_inode;
+       down(&bd_inode->i_sem);
+       size = i_size_read(bd_inode);
+@@ -182,15 +203,13 @@ static loff_t block_llseek(struct file *
+ }
+       
+ /*
+- *    Filp may be NULL when we are called by an msync of a vma
+- *    since the vma has no handle.
++ *    Filp is never NULL; the only case when ->fsync() is called with
++ *    NULL first argument is nfsd_sync_dir() and that's not a directory.
+  */
+  
+ static int block_fsync(struct file *filp, struct dentry *dentry, int datasync)
+ {
+-      struct inode * inode = dentry->d_inode;
+-
+-      return sync_blockdev(inode->i_bdev);
++      return sync_blockdev(I_BDEV(filp->f_mapping->host));
+ }
+ /*
+@@ -200,16 +219,6 @@ static int block_fsync(struct file *filp
+ static spinlock_t bdev_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
+ static kmem_cache_t * bdev_cachep;
+-struct bdev_inode {
+-      struct block_device bdev;
+-      struct inode vfs_inode;
+-};
+-
+-static inline struct bdev_inode *BDEV_I(struct inode *inode)
+-{
+-      return container_of(inode, struct bdev_inode, vfs_inode);
+-}
+-
+ static struct inode *bdev_alloc_inode(struct super_block *sb)
+ {
+       struct bdev_inode *ei = kmem_cache_alloc(bdev_cachep, SLAB_KERNEL);
+@@ -243,7 +252,6 @@ static inline void __bd_forget(struct in
+ {
+       list_del_init(&inode->i_devices);
+       inode->i_bdev = NULL;
+-      inode->i_mapping = &inode->i_data;
+ }
+ static void bdev_clear_inode(struct inode *inode)
+@@ -358,6 +366,8 @@ struct block_device *bdget(dev_t dev)
+       return bdev;
+ }
++EXPORT_SYMBOL(bdget);
++
+ long nr_blockdev_pages(void)
+ {
+       struct list_head *p;
+@@ -376,27 +386,29 @@ void bdput(struct block_device *bdev)
+ {
+       iput(bdev->bd_inode);
+ }
++
++EXPORT_SYMBOL(bdput);
+  
+-int bd_acquire(struct inode *inode)
++static struct block_device *bd_acquire(struct inode *inode)
+ {
+       struct block_device *bdev;
+       spin_lock(&bdev_lock);
+-      if (inode->i_bdev && igrab(inode->i_bdev->bd_inode)) {
++      bdev = inode->i_bdev;
++      if (bdev && igrab(bdev->bd_inode)) {
+               spin_unlock(&bdev_lock);
+-              return 0;
++              return bdev;
+       }
+       spin_unlock(&bdev_lock);
+       bdev = bdget(inode->i_rdev);
+-      if (!bdev)
+-              return -ENOMEM;
+-      spin_lock(&bdev_lock);
+-      if (inode->i_bdev)
+-              __bd_forget(inode);
+-      inode->i_bdev = bdev;
+-      inode->i_mapping = bdev->bd_inode->i_mapping;
+-      list_add(&inode->i_devices, &bdev->bd_inodes);
+-      spin_unlock(&bdev_lock);
+-      return 0;
++      if (bdev) {
++              spin_lock(&bdev_lock);
++              if (inode->i_bdev)
++                      __bd_forget(inode);
++              inode->i_bdev = bdev;
++              list_add(&inode->i_devices, &bdev->bd_inodes);
++              spin_unlock(&bdev_lock);
++      }
++      return bdev;
+ }
+ /* Call when you free inode */
+@@ -444,6 +456,8 @@ int bd_claim(struct block_device *bdev, 
+       return res;
+ }
++EXPORT_SYMBOL(bd_claim);
++
+ void bd_release(struct block_device *bdev)
+ {
+       spin_lock(&bdev_lock);
+@@ -454,6 +468,8 @@ void bd_release(struct block_device *bde
+       spin_unlock(&bdev_lock);
+ }
++EXPORT_SYMBOL(bd_release);
++
+ /*
+  * Tries to open block device by device number.  Use it ONLY if you
+  * really do not have anything better - i.e. when you are behind a
+@@ -471,6 +487,8 @@ struct block_device *open_by_devnum(dev_
+       return err ? ERR_PTR(err) : bdev;
+ }
++EXPORT_SYMBOL(open_by_devnum);
++
+ /*
+  * This routine checks whether a removable media has been changed,
+  * and invalidates all buffer-cache-entries in that case. This
+@@ -500,6 +518,8 @@ int check_disk_change(struct block_devic
+       return 1;
+ }
++EXPORT_SYMBOL(check_disk_change);
++
+ static void bd_set_size(struct block_device *bdev, loff_t size)
+ {
+       unsigned bsize = bdev_hardsect_size(bdev);
+@@ -513,13 +533,14 @@ static void bd_set_size(struct block_dev
+       bdev->bd_inode->i_blkbits = blksize_bits(bsize);
+ }
+-static int do_open(struct block_device *bdev, struct inode *inode, struct file *file)
++static int do_open(struct block_device *bdev, struct file *file)
+ {
+       struct module *owner = NULL;
+       struct gendisk *disk;
+       int ret = -ENXIO;
+       int part;
++      file->f_mapping = bdev->bd_inode->i_mapping;
+       lock_kernel();
+       disk = get_gendisk(bdev->bd_dev, &part);
+       if (!disk) {
+@@ -536,7 +557,7 @@ static int do_open(struct block_device *
+               if (!part) {
+                       struct backing_dev_info *bdi;
+                       if (disk->fops->open) {
+-                              ret = disk->fops->open(inode, file);
++                              ret = disk->fops->open(bdev, file);
+                               if (ret)
+                                       goto out_first;
+                       }
+@@ -581,7 +602,7 @@ static int do_open(struct block_device *
+               module_put(owner);
+               if (bdev->bd_contains == bdev) {
+                       if (bdev->bd_disk->fops->open) {
+-                              ret = bdev->bd_disk->fops->open(inode, file);
++                              ret = bdev->bd_disk->fops->open(bdev, file);
+                               if (ret)
+                                       goto out;
+                       }
+@@ -629,9 +650,11 @@ int blkdev_get(struct block_device *bdev
+       fake_file.f_dentry = &fake_dentry;
+       fake_dentry.d_inode = bdev->bd_inode;
+-      return do_open(bdev, bdev->bd_inode, &fake_file);
++      return do_open(bdev, &fake_file);
+ }
++EXPORT_SYMBOL(blkdev_get);
++
+ int blkdev_open(struct inode * inode, struct file * filp)
+ {
+       struct block_device *bdev;
+@@ -645,10 +668,9 @@ int blkdev_open(struct inode * inode, st
+        */
+       filp->f_flags |= O_LARGEFILE;
+-      bd_acquire(inode);
+-      bdev = inode->i_bdev;
++      bdev = bd_acquire(inode);
+-      res = do_open(bdev, inode, filp);
++      res = do_open(bdev, filp);
+       if (res)
+               return res;
+@@ -662,10 +684,11 @@ int blkdev_open(struct inode * inode, st
+       return res;
+ }
++EXPORT_SYMBOL(blkdev_open);
++
+ int blkdev_put(struct block_device *bdev, int kind)
+ {
+       int ret = 0;
+-      struct inode *bd_inode = bdev->bd_inode;
+       struct gendisk *disk = bdev->bd_disk;
+       down(&bdev->bd_sem);
+@@ -674,14 +697,14 @@ int blkdev_put(struct block_device *bdev
+               switch (kind) {
+               case BDEV_FILE:
+               case BDEV_FS:
+-                      sync_blockdev(bd_inode->i_bdev);
++                      sync_blockdev(bdev);
+                       break;
+               }
+               kill_bdev(bdev);
+       }
+       if (bdev->bd_contains == bdev) {
+               if (disk->fops->release)
+-                      ret = disk->fops->release(bd_inode, NULL);
++                      ret = disk->fops->release(disk);
+       } else {
+               down(&bdev->bd_contains->bd_sem);
+               bdev->bd_contains->bd_part_count--;
+@@ -710,11 +733,14 @@ int blkdev_put(struct block_device *bdev
+       return ret;
+ }
+-int blkdev_close(struct inode * inode, struct file * filp)
++EXPORT_SYMBOL(blkdev_put);
++
++static int blkdev_close(struct inode * inode, struct file * filp)
+ {
+-      if (inode->i_bdev->bd_holder == filp)
+-              bd_release(inode->i_bdev);
+-      return blkdev_put(inode->i_bdev, BDEV_FILE);
++      struct block_device *bdev = I_BDEV(filp->f_mapping->host);
++      if (bdev->bd_holder == filp)
++              bd_release(bdev);
++      return blkdev_put(bdev, BDEV_FILE);
+ }
+ static ssize_t blkdev_file_write(struct file *file, const char __user *buf,
+@@ -733,6 +759,11 @@ static ssize_t blkdev_file_aio_write(str
+       return generic_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos);
+ }
++static int block_ioctl(struct inode *inode, struct file *file, unsigned cmd,
++                      unsigned long arg)
++{
++      return blkdev_ioctl(I_BDEV(file->f_mapping->host), file, cmd, arg);
++}
+ struct address_space_operations def_blk_aops = {
+       .readpage       = blkdev_readpage,
+@@ -754,22 +785,26 @@ struct file_operations def_blk_fops = {
+       .aio_write      = blkdev_file_aio_write, 
+       .mmap           = generic_file_mmap,
+       .fsync          = block_fsync,
+-      .ioctl          = blkdev_ioctl,
++      .ioctl          = block_ioctl,
+       .readv          = generic_file_readv,
+       .writev         = generic_file_writev,
+       .sendfile       = generic_file_sendfile,
+ };
++EXPORT_SYMBOL(def_blk_fops);
++
+ int ioctl_by_bdev(struct block_device *bdev, unsigned cmd, unsigned long arg)
+ {
+       int res;
+       mm_segment_t old_fs = get_fs();
+       set_fs(KERNEL_DS);
+-      res = blkdev_ioctl(bdev->bd_inode, NULL, cmd, arg);
++      res = blkdev_ioctl(bdev, NULL, cmd, arg);
+       set_fs(old_fs);
+       return res;
+ }
++EXPORT_SYMBOL(ioctl_by_bdev);
++
+ /**
+  * lookup_bdev  - lookup a struct block_device by name
+  *
+@@ -800,11 +835,10 @@ struct block_device *lookup_bdev(const c
+       error = -EACCES;
+       if (nd.mnt->mnt_flags & MNT_NODEV)
+               goto fail;
+-      error = bd_acquire(inode);
+-      if (error)
++      error = -ENOMEM;
++      bdev = bd_acquire(inode);
++      if (!bdev)
+               goto fail;
+-      bdev = inode->i_bdev;
+-
+ out:
+       path_release(&nd);
+       return bdev;
+@@ -854,6 +888,8 @@ blkdev_put:
+       return ERR_PTR(error);
+ }
++EXPORT_SYMBOL(open_bdev_excl);
++
+ /**
+  * close_bdev_excl  -  release a blockdevice openen by open_bdev_excl()
+  *
+@@ -867,3 +903,5 @@ void close_bdev_excl(struct block_device
+       bd_release(bdev);
+       blkdev_put(bdev, kind);
+ }
++
++EXPORT_SYMBOL(close_bdev_excl);
+--- linux-2.6.0-test6/fs/buffer.c      2003-08-22 19:23:42.000000000 -0700
++++ 25/fs/buffer.c     2003-10-05 00:36:59.000000000 -0700
+@@ -116,27 +116,50 @@ void unlock_buffer(struct buffer_head *b
+ }
+ /*
+- * Block until a buffer comes unlocked.  This doesn't stop it
++ * Wait until a buffer comes unlocked.  This doesn't stop it
+  * from becoming locked again - you have to lock it yourself
+  * if you want to preserve its state.
++ * If the wait queue parameter specifies an async i/o callback,
++ * then instead of blocking, we just queue up the callback
++ * on the wait queue for async notification when the buffer gets
++ * unlocked.
++ * A NULL wait queue parameter defaults to synchronous behaviour
+  */
+-void __wait_on_buffer(struct buffer_head * bh)
++int __wait_on_buffer_wq(struct buffer_head * bh, wait_queue_t *wait)
+ {
+       wait_queue_head_t *wqh = bh_waitq_head(bh);
+-      DEFINE_WAIT(wait);
++      DEFINE_WAIT(local_wait);
++
++      if (!wait)
++              wait = &local_wait;
+       if (atomic_read(&bh->b_count) == 0 &&
+                       (!bh->b_page || !PageLocked(bh->b_page)))
+               buffer_error();
+       do {
+-              prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE);
++              prepare_to_wait(wqh, wait, TASK_UNINTERRUPTIBLE);
+               if (buffer_locked(bh)) {
+                       blk_run_queues();
++                      if (!is_sync_wait(wait)) {
++                              /*
++                               * if we've queued an async wait queue
++                               * callback do not block; just tell the
++                               * caller to return and retry later when
++                               * the callback is notified
++                               */
++                              return -EIOCBRETRY;
++                      }
+                       io_schedule();
+               }
+       } while (buffer_locked(bh));
+-      finish_wait(wqh, &wait);
++      finish_wait(wqh, wait);
++      return 0;
++}
++
++void __wait_on_buffer(struct buffer_head * bh)
++{
++      __wait_on_buffer_wq(bh, NULL);
+ }
+ static void
+@@ -314,8 +337,7 @@ int file_fsync(struct file *filp, struct
+ asmlinkage long sys_fsync(unsigned int fd)
+ {
+       struct file * file;
+-      struct dentry * dentry;
+-      struct inode * inode;
++      struct address_space *mapping;
+       int ret, err;
+       ret = -EBADF;
+@@ -323,8 +345,7 @@ asmlinkage long sys_fsync(unsigned int f
+       if (!file)
+               goto out;
+-      dentry = file->f_dentry;
+-      inode = dentry->d_inode;
++      mapping = file->f_mapping;
+       ret = -EINVAL;
+       if (!file->f_op || !file->f_op->fsync) {
+@@ -333,17 +354,17 @@ asmlinkage long sys_fsync(unsigned int f
+       }
+       /* We need to protect against concurrent writers.. */
+-      down(&inode->i_sem);
++      down(&mapping->host->i_sem);
+       current->flags |= PF_SYNCWRITE;
+-      ret = filemap_fdatawrite(inode->i_mapping);
+-      err = file->f_op->fsync(file, dentry, 0);
++      ret = filemap_fdatawrite(mapping);
++      err = file->f_op->fsync(file, file->f_dentry, 0);
+       if (!ret)
+               ret = err;
+-      err = filemap_fdatawait(inode->i_mapping);
++      err = filemap_fdatawait(mapping);
+       if (!ret)
+               ret = err;
+       current->flags &= ~PF_SYNCWRITE;
+-      up(&inode->i_sem);
++      up(&mapping->host->i_sem);
+ out_putf:
+       fput(file);
+@@ -354,8 +375,7 @@ out:
+ asmlinkage long sys_fdatasync(unsigned int fd)
+ {
+       struct file * file;
+-      struct dentry * dentry;
+-      struct inode * inode;
++      struct address_space *mapping;
+       int ret, err;
+       ret = -EBADF;
+@@ -363,24 +383,23 @@ asmlinkage long sys_fdatasync(unsigned i
+       if (!file)
+               goto out;
+-      dentry = file->f_dentry;
+-      inode = dentry->d_inode;
+-
+       ret = -EINVAL;
+       if (!file->f_op || !file->f_op->fsync)
+               goto out_putf;
+-      down(&inode->i_sem);
++      mapping = file->f_mapping;
++
++      down(&mapping->host->i_sem);
+       current->flags |= PF_SYNCWRITE;
+-      ret = filemap_fdatawrite(inode->i_mapping);
+-      err = file->f_op->fsync(file, dentry, 1);
++      ret = filemap_fdatawrite(mapping);
++      err = file->f_op->fsync(file, file->f_dentry, 1);
+       if (!ret)
+               ret = err;
+-      err = filemap_fdatawait(inode->i_mapping);
++      err = filemap_fdatawait(mapping);
+       if (!ret)
+               ret = err;
+       current->flags &= ~PF_SYNCWRITE;
+-      up(&inode->i_sem);
++      up(&mapping->host->i_sem);
+ out_putf:
+       fput(file);
+@@ -1296,9 +1315,12 @@ void __bforget(struct buffer_head *bh)
+       __brelse(bh);
+ }
+-static struct buffer_head *__bread_slow(struct buffer_head *bh)
++static struct buffer_head *__bread_slow_wq(struct buffer_head *bh,
++              wait_queue_t *wait)
+ {
+-      lock_buffer(bh);
++      if (-EIOCBRETRY == lock_buffer_wq(bh, wait))
++              return ERR_PTR(-EIOCBRETRY);
++
+       if (buffer_uptodate(bh)) {
+               unlock_buffer(bh);
+               return bh;
+@@ -1308,7 +1330,8 @@ static struct buffer_head *__bread_slow(
+               get_bh(bh);
+               bh->b_end_io = end_buffer_read_sync;
+               submit_bh(READ, bh);
+-              wait_on_buffer(bh);
++              if (-EIOCBRETRY == wait_on_buffer_wq(bh, wait))
++                      return ERR_PTR(-EIOCBRETRY);
+               if (buffer_uptodate(bh))
+                       return bh;
+       }
+@@ -1316,6 +1339,11 @@ static struct buffer_head *__bread_slow(
+       return NULL;
+ }
++static inline struct buffer_head *__bread_slow(struct buffer_head *bh)
++{
++      return __bread_slow_wq(bh, NULL);
++}
++
+ /*
+  * Per-cpu buffer LRU implementation.  To reduce the cost of __find_get_block().
+  * The bhs[] array is sorted - newest buffer is at bhs[0].  Buffers have their
+@@ -1503,6 +1531,18 @@ __bread(struct block_device *bdev, secto
+ }
+ EXPORT_SYMBOL(__bread);
++struct buffer_head *
++__bread_wq(struct block_device *bdev, sector_t block, int size,
++      wait_queue_t *wait)
++{
++      struct buffer_head *bh = __getblk(bdev, block, size);
++
++      if (!buffer_uptodate(bh))
++              bh = __bread_slow_wq(bh, wait);
++      return bh;
++}
++EXPORT_SYMBOL(__bread_wq);
++
+ /*
+  * invalidate_bh_lrus() is called rarely - at unmount.  Because it is only for
+  * unmount it only needs to ensure that all buffers from the target device are
+@@ -1980,8 +2020,9 @@ static int __block_prepare_write(struct 
+       /*
+        * If we issued read requests - let them complete.
+        */
+-      while(wait_bh > wait) {
+-              wait_on_buffer(*--wait_bh);
++      while (wait_bh > wait) {
++              if ((err = wait_on_buffer_wq(*--wait_bh, current->io_wait)))
++                      return err;
+               if (!buffer_uptodate(*wait_bh))
+                       return -EIO;
+       }
+@@ -3035,3 +3076,32 @@ void __init buffer_init(void)
+                               (void *)(long)smp_processor_id());
+       register_cpu_notifier(&buffer_nb);
+ }
++
++EXPORT_SYMBOL(__bforget);
++EXPORT_SYMBOL(__brelse);
++EXPORT_SYMBOL(__wait_on_buffer);
++EXPORT_SYMBOL(__wait_on_buffer_wq);
++EXPORT_SYMBOL(block_commit_write);
++EXPORT_SYMBOL(block_prepare_write);
++EXPORT_SYMBOL(block_read_full_page);
++EXPORT_SYMBOL(block_sync_page);
++EXPORT_SYMBOL(block_truncate_page);
++EXPORT_SYMBOL(block_write_full_page);
++EXPORT_SYMBOL(buffer_insert_list);
++EXPORT_SYMBOL(cont_prepare_write);
++EXPORT_SYMBOL(end_buffer_async_write);
++EXPORT_SYMBOL(end_buffer_read_sync);
++EXPORT_SYMBOL(end_buffer_write_sync);
++EXPORT_SYMBOL(file_fsync);
++EXPORT_SYMBOL(fsync_bdev);
++EXPORT_SYMBOL(fsync_buffers_list);
++EXPORT_SYMBOL(generic_block_bmap);
++EXPORT_SYMBOL(generic_commit_write);
++EXPORT_SYMBOL(generic_cont_expand);
++EXPORT_SYMBOL(init_buffer);
++EXPORT_SYMBOL(invalidate_bdev);
++EXPORT_SYMBOL(ll_rw_block);
++EXPORT_SYMBOL(mark_buffer_dirty);
++EXPORT_SYMBOL(submit_bh);
++EXPORT_SYMBOL(sync_dirty_buffer);
++EXPORT_SYMBOL(unlock_buffer);
+--- linux-2.6.0-test6/fs/coda/file.c   2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/coda/file.c  2003-10-05 00:34:03.000000000 -0700
+@@ -89,6 +89,7 @@ coda_file_mmap(struct file *coda_file, s
+       coda_inode = coda_file->f_dentry->d_inode;
+       host_inode = host_file->f_dentry->d_inode;
++      coda_file->f_mapping = host_file->f_mapping;
+       if (coda_inode->i_mapping == &coda_inode->i_data)
+               coda_inode->i_mapping = host_inode->i_mapping;
+--- linux-2.6.0-test6/fs/compat_ioctl.c        2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/compat_ioctl.c       2003-10-05 00:34:44.000000000 -0700
+@@ -106,6 +106,7 @@
+ #include <linux/nbd.h>
+ #include <linux/random.h>
+ #include <linux/filter.h>
++#include <linux/msdos_fs.h>
+ #undef INCLUDES
+ #endif
+@@ -576,54 +577,45 @@ static int ethtool_ioctl(unsigned int fd
+ static int bond_ioctl(unsigned long fd, unsigned int cmd, unsigned long arg)
+ {
+-      struct ifreq ifr;
++      struct ifreq kifr;
++      struct ifreq *uifr;
++      struct ifreq32 *ifr32 = (struct ifreq32 *) arg;
+       mm_segment_t old_fs;
+-      int err, len;
++      int err;
+       u32 data;
+-      
+-      if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
+-              return -EFAULT;
+-      ifr.ifr_data = (__kernel_caddr_t)get_zeroed_page(GFP_KERNEL);
+-      if (!ifr.ifr_data)
+-              return -EAGAIN;
++      void *datap;
+       switch (cmd) {
+       case SIOCBONDENSLAVE:
+       case SIOCBONDRELEASE:
+       case SIOCBONDSETHWADDR:
+       case SIOCBONDCHANGEACTIVE:
+-              len = IFNAMSIZ * sizeof(char);
+-              break;
++              if (copy_from_user(&kifr, ifr32, sizeof(struct ifreq32)))
++                      return -EFAULT;
++
++              old_fs = get_fs();
++              set_fs (KERNEL_DS);
++              err = sys_ioctl (fd, cmd, (unsigned long)&kifr);
++              set_fs (old_fs);
++
++              return err;
+       case SIOCBONDSLAVEINFOQUERY:
+-              len = sizeof(struct ifslave);
+-              break;
+       case SIOCBONDINFOQUERY:
+-              len = sizeof(struct ifbond);
+-              break;
+-      default:
+-              err = -EINVAL;
+-              goto out;
+-      };
++              uifr = compat_alloc_user_space(sizeof(*uifr));
++              if (copy_in_user(&uifr->ifr_name, &ifr32->ifr_name, IFNAMSIZ))
++                      return -EFAULT;
+-      __get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data));
+-      if (copy_from_user(ifr.ifr_data, compat_ptr(data), len)) {
+-              err = -EFAULT;
+-              goto out;
+-      }
++              if (get_user(data, &ifr32->ifr_ifru.ifru_data))
++                      return -EFAULT;
+-      old_fs = get_fs();
+-      set_fs (KERNEL_DS);
+-      err = sys_ioctl (fd, cmd, (unsigned long)&ifr);
+-      set_fs (old_fs);
+-      if (!err) {
+-              len = copy_to_user(compat_ptr(data), ifr.ifr_data, len);
+-              if (len)
+-                      err = -EFAULT;
+-      }
++              datap = compat_ptr(data);
++              if (put_user(datap, &uifr->ifr_ifru.ifru_data))
++                      return -EFAULT;
+-out:
+-      free_page((unsigned long)ifr.ifr_data);
+-      return err;
++              return sys_ioctl (fd, cmd, (unsigned long)uifr);
++      default:
++              return -EINVAL;
++      };
+ }
+ int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+@@ -1035,6 +1027,7 @@ static int sg_build_iovec(sg_io_hdr_t *s
+                       return -EFAULT;
+       }
++      sgio->dxferp = iov;
+       return 0;
+ }
+@@ -1581,7 +1574,7 @@ static int vt_check(struct file *file)
+        * To have permissions to do most of the vt ioctls, we either have
+        * to be the owner of the tty, or super-user.
+        */
+-      if (current->tty == tty || capable(CAP_SYS_ADMIN))
++      if (process_tty(current) == tty || capable(CAP_SYS_ADMIN))
+               return 1;
+       return 0;                                                    
+ }
+@@ -2310,6 +2303,572 @@ static int mtd_rw_oob(unsigned int fd, u
+       return err;
+ }     
++#define       VFAT_IOCTL_READDIR_BOTH32       _IOR('r', 1, struct compat_dirent[2])
++#define       VFAT_IOCTL_READDIR_SHORT32      _IOR('r', 2, struct compat_dirent[2])
++
++static long
++put_dirent32 (struct dirent *d, struct compat_dirent *d32)
++{
++        int ret;
++
++        if ((ret = verify_area(VERIFY_WRITE, d32,
++                               sizeof(struct compat_dirent))))
++                return ret;
++
++        __put_user(d->d_ino, &d32->d_ino);
++        __put_user(d->d_off, &d32->d_off);
++        __put_user(d->d_reclen, &d32->d_reclen);
++        __copy_to_user(d32->d_name, d->d_name, d->d_reclen);
++        return ret;
++}
++
++static int vfat_ioctl32(unsigned fd, unsigned cmd,  void *ptr)
++{
++      int ret;
++      mm_segment_t oldfs = get_fs();
++      struct dirent d[2];
++
++      switch(cmd)
++      {
++              case VFAT_IOCTL_READDIR_BOTH32:
++                      cmd = VFAT_IOCTL_READDIR_BOTH;
++                      break;
++              case VFAT_IOCTL_READDIR_SHORT32:
++                      cmd = VFAT_IOCTL_READDIR_SHORT;
++                      break;
++      }
++
++      set_fs(KERNEL_DS);
++      ret = sys_ioctl(fd,cmd,(unsigned long)&d);
++      set_fs(oldfs);
++      if (ret >= 0) {
++              ret |= put_dirent32(&d[0], (struct compat_dirent *)ptr);
++              ret |= put_dirent32(&d[1], ((struct compat_dirent *)ptr) + 1);
++      }
++      return ret;
++}
++
++#define REISERFS_IOC_UNPACK32               _IOW(0xCD,1,int)
++
++static int reiserfs_ioctl32(unsigned fd, unsigned cmd, unsigned long ptr)
++{
++        if (cmd == REISERFS_IOC_UNPACK32)
++                cmd = REISERFS_IOC_UNPACK;
++
++        return sys_ioctl(fd,cmd,ptr);
++}
++
++struct raw32_config_request
++{
++        compat_int_t    raw_minor;
++        __u64   block_major;
++        __u64   block_minor;
++} __attribute__((packed));
++
++static int get_raw32_request(struct raw_config_request *req, struct raw32_config_request *user_req)
++{
++        __u32   lo_maj, hi_maj, lo_min, hi_min;
++        int ret;
++
++        if ((ret = verify_area(VERIFY_READ, user_req,
++                               sizeof(struct raw32_config_request))))
++                return ret;
++
++        __get_user(req->raw_minor, &user_req->raw_minor);
++        __get_user(lo_maj, (__u32*)&user_req->block_major);
++        __get_user(hi_maj, ((__u32*)(&user_req->block_major) + 1));
++        __get_user(lo_min, (__u32*)&user_req->block_minor);
++        __get_user(hi_min, ((__u32*)(&user_req->block_minor) + 1));
++
++        req->block_major = lo_maj | (((__u64)hi_maj) << 32);
++        req->block_minor = lo_min | (((__u64)lo_min) << 32);
++
++        return ret;
++}
++
++static int set_raw32_request(struct raw_config_request *req, struct raw32_config_request *user_req)
++{
++      int ret;
++
++        if ((ret = verify_area(VERIFY_WRITE, user_req,
++                               sizeof(struct raw32_config_request))))
++                return ret;
++
++        __put_user(req->raw_minor, &user_req->raw_minor);
++        __put_user((__u32)(req->block_major), (__u32*)&user_req->block_major);
++        __put_user((__u32)(req->block_major >> 32), ((__u32*)(&user_req->block_major) + 1));
++        __put_user((__u32)(req->block_minor), (__u32*)&user_req->block_minor);
++        __put_user((__u32)(req->block_minor >> 32), ((__u32*)(&user_req->block_minor) + 1));
++
++        return ret;
++}
++
++static int raw_ioctl(unsigned fd, unsigned cmd,  void *ptr)
++{
++        int ret;
++
++        switch (cmd) {
++        case RAW_SETBIND:
++        case RAW_GETBIND: {
++                struct raw_config_request req;
++                struct raw32_config_request *user_req = ptr;
++                mm_segment_t oldfs = get_fs();
++
++                if ((ret = get_raw32_request(&req, user_req)))
++                        return ret;
++
++                set_fs(KERNEL_DS);
++                ret = sys_ioctl(fd,cmd,(unsigned long)&req);
++                set_fs(oldfs);
++
++                if ((!ret) && (cmd == RAW_GETBIND)) {
++                        ret = set_raw32_request(&req, user_req);
++                }
++                break;
++        }
++        default:
++                ret = sys_ioctl(fd,cmd,(unsigned long)ptr);
++                break;
++        }
++        return ret;
++}
++
++struct serial_struct32 {
++        compat_int_t    type;
++        compat_int_t    line;
++        compat_uint_t   port;
++        compat_int_t    irq;
++        compat_int_t    flags;
++        compat_int_t    xmit_fifo_size;
++        compat_int_t    custom_divisor;
++        compat_int_t    baud_base;
++        unsigned short  close_delay;
++        char    io_type;
++        char    reserved_char[1];
++        compat_int_t    hub6;
++        unsigned short  closing_wait; /* time to wait before closing */
++        unsigned short  closing_wait2; /* no longer used... */
++        compat_uint_t   iomem_base;
++        unsigned short  iomem_reg_shift;
++        unsigned int    port_high;
++        compat_int_t    reserved[1];
++};
++
++static int serial_struct_ioctl(unsigned fd, unsigned cmd,  void *ptr)
++{
++        typedef struct serial_struct SS;
++        typedef struct serial_struct32 SS32;
++        struct serial_struct32 *ss32 = ptr;
++        int err;
++        struct serial_struct ss;
++        mm_segment_t oldseg = get_fs();
++        __u32 udata;
++
++        if (cmd == TIOCSSERIAL) {
++                if (verify_area(VERIFY_READ, ss32, sizeof(SS32)))
++                        return -EFAULT;
++                __copy_from_user(&ss, ss32, offsetof(SS32, iomem_base));
++                __get_user(udata, &ss32->iomem_base);
++                ss.iomem_base = compat_ptr(udata);
++                __get_user(ss.iomem_reg_shift, &ss32->iomem_reg_shift);
++                __get_user(ss.port_high, &ss32->port_high);
++                ss.iomap_base = 0UL;
++        }
++        set_fs(KERNEL_DS);
++                err = sys_ioctl(fd,cmd,(unsigned long)(&ss));
++        set_fs(oldseg);
++        if (cmd == TIOCGSERIAL && err >= 0) {
++                if (verify_area(VERIFY_WRITE, ss32, sizeof(SS32)))
++                        return -EFAULT;
++                __copy_to_user(ss32,&ss,offsetof(SS32,iomem_base));
++                __put_user((unsigned long)ss.iomem_base  >> 32 ?
++                            0xffffffff : (unsigned)(unsigned long)ss.iomem_base,
++                            &ss32->iomem_base);
++                __put_user(ss.iomem_reg_shift, &ss32->iomem_reg_shift);
++                __put_user(ss.port_high, &ss32->port_high);
++
++        }
++        return err;
++}
++
++struct usbdevfs_ctrltransfer32 {
++        u8 bRequestType;
++        u8 bRequest;
++        u16 wValue;
++        u16 wIndex;
++        u16 wLength;
++        u32 timeout;  /* in milliseconds */
++        compat_caddr_t data;
++};
++
++#define USBDEVFS_CONTROL32           _IOWR('U', 0, struct usbdevfs_ctrltransfer32)
++
++static int do_usbdevfs_control(unsigned int fd, unsigned int cmd, unsigned long arg)
++{
++        struct usbdevfs_ctrltransfer kctrl;
++        struct usbdevfs_ctrltransfer32 *uctrl;
++        mm_segment_t old_fs;
++        __u32 udata;
++        void *uptr, *kptr;
++        int err;
++
++        uctrl = (struct usbdevfs_ctrltransfer32 *) arg;
++
++        if (copy_from_user(&kctrl, uctrl,
++                           (sizeof(struct usbdevfs_ctrltransfer32) -
++                            sizeof(compat_caddr_t))))
++                return -EFAULT;
++
++        if (get_user(udata, &uctrl->data))
++                return -EFAULT;
++        uptr = compat_ptr(udata);
++        /* In usbdevice_fs, it limits the control buffer to a page,
++         * for simplicity so do we.
++         */
++        if (!uptr || kctrl.wLength > PAGE_SIZE)
++                return -EINVAL;
++
++        kptr = (void *)__get_free_page(GFP_KERNEL);
++
++        if ((kctrl.bRequestType & USB_DIR_IN) == 0) {
++                err = -EFAULT;
++                if (copy_from_user(kptr, uptr, kctrl.wLength))
++                        goto out;
++        }
++
++        kctrl.data = kptr;
++
++        old_fs = get_fs();
++        set_fs(KERNEL_DS);
++        err = sys_ioctl(fd, USBDEVFS_CONTROL, (unsigned long)&kctrl);
++        set_fs(old_fs);
++
++        if (err >= 0 &&
++            ((kctrl.bRequestType & USB_DIR_IN) != 0)) {
++                if (copy_to_user(uptr, kptr, kctrl.wLength))
++                        err = -EFAULT;
++        }
++
++out:
++        free_page((unsigned long) kptr);
++        return err;
++}
++
++
++struct usbdevfs_bulktransfer32 {
++        compat_uint_t ep;
++        compat_uint_t len;
++        compat_uint_t timeout; /* in milliseconds */
++        compat_caddr_t data;
++};
++
++#define USBDEVFS_BULK32              _IOWR('U', 2, struct usbdevfs_bulktransfer32)
++
++static int do_usbdevfs_bulk(unsigned int fd, unsigned int cmd, unsigned long arg)
++{
++        struct usbdevfs_bulktransfer kbulk;
++        struct usbdevfs_bulktransfer32 *ubulk;
++        mm_segment_t old_fs;
++        __u32 udata;
++        void *uptr, *kptr;
++        int err;
++
++      ubulk = (struct usbdevfs_bulktransfer32 *) arg;
++
++        if (get_user(kbulk.ep, &ubulk->ep) ||
++            get_user(kbulk.len, &ubulk->len) ||
++            get_user(kbulk.timeout, &ubulk->timeout) ||
++            get_user(udata, &ubulk->data))
++                return -EFAULT;
++
++        uptr = compat_ptr(udata);
++
++        /* In usbdevice_fs, it limits the control buffer to a page,
++         * for simplicity so do we.
++         */
++        if (!uptr || kbulk.len > PAGE_SIZE)
++                return -EINVAL;
++
++        kptr = (void *) __get_free_page(GFP_KERNEL);
++
++        if ((kbulk.ep & 0x80) == 0) {
++                err = -EFAULT;
++              if (copy_from_user(kptr, uptr, kbulk.len))
++                        goto out;
++        }
++
++        kbulk.data = kptr;
++
++      old_fs = get_fs();
++        set_fs(KERNEL_DS);
++        err = sys_ioctl(fd, USBDEVFS_BULK, (unsigned long) &kbulk);
++        set_fs(old_fs);
++
++        if (err >= 0 &&
++            ((kbulk.ep & 0x80) != 0)) {
++                if (copy_to_user(uptr, kptr, kbulk.len))
++                        err = -EFAULT;
++        }
++
++out:
++        free_page((unsigned long) kptr);
++        return err;
++}
++
++/* This needs more work before we can enable it.  Unfortunately
++ * because of the fancy asynchronous way URB status/error is written
++ * back to userspace, we'll need to fiddle with USB devio internals
++ * and/or reimplement entirely the frontend of it ourselves. -DaveM
++ *
++ * The issue is:
++ *
++ *    When an URB is submitted via usbdevicefs it is put onto an
++ *    asynchronous queue.  When the URB completes, it may be reaped
++ *    via another ioctl.  During this reaping the status is written
++ *    back to userspace along with the length of the transfer.
++ *
++ *    We must translate into 64-bit kernel types so we pass in a kernel
++ *    space copy of the usbdevfs_urb structure.  This would mean that we
++ *    must do something to deal with the async entry reaping.  First we
++ *    have to deal somehow with this transitory memory we've allocated.
++ *    This is problematic since there are many call sites from which the
++ *    async entries can be destroyed (and thus when we'd need to free up
++ *    this kernel memory).  One of which is the close() op of usbdevicefs.
++ *    To handle that we'd need to make our own file_operations struct which
++ *    overrides usbdevicefs's release op with our own which runs usbdevicefs's
++ *    real release op then frees up the kernel memory.
++ *
++ *    But how to keep track of these kernel buffers?  We'd need to either
++ *    keep track of them in some table _or_ know about usbdevicefs internals
++ *    (ie. the exact layout of its file private, which is actually defined
++ *    in linux/usbdevice_fs.h, the layout of the async queues are private to
++ *    devio.c)
++ *
++ * There is one possible other solution I considered, also involving knowledge
++ * of usbdevicefs internals:
++ *
++ *    After an URB is submitted, we "fix up" the address back to the user
++ *    space one.  This would work if the status/length fields written back
++ *    by the async URB completion lines up perfectly in the 32-bit type with
++ *    the 64-bit kernel type.  Unfortunately, it does not because the iso
++ *    frame descriptors, at the end of the struct, can be written back.
++ *
++ * I think we'll just need to simply duplicate the devio URB engine here.
++ */
++#if 0
++struct usbdevfs_urb32 {
++      unsigned char type;
++      unsigned char endpoint;
++      compat_int_t status;
++      compat_uint_t flags;
++      compat_caddr_t buffer;
++      compat_int_t buffer_length;
++      compat_int_t actual_length;
++      compat_int_t start_frame;
++      compat_int_t number_of_packets;
++      compat_int_t error_count;
++      compat_uint_t signr;
++      compat_caddr_t usercontext; /* unused */
++      struct usbdevfs_iso_packet_desc iso_frame_desc[0];
++};
++
++#define USBDEVFS_SUBMITURB32       _IOR('U', 10, struct usbdevfs_urb32)
++
++static int get_urb32(struct usbdevfs_urb *kurb,
++                   struct usbdevfs_urb32 *uurb)
++{
++      if (get_user(kurb->type, &uurb->type) ||
++          __get_user(kurb->endpoint, &uurb->endpoint) ||
++          __get_user(kurb->status, &uurb->status) ||
++          __get_user(kurb->flags, &uurb->flags) ||
++          __get_user(kurb->buffer_length, &uurb->buffer_length) ||
++          __get_user(kurb->actual_length, &uurb->actual_length) ||
++          __get_user(kurb->start_frame, &uurb->start_frame) ||
++          __get_user(kurb->number_of_packets, &uurb->number_of_packets) ||
++          __get_user(kurb->error_count, &uurb->error_count) ||
++          __get_user(kurb->signr, &uurb->signr))
++              return -EFAULT;
++
++      kurb->usercontext = 0; /* unused currently */
++
++      return 0;
++}
++
++/* Just put back the values which usbdevfs actually changes. */
++static int put_urb32(struct usbdevfs_urb *kurb,
++                   struct usbdevfs_urb32 *uurb)
++{
++      if (put_user(kurb->status, &uurb->status) ||
++          __put_user(kurb->actual_length, &uurb->actual_length) ||
++          __put_user(kurb->error_count, &uurb->error_count))
++              return -EFAULT;
++
++      if (kurb->number_of_packets != 0) {
++              int i;
++
++              for (i = 0; i < kurb->number_of_packets; i++) {
++                      if (__put_user(kurb->iso_frame_desc[i].actual_length,
++                                     &uurb->iso_frame_desc[i].actual_length) ||
++                          __put_user(kurb->iso_frame_desc[i].status,
++                                     &uurb->iso_frame_desc[i].status))
++                              return -EFAULT;
++              }
++      }
++
++      return 0;
++}
++
++static int get_urb32_isoframes(struct usbdevfs_urb *kurb,
++                             struct usbdevfs_urb32 *uurb)
++{
++      unsigned int totlen;
++      int i;
++
++      if (kurb->type != USBDEVFS_URB_TYPE_ISO) {
++              kurb->number_of_packets = 0;
++              return 0;
++      }
++
++      if (kurb->number_of_packets < 1 ||
++          kurb->number_of_packets > 128)
++              return -EINVAL;
++
++      if (copy_from_user(&kurb->iso_frame_desc[0],
++                         &uurb->iso_frame_desc[0],
++                         sizeof(struct usbdevfs_iso_packet_desc) *
++                         kurb->number_of_packets))
++              return -EFAULT;
++
++      totlen = 0;
++      for (i = 0; i < kurb->number_of_packets; i++) {
++              unsigned int this_len;
++
++              this_len = kurb->iso_frame_desc[i].length;
++              if (this_len > 1023)
++                      return -EINVAL;
++
++              totlen += this_len;
++      }
++
++      if (totlen > 32768)
++              return -EINVAL;
++
++      kurb->buffer_length = totlen;
++
++      return 0;
++}
++
++static int do_usbdevfs_urb(unsigned int fd, unsigned int cmd, unsigned long arg)
++{
++      struct usbdevfs_urb *kurb;
++      struct usbdevfs_urb32 *uurb;
++      mm_segment_t old_fs;
++      __u32 udata;
++      void *uptr, *kptr;
++      unsigned int buflen;
++      int err;
++
++      uurb = (struct usbdevfs_urb32 *) arg;
++
++      err = -ENOMEM;
++      kurb = kmalloc(sizeof(struct usbdevfs_urb) +
++                     (sizeof(struct usbdevfs_iso_packet_desc) * 128),
++                     GFP_KERNEL);
++      if (!kurb)
++              goto out;
++
++      err = -EFAULT;
++      if (get_urb32(kurb, uurb))
++              goto out;
++
++      err = get_urb32_isoframes(kurb, uurb);
++      if (err)
++              goto out;
++
++      err = -EFAULT;
++      if (__get_user(udata, &uurb->buffer))
++              goto out;
++      uptr = compat_ptr(udata);
++
++      buflen = kurb->buffer_length;
++      err = verify_area(VERIFY_WRITE, uptr, buflen);
++      if (err)
++              goto out;
++
++
++      old_fs = get_fs();
++      set_fs(KERNEL_DS);
++      err = sys_ioctl(fd, USBDEVFS_SUBMITURB, (unsigned long) kurb);
++      set_fs(old_fs);
++
++      if (err >= 0) {
++              /* RED-PEN Shit, this doesn't work for async URBs :-( XXX */
++              if (put_urb32(kurb, uurb)) {
++                      err = -EFAULT;
++              }
++      }
++
++out:
++      kfree(kurb);
++      return err;
++}
++#endif
++
++#define USBDEVFS_REAPURB32         _IOW('U', 12, u32)
++#define USBDEVFS_REAPURBNDELAY32   _IOW('U', 13, u32)
++
++static int do_usbdevfs_reapurb(unsigned int fd, unsigned int cmd, unsigned long arg)
++{
++        mm_segment_t old_fs;
++        void *kptr;
++        int err;
++
++        old_fs = get_fs();
++        set_fs(KERNEL_DS);
++        err = sys_ioctl(fd,
++                        (cmd == USBDEVFS_REAPURB32 ?
++                         USBDEVFS_REAPURB :
++                         USBDEVFS_REAPURBNDELAY),
++                        (unsigned long) &kptr);
++        set_fs(old_fs);
++
++        if (err >= 0 &&
++            put_user((u32)(u64)kptr, (u32 *)arg))
++                err = -EFAULT;
++
++        return err;
++}
++
++struct usbdevfs_disconnectsignal32 {
++        compat_int_t signr;
++        compat_caddr_t context;
++};
++
++#define USBDEVFS_DISCSIGNAL32      _IOR('U', 14, struct usbdevfs_disconnectsignal32)
++
++static int do_usbdevfs_discsignal(unsigned int fd, unsigned int cmd, unsigned long arg)
++{
++        struct usbdevfs_disconnectsignal kdis;
++        struct usbdevfs_disconnectsignal32 *udis;
++        mm_segment_t old_fs;
++        u32 uctx;
++        int err;
++
++        udis = (struct usbdevfs_disconnectsignal32 *) arg;
++
++        if (get_user(kdis.signr, &udis->signr) ||
++            __get_user(uctx, &udis->context))
++                return -EFAULT;
++
++        kdis.context = (void *) (long)uctx;
++
++        old_fs = get_fs();
++        set_fs(KERNEL_DS);
++        err = sys_ioctl(fd, USBDEVFS_DISCSIGNAL, (unsigned long) &kdis);
++        set_fs(old_fs);
++
++        return err;
++}
+ #undef CODE
+ #endif
+@@ -2451,6 +3010,22 @@ HANDLE_IOCTL(SONET_GETFRSENSE, do_atm_io
+ HANDLE_IOCTL(BLKBSZGET_32, do_blkbszget)
+ HANDLE_IOCTL(BLKBSZSET_32, do_blkbszset)
+ HANDLE_IOCTL(BLKGETSIZE64_32, do_blkgetsize64)
+-
++/* vfat */
++HANDLE_IOCTL(VFAT_IOCTL_READDIR_BOTH32, vfat_ioctl32)
++HANDLE_IOCTL(VFAT_IOCTL_READDIR_SHORT32, vfat_ioctl32)
++HANDLE_IOCTL(REISERFS_IOC_UNPACK32, reiserfs_ioctl32)
++/* Raw devices */
++HANDLE_IOCTL(RAW_SETBIND, raw_ioctl)
++HANDLE_IOCTL(RAW_GETBIND, raw_ioctl)
++/* Serial */
++HANDLE_IOCTL(TIOCGSERIAL, serial_struct_ioctl)
++HANDLE_IOCTL(TIOCSSERIAL, serial_struct_ioctl)
++/* Usbdevfs */
++HANDLE_IOCTL(USBDEVFS_CONTROL32, do_usbdevfs_control)
++HANDLE_IOCTL(USBDEVFS_BULK32, do_usbdevfs_bulk)
++/*HANDLE_IOCTL(USBDEVFS_SUBMITURB32, do_usbdevfs_urb)*/
++HANDLE_IOCTL(USBDEVFS_REAPURB32, do_usbdevfs_reapurb)
++HANDLE_IOCTL(USBDEVFS_REAPURBNDELAY32, do_usbdevfs_reapurb)
++HANDLE_IOCTL(USBDEVFS_DISCSIGNAL32, do_usbdevfs_discsignal)
+ #undef DECLARES
+ #endif
+--- linux-2.6.0-test6/fs/dcache.c      2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/dcache.c     2003-10-05 00:33:24.000000000 -0700
+@@ -1639,3 +1639,27 @@ void __init vfs_caches_init(unsigned lon
+       bdev_cache_init();
+       chrdev_init();
+ }
++
++EXPORT_SYMBOL(d_alloc);
++EXPORT_SYMBOL(d_alloc_anon);
++EXPORT_SYMBOL(d_alloc_root);
++EXPORT_SYMBOL(d_delete);
++EXPORT_SYMBOL(d_find_alias);
++EXPORT_SYMBOL(d_instantiate);
++EXPORT_SYMBOL(d_invalidate);
++EXPORT_SYMBOL(d_lookup);
++EXPORT_SYMBOL(d_move);
++EXPORT_SYMBOL(d_path);
++EXPORT_SYMBOL(d_prune_aliases);
++EXPORT_SYMBOL(d_rehash);
++EXPORT_SYMBOL(d_splice_alias);
++EXPORT_SYMBOL(d_validate);
++EXPORT_SYMBOL(dget_locked);
++EXPORT_SYMBOL(dput);
++EXPORT_SYMBOL(find_inode_number);
++EXPORT_SYMBOL(have_submounts);
++EXPORT_SYMBOL(is_subdir);
++EXPORT_SYMBOL(names_cachep);
++EXPORT_SYMBOL(shrink_dcache_anon);
++EXPORT_SYMBOL(shrink_dcache_parent);
++EXPORT_SYMBOL(shrink_dcache_sb);
+--- linux-2.6.0-test6/fs/devfs/base.c  2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/devfs/base.c 2003-10-05 00:36:10.000000000 -0700
+@@ -973,8 +973,9 @@ static struct devfs_entry *_devfs_search
+ /**
+  *    _devfs_alloc_entry - Allocate a devfs entry.
+- *    @name:  The name of the entry.
+- *    @namelen:  The number of characters in @name.
++ *    @name:     the name of the entry
++ *    @namelen:  the number of characters in @name
++ *      @mode:     the mode for the entry
+  *
+  *  Allocate a devfs entry and returns a pointer to the entry on success, else
+  *   %NULL.
+@@ -1954,15 +1955,9 @@ static int devfs_notify_change (struct d
+     return 0;
+ }   /*  End Function devfs_notify_change  */
+-static void devfs_clear_inode (struct inode *inode)
+-{
+-    if ( S_ISBLK (inode->i_mode) ) bdput (inode->i_bdev);
+-}   /*  End Function devfs_clear_inode  */
+-
+ static struct super_operations devfs_sops =
+ { 
+     .drop_inode    = generic_delete_inode,
+-    .clear_inode   = devfs_clear_inode,
+     .statfs        = simple_statfs,
+ };
+@@ -2014,11 +2009,7 @@ static struct inode *_devfs_get_vfs_inod
+       inode->i_rdev = de->u.cdev.dev;
+     }
+     else if ( S_ISBLK (de->mode) )
+-    {
+-      inode->i_rdev = de->u.bdev.dev;
+-      if (bd_acquire (inode) != 0)
+-              PRINTK ("(%d): no block device from bdget()\n",(int)inode->i_ino);
+-    }
++      init_special_inode(inode, de->mode, de->u.bdev.dev);
+     else if ( S_ISFIFO (de->mode) )
+       inode->i_fop = &def_fifo_fops;
+     else if ( S_ISDIR (de->mode) )
+@@ -2117,11 +2108,7 @@ static int devfs_open (struct inode *ino
+     if (de == NULL) return -ENODEV;
+     if ( S_ISDIR (de->mode) ) return 0;
+     file->private_data = de->info;
+-    if ( S_ISBLK (inode->i_mode) )
+-    {
+-      file->f_op = &def_blk_fops;
+-      err = def_blk_fops.open (inode, file); /* Module refcount unchanged */
+-    } else if (S_ISCHR(inode->i_mode)) {
++    if (S_ISCHR(inode->i_mode)) {
+       ops = devfs_get_ops (de);  /*  Now have module refcount  */
+       file->f_op = ops;
+       if (file->f_op)
+--- linux-2.6.0-test6/fs/direct-io.c   2003-08-08 22:55:13.000000000 -0700
++++ 25/fs/direct-io.c  2003-10-05 00:36:53.000000000 -0700
+@@ -51,6 +51,10 @@
+  *
+  * If blkfactor is zero then the user's request was aligned to the filesystem's
+  * blocksize.
++ *
++ * needs_locking is set for regular files on direct-IO-naive filesystems.  It
++ * determines whether we need to do the fancy locking which prevents direct-IO
++ * from being able to read uninitialised disk blocks.
+  */
+ struct dio {
+@@ -58,6 +62,7 @@ struct dio {
+       struct bio *bio;                /* bio under assembly */
+       struct inode *inode;
+       int rw;
++      int needs_locking;              /* doesn't change */
+       unsigned blkbits;               /* doesn't change */
+       unsigned blkfactor;             /* When we're using an alignment which
+                                          is finer than the filesystem's soft
+@@ -205,6 +210,8 @@ static void dio_complete(struct dio *dio
+ {
+       if (dio->end_io)
+               dio->end_io(dio->inode, offset, bytes, dio->map_bh.b_private);
++      if (dio->needs_locking)
++              up_read(&dio->inode->i_alloc_sem);
+ }
+ /*
+@@ -448,6 +455,7 @@ static int get_more_blocks(struct dio *d
+       unsigned long fs_count; /* Number of filesystem-sized blocks */
+       unsigned long dio_count;/* Number of dio_block-sized blocks */
+       unsigned long blkmask;
++      int beyond_eof = 0;
+       /*
+        * If there was a memory error and we've overwritten all the
+@@ -465,8 +473,19 @@ static int get_more_blocks(struct dio *d
+               if (dio_count & blkmask)        
+                       fs_count++;
++              if (dio->needs_locking) {
++                      if (dio->block_in_file >= (i_size_read(dio->inode) >>
++                                                      dio->blkbits))
++                              beyond_eof = 1;
++              }
++              /*
++               * For writes inside i_size we forbid block creations: only
++               * overwrites are permitted.  We fall back to buffered writes
++               * at a higher level for inside-i_size block-instantiating
++               * writes.
++               */
+               ret = (*dio->get_blocks)(dio->inode, fs_startblk, fs_count,
+-                              map_bh, dio->rw == WRITE);
++                              map_bh, (dio->rw == WRITE) && beyond_eof);
+       }
+       return ret;
+ }
+@@ -773,6 +792,10 @@ do_holes:
+                       if (!buffer_mapped(map_bh)) {
+                               char *kaddr;
++                              /* AKPM: eargh, -ENOTBLK is a hack */
++                              if (dio->rw == WRITE)
++                                      return -ENOTBLK;
++
+                               if (dio->block_in_file >=
+                                       i_size_read(dio->inode)>>blkbits) {
+                                       /* We hit eof */
+@@ -838,21 +861,21 @@ out:
+       return ret;
+ }
++/*
++ * Releases both i_sem and i_alloc_sem
++ */
+ static int
+ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, 
+       const struct iovec *iov, loff_t offset, unsigned long nr_segs, 
+-      unsigned blkbits, get_blocks_t get_blocks, dio_iodone_t end_io)
++      unsigned blkbits, get_blocks_t get_blocks, dio_iodone_t end_io,
++      struct dio *dio)
+ {
+       unsigned long user_addr; 
+       int seg;
+       int ret = 0;
+       int ret2;
+-      struct dio *dio;
+       size_t bytes;
+-      dio = kmalloc(sizeof(*dio), GFP_KERNEL);
+-      if (!dio)
+-              return -ENOMEM;
+       dio->is_async = !is_sync_kiocb(iocb);
+       dio->bio = NULL;
+@@ -863,7 +886,6 @@ direct_io_worker(int rw, struct kiocb *i
+       dio->start_zero_done = 0;
+       dio->block_in_file = offset >> blkbits;
+       dio->blocks_available = 0;
+-
+       dio->cur_page = NULL;
+       dio->boundary = 0;
+@@ -946,6 +968,13 @@ direct_io_worker(int rw, struct kiocb *i
+               dio_bio_submit(dio);
+       /*
++       * All new block allocations have been performed.  We can let i_sem
++       * go now.
++       */
++      if (dio->needs_locking)
++              up(&dio->inode->i_sem);
++
++      /*
+        * OK, all BIOs are submitted, so we can decrement bio_count to truly
+        * reflect the number of to-be-processed BIOs.
+        */
+@@ -980,11 +1009,17 @@ direct_io_worker(int rw, struct kiocb *i
+ /*
+  * This is a library function for use by filesystem drivers.
++ *
++ * For writes to S_ISREG files, we are called under i_sem and return with i_sem
++ * held, even though it is internally dropped.
++ *
++ * For writes to S_ISBLK files, i_sem is not held on entry; it is never taken.
+  */
+ int
+-blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, 
++__blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
+       struct block_device *bdev, const struct iovec *iov, loff_t offset, 
+-      unsigned long nr_segs, get_blocks_t get_blocks, dio_iodone_t end_io)
++      unsigned long nr_segs, get_blocks_t get_blocks, dio_iodone_t end_io,
++      int needs_special_locking)
+ {
+       int seg;
+       size_t size;
+@@ -993,6 +1028,8 @@ blockdev_direct_IO(int rw, struct kiocb 
+       unsigned bdev_blkbits = 0;
+       unsigned blocksize_mask = (1 << blkbits) - 1;
+       ssize_t retval = -EINVAL;
++      struct dio *dio;
++      int needs_locking;
+       if (bdev)
+               bdev_blkbits = blksize_bits(bdev_hardsect_size(bdev));
+@@ -1018,8 +1055,37 @@ blockdev_direct_IO(int rw, struct kiocb 
+               }
+       }
+-      retval = direct_io_worker(rw, iocb, inode, iov, offset, 
+-                              nr_segs, blkbits, get_blocks, end_io);
++      dio = kmalloc(sizeof(*dio), GFP_KERNEL);
++      retval = -ENOMEM;
++      if (!dio)
++              goto out;
++
++      /*
++       * For regular files,
++       *      readers need to grab i_sem and i_alloc_sem
++       *      writers need to grab i_alloc_sem only (i_sem is already held)
++       */
++      needs_locking = 0;
++      if (S_ISREG(inode->i_mode) && needs_special_locking) {
++              needs_locking = 1;
++              if (rw == READ) {
++                      down(&inode->i_sem);
++                      retval = filemap_write_and_wait(inode->i_mapping);
++                      if (retval) {
++                              up(&inode->i_sem);
++                              kfree(dio);
++                              goto out;
++                      }
++              }
++              down_read(&inode->i_alloc_sem);
++      }
++      dio->needs_locking = needs_locking;
++
++      retval = direct_io_worker(rw, iocb, inode, iov, offset,
++                              nr_segs, blkbits, get_blocks, end_io, dio);
++      if (needs_locking && rw == WRITE)
++              down(&inode->i_sem);
+ out:
+       return retval;
+ }
++EXPORT_SYMBOL(__blockdev_direct_IO);
+--- linux-2.6.0-test6/fs/dquot.c       2003-07-10 18:50:31.000000000 -0700
++++ 25/fs/dquot.c      2003-10-05 00:36:15.000000000 -0700
+@@ -668,12 +668,12 @@ static void print_warning(struct dquot *
+       if (!need_print_warning(dquot) || (flag && test_and_set_bit(flag, &dquot->dq_flags)))
+               return;
+-      tty_write_message(current->tty, dquot->dq_sb->s_id);
++      tty_write_message(process_tty(current), dquot->dq_sb->s_id);
+       if (warntype == ISOFTWARN || warntype == BSOFTWARN)
+-              tty_write_message(current->tty, ": warning, ");
++              tty_write_message(process_tty(current), ": warning, ");
+       else
+-              tty_write_message(current->tty, ": write failed, ");
+-      tty_write_message(current->tty, quotatypes[dquot->dq_type]);
++              tty_write_message(process_tty(current), ": write failed, ");
++      tty_write_message(process_tty(current), quotatypes[dquot->dq_type]);
+       switch (warntype) {
+               case IHARDWARN:
+                       msg = " file limit reached.\n";
+@@ -694,7 +694,7 @@ static void print_warning(struct dquot *
+                       msg = " block quota exceeded.\n";
+                       break;
+       }
+-      tty_write_message(current->tty, msg);
++      tty_write_message(process_tty(current), msg);
+ }
+ static inline void flush_warnings(struct dquot **dquots, char *warntype)
+--- linux-2.6.0-test6/fs/efs/super.c   2003-06-22 12:04:44.000000000 -0700
++++ 25/fs/efs/super.c  2003-10-05 00:33:24.000000000 -0700
+@@ -218,7 +218,11 @@ int efs_fill_super(struct super_block *s
+       memset(sb, 0, sizeof(struct efs_sb_info));
+  
+       s->s_magic              = EFS_SUPER_MAGIC;
+-      sb_set_blocksize(s, EFS_BLOCKSIZE);
++      if (!sb_set_blocksize(s, EFS_BLOCKSIZE)) {
++              printk(KERN_ERR "EFS: device does not support %d byte blocks\n",
++                      EFS_BLOCKSIZE);
++              goto out_no_fs_ul;
++      }
+   
+       /* read the vh (volume header) block */
+       bh = sb_bread(s, 0);
+--- linux-2.6.0-test6/fs/eventpoll.c   2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/eventpoll.c  2003-10-05 00:34:03.000000000 -0700
+@@ -740,6 +740,7 @@ static int ep_getfd(int *efd, struct ino
+       d_add(dentry, inode);
+       file->f_vfsmnt = mntget(eventpoll_mnt);
+       file->f_dentry = dget(dentry);
++      file->f_mapping = inode->i_mapping;
+       file->f_pos = 0;
+       file->f_flags = O_RDONLY;
+--- linux-2.6.0-test6/fs/exec.c        2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/exec.c       2003-10-05 00:36:15.000000000 -0700
+@@ -83,6 +83,8 @@ int register_binfmt(struct linux_binfmt 
+       return 0;       
+ }
++EXPORT_SYMBOL(register_binfmt);
++
+ int unregister_binfmt(struct linux_binfmt * fmt)
+ {
+       struct linux_binfmt ** tmp = &formats;
+@@ -100,6 +102,8 @@ int unregister_binfmt(struct linux_binfm
+       return -EINVAL;
+ }
++EXPORT_SYMBOL(unregister_binfmt);
++
+ static inline void put_binfmt(struct linux_binfmt * fmt)
+ {
+       module_put(fmt->module);
+@@ -281,6 +285,8 @@ int copy_strings_kernel(int argc,char **
+       return r;
+ }
++EXPORT_SYMBOL(copy_strings_kernel);
++
+ #ifdef CONFIG_MMU
+ /*
+  * This routine is used to map in a page into an address space: needed by
+@@ -443,6 +449,8 @@ int setup_arg_pages(struct linux_binprm 
+       return 0;
+ }
++EXPORT_SYMBOL(setup_arg_pages);
++
+ #define free_arg_pages(bprm) do { } while (0)
+ #else
+@@ -493,6 +501,8 @@ out:
+       goto out;
+ }
++EXPORT_SYMBOL(open_exec);
++
+ int kernel_read(struct file *file, unsigned long offset,
+       char *addr, unsigned long count)
+ {
+@@ -508,6 +518,8 @@ int kernel_read(struct file *file, unsig
+       return result;
+ }
++EXPORT_SYMBOL(kernel_read);
++
+ static int exec_mmap(struct mm_struct *mm)
+ {
+       struct task_struct *tsk;
+@@ -584,6 +596,11 @@ static inline int de_thread(struct task_
+               newsig->group_stop_count = 0;
+               newsig->curr_target = NULL;
+               init_sigpending(&newsig->shared_pending);
++
++              newsig->pgrp = oldsig->pgrp;
++              newsig->session = oldsig->session;
++              newsig->leader = oldsig->leader;
++              newsig->tty_old_pgrp = oldsig->tty_old_pgrp;
+       }
+       if (thread_group_empty(current))
+@@ -822,6 +839,8 @@ out:
+       return retval;
+ }
++EXPORT_SYMBOL(flush_old_exec);
++
+ /*
+  * We mustn't allow tracing of suid binaries, unless
+  * the tracer has the capability to trace anything..
+@@ -878,6 +897,8 @@ int prepare_binprm(struct linux_binprm *
+       return kernel_read(bprm->file,0,bprm->buf,BINPRM_BUF_SIZE);
+ }
++EXPORT_SYMBOL(prepare_binprm);
++
+ /*
+  * This function is used to produce the new IDs and capabilities
+  * from the old ones and the file's capabilities.
+@@ -918,6 +939,8 @@ void compute_creds(struct linux_binprm *
+       security_bprm_compute_creds(bprm);
+ }
++EXPORT_SYMBOL(compute_creds);
++
+ void remove_arg_zero(struct linux_binprm *bprm)
+ {
+       if (bprm->argc) {
+@@ -942,6 +965,8 @@ inside:
+       }
+ }
++EXPORT_SYMBOL(remove_arg_zero);
++
+ /*
+  * cycle the list of binary formats handler, until one recognizes the image
+  */
+@@ -1037,6 +1062,8 @@ int search_binary_handler(struct linux_b
+       return retval;
+ }
++EXPORT_SYMBOL(search_binary_handler);
++
+ /*
+  * sys_execve() executes a new program.
+  */
+@@ -1133,6 +1160,8 @@ out_file:
+       return retval;
+ }
++EXPORT_SYMBOL(do_execve);
++
+ int set_binfmt(struct linux_binfmt *new)
+ {
+       struct linux_binfmt *old = current->binfmt;
+@@ -1147,6 +1176,8 @@ int set_binfmt(struct linux_binfmt *new)
+       return 0;
+ }
++EXPORT_SYMBOL(set_binfmt);
++
+ #define CORENAME_MAX_SIZE 64
+ /* format_corename will inspect the pattern parameter, and output a
+--- linux-2.6.0-test6/fs/ext2/inode.c  2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/ext2/inode.c 2003-10-05 00:36:59.000000000 -0700
+@@ -257,11 +257,12 @@ static int ext2_block_to_path(struct ino
+  *    or when it reads all @depth-1 indirect blocks successfully and finds
+  *    the whole chain, all way to the data (returns %NULL, *err == 0).
+  */
+-static Indirect *ext2_get_branch(struct inode *inode,
++static Indirect *ext2_get_branch_wq(struct inode *inode,
+                                int depth,
+                                int *offsets,
+                                Indirect chain[4],
+-                               int *err)
++                               int *err,
++                               wait_queue_t *wait)
+ {
+       struct super_block *sb = inode->i_sb;
+       Indirect *p = chain;
+@@ -273,8 +274,8 @@ static Indirect *ext2_get_branch(struct 
+       if (!p->key)
+               goto no_block;
+       while (--depth) {
+-              bh = sb_bread(sb, le32_to_cpu(p->key));
+-              if (!bh)
++              bh = sb_bread_wq(sb, le32_to_cpu(p->key), wait);
++              if (!bh || IS_ERR(bh))
+                       goto failure;
+               read_lock(&EXT2_I(inode)->i_meta_lock);
+               if (!verify_chain(chain, p))
+@@ -292,11 +293,21 @@ changed:
+       *err = -EAGAIN;
+       goto no_block;
+ failure:
+-      *err = -EIO;
++      *err = IS_ERR(bh) ? PTR_ERR(bh) : -EIO;
+ no_block:
+       return p;
+ }
++static Indirect *ext2_get_branch(struct inode *inode,
++                               int depth,
++                               int *offsets,
++                               Indirect chain[4],
++                               int *err)
++{
++      return ext2_get_branch_wq(inode, depth, offsets, chain,
++              err, NULL);
++}
++
+ /**
+  *    ext2_find_near - find a place for allocation with sufficient locality
+  *    @inode: owner
+@@ -536,7 +547,8 @@ changed:
+  * reachable from inode.
+  */
+-static int ext2_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create)
++static int ext2_get_block_wq(struct inode *inode, sector_t iblock,
++      struct buffer_head *bh_result, int create, wait_queue_t *wait)
+ {
+       int err = -EIO;
+       int offsets[4];
+@@ -551,7 +563,8 @@ static int ext2_get_block(struct inode *
+               goto out;
+ reread:
+-      partial = ext2_get_branch(inode, depth, offsets, chain, &err);
++      partial = ext2_get_branch_wq(inode, depth, offsets, chain, &err,
++              wait);
+       /* Simplest case - block found, no allocation needed */
+       if (!partial) {
+@@ -565,7 +578,7 @@ got_it:
+       }
+       /* Next simple case - plain lookup or failed read of indirect block */
+-      if (!create || err == -EIO) {
++      if (!create || err == -EIO || err == -EIOCBRETRY) {
+ cleanup:
+               while (partial > chain) {
+                       brelse(partial->bh);
+@@ -606,6 +619,19 @@ changed:
+       goto reread;
+ }
++static int ext2_get_block_async(struct inode *inode, sector_t iblock,
++      struct buffer_head *bh_result, int create)
++{
++      return ext2_get_block_wq(inode, iblock, bh_result, create,
++              current->io_wait);
++}
++
++static int ext2_get_block(struct inode *inode, sector_t iblock,
++      struct buffer_head *bh_result, int create)
++{
++      return ext2_get_block_wq(inode, iblock, bh_result, create, NULL);
++}
++
+ static int ext2_writepage(struct page *page, struct writeback_control *wbc)
+ {
+       return block_write_full_page(page, ext2_get_block, wbc);
+@@ -627,7 +653,7 @@ static int
+ ext2_prepare_write(struct file *file, struct page *page,
+                       unsigned from, unsigned to)
+ {
+-      return block_prepare_write(page,from,to,ext2_get_block);
++      return block_prepare_write(page,from,to,ext2_get_block_async);
+ }
+ static int
+@@ -659,7 +685,7 @@ ext2_direct_IO(int rw, struct kiocb *ioc
+                       loff_t offset, unsigned long nr_segs)
+ {
+       struct file *file = iocb->ki_filp;
+-      struct inode *inode = file->f_dentry->d_inode->i_mapping->host;
++      struct inode *inode = file->f_mapping->host;
+       return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
+                               offset, nr_segs, ext2_get_blocks, NULL);
+@@ -1228,6 +1254,7 @@ static int ext2_update_inode(struct inod
+                       raw_inode->i_block[0] = 0;
+                       raw_inode->i_block[1] =
+                               cpu_to_le32(new_encode_dev(inode->i_rdev));
++                      raw_inode->i_block[2] = 0;
+               }
+       } else for (n = 0; n < EXT2_N_BLOCKS; n++)
+               raw_inode->i_block[n] = ei->i_data[n];
+--- linux-2.6.0-test6/fs/ext2/super.c  2003-07-10 18:50:31.000000000 -0700
++++ 25/fs/ext2/super.c 2003-10-05 00:33:24.000000000 -0700
+@@ -22,6 +22,7 @@
+ #include <linux/slab.h>
+ #include <linux/init.h>
+ #include <linux/blkdev.h>
++#include <linux/parser.h>
+ #include <linux/random.h>
+ #include <linux/buffer_head.h>
+ #include <linux/smp_lock.h>
+@@ -265,149 +266,157 @@ static unsigned long get_sb_block(void *
+       return sb_block;
+ }
+-static int want_value(char *value, char *option)
+-{
+-      if (!value || !*value) {
+-              printk(KERN_NOTICE "EXT2-fs: the %s option needs an argument\n",
+-                     option);
+-              return -1;
+-      }
+-      return 0;
+-}
+-
+-static int want_null_value(char *value, char *option)
+-{
+-      if (*value) {
+-              printk(KERN_NOTICE "EXT2-fs: Invalid %s argument: %s\n",
+-                     option, value);
+-              return -1;
+-      }
+-      return 0;
+-}
++enum {
++      Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid,
++      Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro,
++      Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov, Opt_nobh,
++      Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl,
++      Opt_ignore, Opt_err,
++};
+-static int want_numeric(char *value, char *option, unsigned long *number)
+-{
+-      if (want_value(value, option))
+-              return -1;
+-      *number = simple_strtoul(value, &value, 0);
+-      if (want_null_value(value, option))
+-              return -1;
+-      return 0;
+-}
++static match_table_t tokens = {
++      {Opt_bsd_df, "bsddf"},
++      {Opt_minix_df, "minixdf"},
++      {Opt_grpid, "grpid"},
++      {Opt_grpid, "bsdgroups"},
++      {Opt_nogrpid, "nogrpid"},
++      {Opt_nogrpid, "sysvgroups"},
++      {Opt_resgid, "resgid=%d"},
++      {Opt_resuid, "resuid=%d"},
++      {Opt_sb, "sb=%d"},
++      {Opt_err_cont, "errors=continue"},
++      {Opt_err_panic, "errors=panic"},
++      {Opt_err_ro, "errors=remount-ro"},
++      {Opt_nouid32, "nouid32"},
++      {Opt_nocheck, "check=none"},
++      {Opt_nocheck, "nocheck"},
++      {Opt_check, "check"},
++      {Opt_debug, "debug"},
++      {Opt_oldalloc, "oldalloc"},
++      {Opt_orlov, "orlov"},
++      {Opt_nobh, "nobh"},
++      {Opt_user_xattr, "user_xattr"},
++      {Opt_nouser_xattr, "nouser_xattr"},
++      {Opt_acl, "acl"},
++      {Opt_noacl, "noacl"},
++      {Opt_ignore, "grpquota"},
++      {Opt_ignore, "noquota"},
++      {Opt_ignore, "quota"},
++      {Opt_ignore, "usrquota"},
++      {Opt_err, NULL}
++};
+-/*
+- * This function has been shamelessly adapted from the msdos fs
+- */
+ static int parse_options (char * options,
+                         struct ext2_sb_info *sbi)
+ {
+-      char * this_char;
+-      char * value;
++      char * p;
++      substring_t args[MAX_OPT_ARGS];
++      unsigned long kind = EXT2_MOUNT_ERRORS_CONT;
++      int option;
+       if (!options)
+               return 1;
+-      while ((this_char = strsep (&options, ",")) != NULL) {
+-              if (!*this_char)
++
++      while ((p = strsep (&options, ",")) != NULL) {
++              int token;
++              if (!*p)
+                       continue;
+-              if ((value = strchr (this_char, '=')) != NULL)
+-                      *value++ = 0;
++
++              token = match_token(p, tokens, args);
++              switch (token) {
++              case Opt_bsd_df:
++                      clear_opt (sbi->s_mount_opt, MINIX_DF);
++                      break;
++              case Opt_minix_df:
++                      set_opt (sbi->s_mount_opt, MINIX_DF);
++                      break;
++              case Opt_grpid:
++                      set_opt (sbi->s_mount_opt, GRPID);
++                      break;
++              case Opt_nogrpid:
++                      clear_opt (sbi->s_mount_opt, GRPID);
++                      break;
++              case Opt_resuid:
++                      if (match_int(&args[0], &option))
++                              return 0;
++                      sbi->s_resuid = option;
++                      break;
++              case Opt_resgid:
++                      if (match_int(&args[0], &option))
++                              return 0;
++                      sbi->s_resgid = option;
++                      break;
++              case Opt_sb:
++                      /* handled by get_sb_block() instead of here */
++                      /* *sb_block = match_int(&args[0]); */
++                      break;
++              case Opt_err_panic:
++                      kind = EXT2_MOUNT_ERRORS_PANIC;
++                      break;
++              case Opt_err_ro:
++                      kind = EXT2_MOUNT_ERRORS_RO;
++                      break;
++              case Opt_err_cont:
++                      kind = EXT2_MOUNT_ERRORS_CONT;
++                      break;
++              case Opt_nouid32:
++                      set_opt (sbi->s_mount_opt, NO_UID32);
++                      break;
++              case Opt_check:
++#ifdef CONFIG_EXT2_CHECK
++                      set_opt (sbi->s_mount_opt, CHECK);
++#else
++                      printk("EXT2 Check option not supported\n");
++#endif
++                      break;
++              case Opt_nocheck:
++                      clear_opt (sbi->s_mount_opt, CHECK);
++                      break;
++              case Opt_debug:
++                      set_opt (sbi->s_mount_opt, DEBUG);
++                      break;
++              case Opt_oldalloc:
++                      set_opt (sbi->s_mount_opt, OLDALLOC);
++                      break;
++              case Opt_orlov:
++                      clear_opt (sbi->s_mount_opt, OLDALLOC);
++                      break;
++              case Opt_nobh:
++                      set_opt (sbi->s_mount_opt, NOBH);
++                      break;
+ #ifdef CONFIG_EXT2_FS_XATTR
+-              if (!strcmp (this_char, "user_xattr"))
++              case Opt_user_xattr:
+                       set_opt (sbi->s_mount_opt, XATTR_USER);
+-              else if (!strcmp (this_char, "nouser_xattr"))
++                      break;
++              case Opt_nouser_xattr:
+                       clear_opt (sbi->s_mount_opt, XATTR_USER);
+-              else
++                      break;
++#else
++              case Opt_user_xattr:
++              case Opt_nouser_xattr:
++                      printk("EXT2 (no)user_xattr options not supported\n");
++                      break;
+ #endif
+ #ifdef CONFIG_EXT2_FS_POSIX_ACL
+-              if (!strcmp(this_char, "acl"))
++              case Opt_acl:
+                       set_opt(sbi->s_mount_opt, POSIX_ACL);
+-              else if (!strcmp(this_char, "noacl"))
++                      break;
++              case Opt_noacl:
+                       clear_opt(sbi->s_mount_opt, POSIX_ACL);
+-              else
+-#endif
+-              if (!strcmp (this_char, "bsddf"))
+-                      clear_opt (sbi->s_mount_opt, MINIX_DF);
+-              else if (!strcmp (this_char, "nouid32")) {
+-                      set_opt (sbi->s_mount_opt, NO_UID32);
+-              }
+-              else if (!strcmp (this_char, "check")) {
+-                      if (!value || !*value || !strcmp (value, "none"))
+-                              clear_opt (sbi->s_mount_opt, CHECK);
+-                      else
+-#ifdef CONFIG_EXT2_CHECK
+-                              set_opt (sbi->s_mount_opt, CHECK);
++                      break;
+ #else
+-                              printk("EXT2 Check option not supported\n");
++              case Opt_acl:
++              case Opt_noacl:
++                      printk("EXT2 (no)acl options not supported\n");
++                      break;
+ #endif
+-              }
+-              else if (!strcmp (this_char, "debug"))
+-                      set_opt (sbi->s_mount_opt, DEBUG);
+-              else if (!strcmp (this_char, "errors")) {
+-                      if (!value || !*value) {
+-                              printk ("EXT2-fs: the errors option requires "
+-                                      "an argument\n");
+-                              return 0;
+-                      }
+-                      if (!strcmp (value, "continue")) {
+-                              clear_opt (sbi->s_mount_opt, ERRORS_RO);
+-                              clear_opt (sbi->s_mount_opt, ERRORS_PANIC);
+-                              set_opt (sbi->s_mount_opt, ERRORS_CONT);
+-                      }
+-                      else if (!strcmp (value, "remount-ro")) {
+-                              clear_opt (sbi->s_mount_opt, ERRORS_CONT);
+-                              clear_opt (sbi->s_mount_opt, ERRORS_PANIC);
+-                              set_opt (sbi->s_mount_opt, ERRORS_RO);
+-                      }
+-                      else if (!strcmp (value, "panic")) {
+-                              clear_opt (sbi->s_mount_opt, ERRORS_CONT);
+-                              clear_opt (sbi->s_mount_opt, ERRORS_RO);
+-                              set_opt (sbi->s_mount_opt, ERRORS_PANIC);
+-                      }
+-                      else {
+-                              printk ("EXT2-fs: Invalid errors option: %s\n",
+-                                      value);
+-                              return 0;
+-                      }
+-              }
+-              else if (!strcmp (this_char, "grpid") ||
+-                       !strcmp (this_char, "bsdgroups"))
+-                      set_opt (sbi->s_mount_opt, GRPID);
+-              else if (!strcmp (this_char, "minixdf"))
+-                      set_opt (sbi->s_mount_opt, MINIX_DF);
+-              else if (!strcmp (this_char, "nocheck"))
+-                      clear_opt (sbi->s_mount_opt, CHECK);
+-              else if (!strcmp (this_char, "nogrpid") ||
+-                       !strcmp (this_char, "sysvgroups"))
+-                      clear_opt (sbi->s_mount_opt, GRPID);
+-              else if (!strcmp (this_char, "resgid")) {
+-                      unsigned long v;
+-                      if (want_numeric(value, "resgid", &v))
+-                              return 0;
+-                      sbi->s_resgid = v;
+-              }
+-              else if (!strcmp (this_char, "resuid")) {
+-                      unsigned long v;
+-                      if (want_numeric(value, "resuid", &v))
+-                              return 0;
+-                      sbi->s_resuid = v;
+-              }
+-              else if (!strcmp (this_char, "oldalloc"))
+-                      set_opt (sbi->s_mount_opt, OLDALLOC);
+-              else if (!strcmp (this_char, "orlov"))
+-                      clear_opt (sbi->s_mount_opt, OLDALLOC);
+-              else if (!strcmp (this_char, "nobh"))
+-                      set_opt(sbi->s_mount_opt, NOBH);
+-              /* Silently ignore the quota options */
+-              else if (!strcmp (this_char, "grpquota")
+-                       || !strcmp (this_char, "noquota")
+-                       || !strcmp (this_char, "quota")
+-                       || !strcmp (this_char, "usrquota"))
+-                      /* Don't do anything ;-) */ ;
+-              else {
+-                      printk ("EXT2-fs: Unrecognized mount option %s\n", this_char);
++              case Opt_ignore:
++                      break;
++              default:
+                       return 0;
+               }
+       }
++      sbi->s_mount_opt |= kind;
+       return 1;
+ }
+--- linux-2.6.0-test6/fs/ext3/file.c   2003-08-08 22:55:13.000000000 -0700
++++ 25/fs/ext3/file.c  2003-10-05 00:33:24.000000000 -0700
+@@ -47,7 +47,7 @@ static int ext3_release_file (struct ino
+  * the caller didn't specify O_LARGEFILE.  On 64bit systems we force
+  * on this flag in sys_open.
+  */
+-static int ext3_open_file (struct inode * inode, struct file * filp)
++static int ext3_open_file (struct inode *inode, struct file *filp)
+ {
+       if (!(filp->f_flags & O_LARGEFILE) &&
+           inode->i_size > 0x7FFFFFFFLL)
+@@ -56,7 +56,7 @@ static int ext3_open_file (struct inode 
+ }
+ static ssize_t
+-ext3_file_write(struct kiocb *iocb, const char *buf, size_t count, loff_t pos)
++ext3_file_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos)
+ {
+       struct file *file = iocb->ki_filp;
+       struct inode *inode = file->f_dentry->d_inode;
+@@ -117,8 +117,8 @@ struct file_operations ext3_file_operati
+       .llseek         = generic_file_llseek,
+       .read           = do_sync_read,
+       .write          = do_sync_write,
+-      .aio_read               = generic_file_aio_read,
+-      .aio_write              = ext3_file_write,
++      .aio_read       = generic_file_aio_read,
++      .aio_write      = ext3_file_write,
+       .readv          = generic_file_readv,
+       .writev         = generic_file_writev,
+       .ioctl          = ext3_ioctl,
+--- linux-2.6.0-test6/fs/ext3/inode.c  2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/ext3/inode.c 2003-10-05 00:36:12.000000000 -0700
+@@ -812,15 +812,17 @@ out:
+       if (err == -EAGAIN)
+               goto changed;
+-      if (ext3_find_goal(inode, iblock, chain, partial, &goal) < 0)
++      down(&ei->truncate_sem);
++      if (ext3_find_goal(inode, iblock, chain, partial, &goal) < 0) {
++              up(&ei->truncate_sem);
+               goto changed;
++      }
+       left = (chain + depth) - partial;
+       /*
+        * Block out ext3_truncate while we alter the tree
+        */
+-      down_read(&ei->truncate_sem);
+       err = ext3_alloc_branch(handle, inode, left, goal,
+                                       offsets+(partial-chain), partial);
+@@ -832,7 +834,7 @@ out:
+       if (!err)
+               err = ext3_splice_branch(handle, inode, iblock, chain,
+                                        partial, left);
+-      up_read(&ei->truncate_sem);
++      up(&ei->truncate_sem);
+       if (err == -EAGAIN)
+               goto changed;
+       if (err)
+@@ -1537,7 +1539,7 @@ static int ext3_direct_IO(int rw, struct
+                       unsigned long nr_segs)
+ {
+       struct file *file = iocb->ki_filp;
+-      struct inode *inode = file->f_dentry->d_inode->i_mapping->host;
++      struct inode *inode = file->f_mapping->host;
+       struct ext3_inode_info *ei = EXT3_I(inode);
+       handle_t *handle = NULL;
+       int ret;
+@@ -2205,7 +2207,7 @@ void ext3_truncate(struct inode * inode)
+        * From here we block out all ext3_get_block() callers who want to
+        * modify the block allocation tree.
+        */
+-      down_write(&ei->truncate_sem);
++      down(&ei->truncate_sem);
+       if (n == 1) {           /* direct blocks */
+               ext3_free_data(handle, inode, NULL, i_data+offsets[0],
+@@ -2269,7 +2271,7 @@ do_indirects:
+               case EXT3_TIND_BLOCK:
+                       ;
+       }
+-      up_write(&ei->truncate_sem);
++      up(&ei->truncate_sem);
+       inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+       ext3_mark_inode_dirty(handle, inode);
+@@ -2679,6 +2681,7 @@ static int ext3_do_update_inode(handle_t
+                       raw_inode->i_block[0] = 0;
+                       raw_inode->i_block[1] =
+                               cpu_to_le32(new_encode_dev(inode->i_rdev));
++                      raw_inode->i_block[2] = 0;
+               }
+       } else for (block = 0; block < EXT3_N_BLOCKS; block++)
+               raw_inode->i_block[block] = ei->i_data[block];
+--- linux-2.6.0-test6/fs/ext3/super.c  2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/ext3/super.c 2003-10-05 00:36:12.000000000 -0700
+@@ -27,6 +27,7 @@
+ #include <linux/slab.h>
+ #include <linux/init.h>
+ #include <linux/blkdev.h>
++#include <linux/parser.h>
+ #include <linux/smp_lock.h>
+ #include <linux/buffer_head.h>
+ #include <linux/vfs.h>
+@@ -459,7 +460,7 @@ static void init_once(void * foo, kmem_c
+ #ifdef CONFIG_EXT3_FS_XATTR
+               init_rwsem(&ei->xattr_sem);
+ #endif
+-              init_rwsem(&ei->truncate_sem);
++              init_MUTEX(&ei->truncate_sem);
+               inode_init_once(&ei->vfs_inode);
+       }
+ }
+@@ -526,36 +527,54 @@ static struct export_operations ext3_exp
+       .get_parent = ext3_get_parent,
+ };
++enum {
++      Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid,
++      Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro,
++      Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov,
++      Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, Opt_noload,
++      Opt_commit, Opt_journal_update, Opt_journal_inum,
++      Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
++      Opt_ignore, Opt_err,
++};
+-static int want_value(char *value, char *option)
+-{
+-      if (!value || !*value) {
+-              printk(KERN_NOTICE "EXT3-fs: the %s option needs an argument\n",
+-                     option);
+-              return -1;
+-      }
+-      return 0;
+-}
+-
+-static int want_null_value(char *value, char *option)
+-{
+-      if (*value) {
+-              printk(KERN_NOTICE "EXT3-fs: Invalid %s argument: %s\n",
+-                     option, value);
+-              return -1;
+-      }
+-      return 0;
+-}
+-
+-static int want_numeric(char *value, char *option, unsigned long *number)
+-{
+-      if (want_value(value, option))
+-              return -1;
+-      *number = simple_strtoul(value, &value, 0);
+-      if (want_null_value(value, option))
+-              return -1;
+-      return 0;
+-}
++static match_table_t tokens = {
++      {Opt_bsd_df, "bsddf"},
++      {Opt_minix_df, "minixdf"},
++      {Opt_grpid, "grpid"},
++      {Opt_grpid, "bsdgroups"},
++      {Opt_nogrpid, "nogrpid"},
++      {Opt_nogrpid, "sysvgroups"},
++      {Opt_resgid, "resgid=%d"},
++      {Opt_resuid, "resuid=%d"},
++      {Opt_sb, "sb=%d"},
++      {Opt_err_cont, "errors=continue"},
++      {Opt_err_panic, "errors=panic"},
++      {Opt_err_ro, "errors=remount-ro"},
++      {Opt_nouid32, "nouid32"},
++      {Opt_nocheck, "nocheck"},
++      {Opt_nocheck, "check=none"},
++      {Opt_check, "check"},
++      {Opt_debug, "debug"},
++      {Opt_oldalloc, "oldalloc"},
++      {Opt_orlov, "orlov"},
++      {Opt_user_xattr, "user_xattr"},
++      {Opt_nouser_xattr, "nouser_xattr"},
++      {Opt_acl, "acl"},
++      {Opt_noacl, "noacl"},
++      {Opt_noload, "noload"},
++      {Opt_commit, "commit=%u"},
++      {Opt_journal_update, "journal=update"},
++      {Opt_journal_inum, "journal=%u"},
++      {Opt_abort, "abort"},
++      {Opt_data_journal, "data=journal"},
++      {Opt_data_ordered, "data=ordered"},
++      {Opt_data_writeback, "data=writeback"},
++      {Opt_ignore, "grpquota"},
++      {Opt_ignore, "noquota"},
++      {Opt_ignore, "quota"},
++      {Opt_ignore, "usrquota"},
++      {Opt_err, NULL}
++};
+ static unsigned long get_sb_block(void **data)
+ {
+@@ -577,175 +596,180 @@ static unsigned long get_sb_block(void *
+       return sb_block;
+ }
+-/*
+- * This function has been shamelessly adapted from the msdos fs
+- */
+ static int parse_options (char * options, struct ext3_sb_info *sbi,
+                         unsigned long * inum, int is_remount)
+ {
+-      char * this_char;
+-      char * value;
++      char * p;
++      substring_t args[MAX_OPT_ARGS];
++      int data_opt = 0;
++      int option;
+       if (!options)
+               return 1;
+-      while ((this_char = strsep (&options, ",")) != NULL) {
+-              if (!*this_char)
++
++      while ((p = strsep (&options, ",")) != NULL) {
++              int token;
++              if (!*p)
+                       continue;
+-              if ((value = strchr (this_char, '=')) != NULL)
+-                      *value++ = 0;
+-#ifdef CONFIG_EXT3_FS_XATTR
+-              if (!strcmp (this_char, "user_xattr"))
+-                      set_opt (sbi->s_mount_opt, XATTR_USER);
+-              else if (!strcmp (this_char, "nouser_xattr"))
+-                      clear_opt (sbi->s_mount_opt, XATTR_USER);
+-              else
+-#endif
+-#ifdef CONFIG_EXT3_FS_POSIX_ACL
+-              if (!strcmp(this_char, "acl"))
+-                      set_opt (sbi->s_mount_opt, POSIX_ACL);
+-              else if (!strcmp(this_char, "noacl"))
+-                      clear_opt (sbi->s_mount_opt, POSIX_ACL);
+-              else
+-#endif
+-              if (!strcmp (this_char, "bsddf"))
++
++              token = match_token(p, tokens, args);
++              switch (token) {
++              case Opt_bsd_df:
+                       clear_opt (sbi->s_mount_opt, MINIX_DF);
+-              else if (!strcmp (this_char, "nouid32")) {
++                      break;
++              case Opt_minix_df:
++                      set_opt (sbi->s_mount_opt, MINIX_DF);
++                      break;
++              case Opt_grpid:
++                      set_opt (sbi->s_mount_opt, GRPID);
++                      break;
++              case Opt_nogrpid:
++                      clear_opt (sbi->s_mount_opt, GRPID);
++                      break;
++              case Opt_resuid:
++                      if (match_int(&args[0], &option))
++                              return 0;
++                      sbi->s_resuid = option;
++                      break;
++              case Opt_resgid:
++                      if (match_int(&args[0], &option))
++                              return 0;
++                      sbi->s_resgid = option;
++                      break;
++              case Opt_sb:
++                      /* handled by get_sb_block() instead of here */
++                      /* *sb_block = match_int(&args[0]); */
++                      break;
++              case Opt_err_panic:
++                      clear_opt (sbi->s_mount_opt, ERRORS_CONT);
++                      clear_opt (sbi->s_mount_opt, ERRORS_RO);
++                      set_opt (sbi->s_mount_opt, ERRORS_PANIC);
++                      break;
++              case Opt_err_ro:
++                      clear_opt (sbi->s_mount_opt, ERRORS_CONT);
++                      clear_opt (sbi->s_mount_opt, ERRORS_PANIC);
++                      set_opt (sbi->s_mount_opt, ERRORS_RO);
++                      break;
++              case Opt_err_cont:
++                      clear_opt (sbi->s_mount_opt, ERRORS_RO);
++                      clear_opt (sbi->s_mount_opt, ERRORS_PANIC);
++                      set_opt (sbi->s_mount_opt, ERRORS_CONT);
++                      break;
++              case Opt_nouid32:
+                       set_opt (sbi->s_mount_opt, NO_UID32);
+-              }
+-              else if (!strcmp (this_char, "abort"))
+-                      set_opt (sbi->s_mount_opt, ABORT);
+-              else if (!strcmp (this_char, "check")) {
+-                      if (!value || !*value || !strcmp (value, "none"))
+-                              clear_opt (sbi->s_mount_opt, CHECK);
+-                      else
++                      break;
++              case Opt_check:
+ #ifdef CONFIG_EXT3_CHECK
+-                              set_opt (sbi->s_mount_opt, CHECK);
++                      set_opt (sbi->s_mount_opt, CHECK);
+ #else
+-                              printk(KERN_ERR 
+-                                     "EXT3 Check option not supported\n");
++                      printk(KERN_ERR
++                             "EXT3 Check option not supported\n");
+ #endif
+-              }
+-              else if (!strcmp (this_char, "debug"))
+-                      set_opt (sbi->s_mount_opt, DEBUG);
+-              else if (!strcmp (this_char, "errors")) {
+-                      if (want_value(value, "errors"))
+-                              return 0;
+-                      if (!strcmp (value, "continue")) {
+-                              clear_opt (sbi->s_mount_opt, ERRORS_RO);
+-                              clear_opt (sbi->s_mount_opt, ERRORS_PANIC);
+-                              set_opt (sbi->s_mount_opt, ERRORS_CONT);
+-                      }
+-                      else if (!strcmp (value, "remount-ro")) {
+-                              clear_opt (sbi->s_mount_opt, ERRORS_CONT);
+-                              clear_opt (sbi->s_mount_opt, ERRORS_PANIC);
+-                              set_opt (sbi->s_mount_opt, ERRORS_RO);
+-                      }
+-                      else if (!strcmp (value, "panic")) {
+-                              clear_opt (sbi->s_mount_opt, ERRORS_CONT);
+-                              clear_opt (sbi->s_mount_opt, ERRORS_RO);
+-                              set_opt (sbi->s_mount_opt, ERRORS_PANIC);
+-                      }
+-                      else {
+-                              printk (KERN_ERR
+-                                      "EXT3-fs: Invalid errors option: %s\n",
+-                                      value);
+-                              return 0;
+-                      }
+-              }
+-              else if (!strcmp (this_char, "grpid") ||
+-                       !strcmp (this_char, "bsdgroups"))
+-                      set_opt (sbi->s_mount_opt, GRPID);
+-              else if (!strcmp (this_char, "minixdf"))
+-                      set_opt (sbi->s_mount_opt, MINIX_DF);
+-              else if (!strcmp (this_char, "nocheck"))
++                      break;
++              case Opt_nocheck:
+                       clear_opt (sbi->s_mount_opt, CHECK);
+-              else if (!strcmp (this_char, "nogrpid") ||
+-                       !strcmp (this_char, "sysvgroups"))
+-                      clear_opt (sbi->s_mount_opt, GRPID);
+-              else if (!strcmp (this_char, "resgid")) {
+-                      unsigned long v;
+-                      if (want_numeric(value, "resgid", &v))
+-                              return 0;
+-                      sbi->s_resgid = v;
+-              }
+-              else if (!strcmp (this_char, "resuid")) {
+-                      unsigned long v;
+-                      if (want_numeric(value, "resuid", &v))
+-                              return 0;
+-                      sbi->s_resuid = v;
+-              }
+-              else if (!strcmp (this_char, "oldalloc"))
++                      break;
++              case Opt_debug:
++                      set_opt (sbi->s_mount_opt, DEBUG);
++                      break;
++              case Opt_oldalloc:
+                       set_opt (sbi->s_mount_opt, OLDALLOC);
+-              else if (!strcmp (this_char, "orlov"))
++                      break;
++              case Opt_orlov:
+                       clear_opt (sbi->s_mount_opt, OLDALLOC);
+-              /* Silently ignore the quota options */
+-              else if (!strcmp (this_char, "grpquota")
+-                       || !strcmp (this_char, "noquota")
+-                       || !strcmp (this_char, "quota")
+-                       || !strcmp (this_char, "usrquota"))
+-                      /* Don't do anything ;-) */ ;
+-              else if (!strcmp (this_char, "journal")) {
++                      break;
++#ifdef CONFIG_EXT3_FS_XATTR
++              case Opt_user_xattr:
++                      set_opt (sbi->s_mount_opt, XATTR_USER);
++                      break;
++              case Opt_nouser_xattr:
++                      clear_opt (sbi->s_mount_opt, XATTR_USER);
++                      break;
++#else
++              case Opt_user_xattr:
++              case Opt_nouser_xattr:
++                      printk("EXT3 (no)user_xattr options not supported\n");
++                      break;
++#endif
++#ifdef CONFIG_EXT3_FS_POSIX_ACL
++              case Opt_acl:
++                      set_opt(sbi->s_mount_opt, POSIX_ACL);
++                      break;
++              case Opt_noacl:
++                      clear_opt(sbi->s_mount_opt, POSIX_ACL);
++                      break;
++#else
++              case Opt_acl:
++              case Opt_noacl:
++                      printk("EXT3 (no)acl options not supported\n");
++                      break;
++#endif
++              case Opt_journal_update:
+                       /* @@@ FIXME */
+                       /* Eventually we will want to be able to create
+-                           a journal file here.  For now, only allow the
+-                           user to specify an existing inode to be the
+-                           journal file. */
++                         a journal file here.  For now, only allow the
++                         user to specify an existing inode to be the
++                         journal file. */
+                       if (is_remount) {
+                               printk(KERN_ERR "EXT3-fs: cannot specify "
+                                      "journal on remount\n");
+                               return 0;
+                       }
+-
+-                      if (want_value(value, "journal"))
++                      set_opt (sbi->s_mount_opt, UPDATE_JOURNAL);
++                      break;
++              case Opt_journal_inum:
++                      if (is_remount) {
++                              printk(KERN_ERR "EXT3-fs: cannot specify "
++                                     "journal on remount\n");
+                               return 0;
+-                      if (!strcmp (value, "update"))
+-                              set_opt (sbi->s_mount_opt, UPDATE_JOURNAL);
+-                      else if (want_numeric(value, "journal", inum))
++                      }
++                      if (match_int(&args[0], &option))
+                               return 0;
+-              }
+-              else if (!strcmp (this_char, "noload"))
++                      *inum = option;
++                      break;
++              case Opt_noload:
+                       set_opt (sbi->s_mount_opt, NOLOAD);
+-              else if (!strcmp (this_char, "data")) {
+-                      int data_opt = 0;
+-
+-                      if (want_value(value, "data"))
+-                              return 0;
+-                      if (!strcmp (value, "journal"))
+-                              data_opt = EXT3_MOUNT_JOURNAL_DATA;
+-                      else if (!strcmp (value, "ordered"))
+-                              data_opt = EXT3_MOUNT_ORDERED_DATA;
+-                      else if (!strcmp (value, "writeback"))
+-                              data_opt = EXT3_MOUNT_WRITEBACK_DATA;
+-                      else {
+-                              printk (KERN_ERR 
+-                                      "EXT3-fs: Invalid data option: %s\n",
+-                                      value);
++                      break;
++              case Opt_commit:
++                      if (match_int(&args[0], &option))
+                               return 0;
+-                      }
++                      sbi->s_commit_interval = HZ * option;
++                      break;
++              case Opt_data_journal:
++                      data_opt = EXT3_MOUNT_JOURNAL_DATA;
++                      goto datacheck;
++              case Opt_data_ordered:
++                      data_opt = EXT3_MOUNT_ORDERED_DATA;
++                      goto datacheck;
++              case Opt_data_writeback:
++                      data_opt = EXT3_MOUNT_WRITEBACK_DATA;
++              datacheck:
+                       if (is_remount) {
+-                              if ((sbi->s_mount_opt & EXT3_MOUNT_DATA_FLAGS) !=
+-                                                      data_opt) {
++                              if ((sbi->s_mount_opt & EXT3_MOUNT_DATA_FLAGS)
++                                              != data_opt) {
+                                       printk(KERN_ERR
+-                                             "EXT3-fs: cannot change data "
+-                                             "mode on remount\n");
++                                              "EXT3-fs: cannot change data "
++                                              "mode on remount\n");
+                                       return 0;
+                               }
+                       } else {
+                               sbi->s_mount_opt &= ~EXT3_MOUNT_DATA_FLAGS;
+                               sbi->s_mount_opt |= data_opt;
+                       }
+-              } else if (!strcmp (this_char, "commit")) {
+-                      unsigned long v;
+-                      if (want_numeric(value, "commit", &v))
+-                              return 0;
+-                      sbi->s_commit_interval = (HZ * v);
+-              } else {
+-                      printk (KERN_ERR 
+-                              "EXT3-fs: Unrecognized mount option %s\n",
+-                              this_char);
++                      break;
++              case Opt_abort:
++                      set_opt(sbi->s_mount_opt, ABORT);
++                      break;
++              case Opt_ignore:
++                      break;
++              default:
++                      printk (KERN_ERR
++                              "EXT3-fs: Unrecognized mount option \"%s\" "
++                              "or missing value\n", p);
+                       return 0;
+               }
+       }
++
+       return 1;
+ }
+--- linux-2.6.0-test6/fs/ext3/symlink.c        2003-06-14 12:18:22.000000000 -0700
++++ 25/fs/ext3/symlink.c       2003-10-05 00:33:24.000000000 -0700
+@@ -22,7 +22,8 @@
+ #include <linux/ext3_fs.h>
+ #include "xattr.h"
+-static int ext3_readlink(struct dentry *dentry, char *buffer, int buflen)
++static int
++ext3_readlink(struct dentry *dentry, char __user *buffer, int buflen)
+ {
+       struct ext3_inode_info *ei = EXT3_I(dentry->d_inode);
+       return vfs_readlink(dentry, buffer, buflen, (char*)ei->i_data);
+--- linux-2.6.0-test6/fs/fat/dir.c     2003-08-08 22:55:13.000000000 -0700
++++ 25/fs/fat/dir.c    2003-10-05 00:33:24.000000000 -0700
+@@ -663,7 +663,7 @@ int fat_dir_ioctl(struct inode * inode, 
+               return -EINVAL;
+       }
+-      d1 = (struct dirent *)arg;
++      d1 = (struct dirent __user *)arg;
+       if (!access_ok(VERIFY_WRITE, d1, sizeof(struct dirent[2])))
+               return -EFAULT;
+       /*
+--- linux-2.6.0-test6/fs/fat/inode.c   2003-08-08 22:55:13.000000000 -0700
++++ 25/fs/fat/inode.c  2003-10-05 00:33:24.000000000 -0700
+@@ -20,6 +20,7 @@
+ #include <linux/buffer_head.h>
+ #include <linux/mount.h>
+ #include <linux/vfs.h>
++#include <linux/parser.h>
+ #include <asm/unaligned.h>
+ /*
+@@ -183,20 +184,6 @@ void fat_put_super(struct super_block *s
+       kfree(sbi);
+ }
+-static int simple_getbool(char *s, int *setval)
+-{
+-      if (s) {
+-              if (!strcmp(s,"1") || !strcmp(s,"yes") || !strcmp(s,"true"))
+-                      *setval = 1;
+-              else if (!strcmp(s,"0") || !strcmp(s,"no") || !strcmp(s,"false"))
+-                      *setval = 0;
+-              else
+-                      return 0;
+-      } else
+-              *setval = 1;
+-      return 1;
+-}
+-
+ static int fat_show_options(struct seq_file *m, struct vfsmount *mnt)
+ {
+       struct msdos_sb_info *sbi = MSDOS_SB(mnt->mnt_sb);
+@@ -259,11 +246,95 @@ static int fat_show_options(struct seq_f
+       return 0;
+ }
++static void print_obsolete_option(char *optname)
++{
++      printk(KERN_INFO "FAT: %s option is obsolete, "
++                      "not supported now\n", optname);
++}
++
++enum {
++      Opt_blocksize, Opt_charset, Opt_check_n, Opt_check_r, Opt_check_s,
++      Opt_fat, Opt_codepage, Opt_conv_a, Opt_conv_b, Opt_conv_t,
++      Opt_debug, Opt_dots, Opt_err, Opt_gid, Opt_immutable,
++      Opt_nocase, Opt_nodots, Opt_quiet, Opt_showexec, Opt_uid,
++      Opt_shortname_lower, Opt_shortname_win95, Opt_shortname_winnt, Opt_shortname_mixed,
++      Opt_umask, Opt_dmask, Opt_fmask, Opt_posix, Opt_cvf_format, Opt_cvf_options,
++      Opt_utf8_off, Opt_utf8_no, Opt_utf8_false,
++      Opt_utf8_on, Opt_utf8_yes, Opt_utf8_true, Opt_utf8_opt,
++      Opt_uni_xl_off, Opt_uni_xl_no, Opt_uni_xl_false,
++      Opt_uni_xl_on, Opt_uni_xl_yes, Opt_uni_xl_true, Opt_uni_xl_opt,
++      Opt_nonumtail_off, Opt_nonumtail_no, Opt_nonumtail_false,
++      Opt_nonumtail_on, Opt_nonumtail_yes, Opt_nonumtail_true, Opt_nonumtail_opt,
++};
++
++static match_table_t FAT_tokens = {
++      {Opt_check_r, "check=relaxed"},
++      {Opt_check_s, "check=strict"},
++      {Opt_check_n, "check=normal"},
++      {Opt_check_r, "check=r"},
++      {Opt_check_s, "check=s"},
++      {Opt_check_n, "check=n"},
++      {Opt_conv_b, "conv=binary"},
++      {Opt_conv_t, "conv=text"},
++      {Opt_conv_a, "conv=auto"},
++      {Opt_conv_b, "conv=b"},
++      {Opt_conv_t, "conv=t"},
++      {Opt_conv_a, "conv=a"},
++      {Opt_nodots, "nodots"},
++      {Opt_nodots, "dotsOK=no"},
++      {Opt_dots, "dotsOK=yes"},
++      {Opt_dots, "dots"},
++      {Opt_uid, "uid=%d"},
++      {Opt_gid, "gid=%d"},
++      {Opt_umask, "umask=%o"},
++      {Opt_dmask, "dmask=%o"},
++      {Opt_fmask, "fmask=%o"},
++      {Opt_fat, "fat=%d"},
++      {Opt_codepage, "codepage=%d"},
++      {Opt_charset, "iocharset=%s"},
++      {Opt_blocksize, "blocksize=%d"},
++      {Opt_nocase, "nocase"},
++      {Opt_cvf_format, "cvf_format=%20s"},
++      {Opt_cvf_options, "cvf_options=%100s"},
++      {Opt_shortname_lower, "shortname=lower"},
++      {Opt_shortname_win95, "shortname=win95"},
++      {Opt_shortname_winnt, "shortname=winnt"},
++      {Opt_shortname_mixed, "shortname=mixed"},
++      {Opt_utf8_off, "utf8=0"},       /* 0 or no or false */
++      {Opt_utf8_no, "utf8=no"},
++      {Opt_utf8_false, "utf8=false"},
++      {Opt_utf8_on, "utf8=1"},        /* empty or 1 or yes or true */
++      {Opt_utf8_yes, "utf8=yes"},
++      {Opt_utf8_true, "utf8=true"},
++      {Opt_utf8_opt, "utf8"},
++      {Opt_uni_xl_off, "uni_xlate=0"},        /* 0 or no or false */
++      {Opt_uni_xl_no, "uni_xlate=no"},
++      {Opt_uni_xl_false, "uni_xlate=false"},
++      {Opt_uni_xl_on, "uni_xlate=1"},         /* empty or 1 or yes or true */
++      {Opt_uni_xl_yes, "uni_xlate=yes"},
++      {Opt_uni_xl_true, "uni_xlate=true"},
++      {Opt_uni_xl_opt, "uni_xlate"},
++      {Opt_nonumtail_off, "nonumtail=0"},     /* 0 or no or false */
++      {Opt_nonumtail_no, "nonumtail=no"},
++      {Opt_nonumtail_false, "nonumtail=false"},
++      {Opt_nonumtail_on, "nonumtail=1"},      /* empty or 1 or yes or true */
++      {Opt_nonumtail_yes, "nonumtail=yes"},
++      {Opt_nonumtail_true, "nonumtail=true"},
++      {Opt_nonumtail_opt, "nonumtail"},
++      {Opt_quiet, "quiet"},
++      {Opt_showexec, "showexec"},
++      {Opt_debug, "debug"},
++      {Opt_immutable, "sys_immutable"},
++      {Opt_posix, "posix"},
++      {Opt_err, NULL}
++};
++
+ static int parse_options(char *options, int is_vfat, int *debug,
+                        struct fat_mount_options *opts)
+ {
+-      char *this_char, *value, *p;
+-      int ret = 1, val, len;
++      char *p;
++      substring_t args[MAX_OPT_ARGS];
++      int option;
+       opts->isvfat = is_vfat;
+@@ -284,183 +355,198 @@ static int parse_options(char *options, 
+       *debug = 0;
+       if (!options)
+-              goto out;
+-      while ((this_char = strsep(&options,",")) != NULL) {
+-              if (!*this_char)
++              return 1;
++
++      while ((p = strsep(&options, ",")) != NULL) {
++              int token;
++              if (!*p)
+                       continue;
+-              if ((value = strchr(this_char,'=')) != NULL)
+-                      *value++ = 0;
+-              if (!strcmp(this_char,"check") && value) {
+-                      if (value[0] && !value[1] && strchr("rns",*value))
+-                              opts->name_check = *value;
+-                      else if (!strcmp(value,"relaxed"))
+-                              opts->name_check = 'r';
+-                      else if (!strcmp(value,"normal"))
+-                              opts->name_check = 'n';
+-                      else if (!strcmp(value,"strict"))
+-                              opts->name_check = 's';
+-                      else ret = 0;
+-              }
+-              else if (!strcmp(this_char,"conv") && value) {
+-                      printk(KERN_INFO "FAT: conv option is obsolete, "
+-                             "not supported now\n");
+-              }
+-              else if (!strcmp(this_char,"nocase")) {
++              token = match_token(p, FAT_tokens, args);
++              switch (token) {
++              case Opt_check_s:
++                      opts->name_check = 's';
++                      break;
++              case Opt_check_r:
++                              opts->name_check = 'r';
++                      break;
++              case Opt_check_n:
++                              opts->name_check = 'n';
++                      break;
++              case Opt_dots:          /* msdos specific */
++                      if (!is_vfat)
++                              opts->dotsOK = 1;
++                      break;
++              case Opt_nodots:        /* msdos specific */
++                      if (!is_vfat)
++                              opts->dotsOK = 0;
++                      break;
++              case Opt_nocase:
+                       if (!is_vfat)
+                               opts->nocase = 1;
+                       else {
+-                              /* for backward compatible */
++                              /* for backward compatibility */
+                               opts->shortname = VFAT_SFN_DISPLAY_WIN95
+                                       | VFAT_SFN_CREATE_WIN95;
+                       }
+-              }
+-              else if (!strcmp(this_char,"showexec")) {
++                      break;
++              case Opt_quiet:
++                      opts->quiet = 1;
++                      break;
++              case Opt_showexec:
+                       opts->showexec = 1;
+-              }
+-              else if (!strcmp(this_char,"uid")) {
+-                      if (!value || !*value) ret = 0;
+-                      else {
+-                              opts->fs_uid = simple_strtoul(value,&value,0);
+-                              if (*value) ret = 0;
+-                      }
+-              }
+-              else if (!strcmp(this_char,"gid")) {
+-                      if (!value || !*value) ret= 0;
+-                      else {
+-                              opts->fs_gid = simple_strtoul(value,&value,0);
+-                              if (*value) ret = 0;
+-                      }
+-              }
+-              else if (!strcmp(this_char,"umask")) {
+-                      if (!value || !*value) ret = 0;
+-                      else {
+-                              opts->fs_fmask = opts->fs_dmask =
+-                                      simple_strtoul(value,&value,8);
+-                              if (*value) ret = 0;
+-                      }
+-              }
+-              else if (!strcmp(this_char,"fmask")) {
+-                      if (!value || !*value) ret = 0;
+-                      else {
+-                              opts->fs_fmask = simple_strtoul(value,&value,8);
+-                              if (*value) ret = 0;
+-                      }
+-              }
+-              else if (!strcmp(this_char,"dmask")) {
+-                      if (!value || !*value) ret = 0;
+-                      else {
+-                              opts->fs_dmask = simple_strtoul(value,&value,8);
+-                              if (*value) ret = 0;
+-                      }
+-              }
+-              else if (!strcmp(this_char,"debug")) {
+-                      if (value) ret = 0;
+-                      else *debug = 1;
+-              }
+-              else if (!strcmp(this_char,"fat")) {
+-                      printk(KERN_INFO "FAT: fat option is obsolete, "
+-                             "not supported now\n");
+-              }
+-              else if (!strcmp(this_char,"quiet")) {
+-                      if (value) ret = 0;
+-                      else opts->quiet = 1;
+-              }
+-              else if (!strcmp(this_char,"blocksize")) {
+-                      printk(KERN_INFO "FAT: blocksize option is obsolete, "
+-                             "not supported now\n");
+-              }
+-              else if (!strcmp(this_char,"sys_immutable")) {
+-                      if (value) ret = 0;
+-                      else opts->sys_immutable = 1;
+-              }
+-              else if (!strcmp(this_char,"codepage") && value) {
+-                      opts->codepage = simple_strtoul(value,&value,0);
+-                      if (*value) ret = 0;
+-              }
+-
+-              /* msdos specific */
+-              else if (!is_vfat && !strcmp(this_char,"dots")) {
+-                      opts->dotsOK = 1;
+-              }
+-              else if (!is_vfat && !strcmp(this_char,"nodots")) {
+-                      opts->dotsOK = 0;
+-              }
+-              else if (!is_vfat && !strcmp(this_char,"dotsOK") && value) {
+-                      if (!strcmp(value,"yes")) opts->dotsOK = 1;
+-                      else if (!strcmp(value,"no")) opts->dotsOK = 0;
+-                      else ret = 0;
+-              }
++                      break;
++              case Opt_debug:
++                      *debug = 1;
++                      break;
++              case Opt_immutable:
++                      opts->sys_immutable = 1;
++                      break;
++              case Opt_uid:
++                      if (match_int(&args[0], &option))
++                              return 0;
++                      opts->fs_uid = option;
++                      break;
++              case Opt_gid:
++                      if (match_int(&args[0], &option))
++                              return 0;
++                      opts->fs_gid = option;
++                      break;
++              case Opt_umask:
++                      if (match_octal(&args[0], &option))
++                              return 0;
++                      opts->fs_fmask = opts->fs_dmask = option;
++                      break;
++              case Opt_dmask:
++                      if (match_octal(&args[0], &option))
++                              return 0;
++                      opts->fs_dmask = option;
++                      break;
++              case Opt_fmask:
++                      if (match_octal(&args[0], &option))
++                              return 0;
++                      opts->fs_fmask = option;
++                      break;
++              case Opt_codepage:
++                      if (match_int(&args[0], &option))
++                              return 0;
++                      opts->codepage = option;
++                      printk("MSDOS FS: Using codepage %d\n",
++                                      opts->codepage);
++                      break;
+               /* vfat specific */
+-              else if (is_vfat && !strcmp(this_char,"iocharset") && value) {
+-                      p = value;
+-                      while (*value && *value != ',')
+-                              value++;
+-                      len = value - p;
+-                      if (len) {
+-                              char *buffer;
+-
+-                              if (opts->iocharset != NULL) {
+-                                      kfree(opts->iocharset);
+-                                      opts->iocharset = NULL;
+-                              }
+-                              buffer = kmalloc(len + 1, GFP_KERNEL);
+-                              if (buffer != NULL) {
+-                                      opts->iocharset = buffer;
+-                                      memcpy(buffer, p, len);
+-                                      buffer[len] = 0;
+-                              } else
+-                                      ret = 0;
++              case Opt_charset:
++                      if (is_vfat) {
++                              kfree(opts->iocharset);
++                              opts->iocharset = match_strdup(&args[0]);
++                              if (!opts->iocharset)
++                                      return 0;
++                              printk("MSDOS FS: IO charset %s\n",
++                                      opts->iocharset);
+                       }
+-              }
+-              else if (is_vfat && !strcmp(this_char,"utf8")) {
+-                      ret = simple_getbool(value, &val);
+-                      if (ret) opts->utf8 = val;
+-              }
+-              else if (is_vfat && !strcmp(this_char,"uni_xlate")) {
+-                      ret = simple_getbool(value, &val);
+-                      if (ret) opts->unicode_xlate = val;
+-              }
+-              else if (is_vfat && !strcmp(this_char,"posix")) {
+-                      printk(KERN_INFO "FAT: posix option is obsolete, "
+-                             "not supported now\n");
+-              }
+-              else if (is_vfat && !strcmp(this_char,"nonumtail")) {
+-                      ret = simple_getbool(value, &val);
+-                      if (ret) {
+-                              opts->numtail = !val;
+-                      }
+-              }
+-              else if (is_vfat && !strcmp(this_char, "shortname")) {
+-                      if (!strcmp(value, "lower"))
++                      break;
++              case Opt_shortname_lower:
++                      if (is_vfat) {
+                               opts->shortname = VFAT_SFN_DISPLAY_LOWER
+                                               | VFAT_SFN_CREATE_WIN95;
+-                      else if (!strcmp(value, "win95"))
++                      }
++                      break;
++              case Opt_shortname_win95:
++                      if (is_vfat) {
+                               opts->shortname = VFAT_SFN_DISPLAY_WIN95
+                                               | VFAT_SFN_CREATE_WIN95;
+-                      else if (!strcmp(value, "winnt"))
++                      }
++                      break;
++              case Opt_shortname_winnt:
++                      if (is_vfat) {
+                               opts->shortname = VFAT_SFN_DISPLAY_WINNT
+                                               | VFAT_SFN_CREATE_WINNT;
+-                      else if (!strcmp(value, "mixed"))
++                      }
++                      break;
++              case Opt_shortname_mixed:
++                      if (is_vfat) {
+                               opts->shortname = VFAT_SFN_DISPLAY_WINNT
+                                               | VFAT_SFN_CREATE_WIN95;
+-                      else
+-                              ret = 0;
+-              } else {
+-                      printk(KERN_ERR "FAT: Unrecognized mount option %s\n",
+-                             this_char);
+-                      ret = 0;
+-              }
++                      }
++                      break;
++              case Opt_utf8_off:      /* 0 or no or false */
++              case Opt_utf8_no:
++              case Opt_utf8_false:
++                      if (is_vfat) {
++                              opts->utf8 = 0;
++                      }
++                      break;
++              case Opt_utf8_on:       /* empty or 1 or yes or true */
++              case Opt_utf8_opt:
++              case Opt_utf8_yes:
++              case Opt_utf8_true:
++                      if (is_vfat) {
++                              opts->utf8 = 1;
++                      }
++                      break;
++              case Opt_uni_xl_off:    /* 0 or no or false */
++              case Opt_uni_xl_no:
++              case Opt_uni_xl_false:
++                      if (is_vfat) {
++                              opts->unicode_xlate = 0;
++                      }
++                      break;
++              case Opt_uni_xl_on:     /* empty or 1 or yes or true */
++              case Opt_uni_xl_yes:
++              case Opt_uni_xl_true:
++              case Opt_uni_xl_opt:
++                      if (is_vfat) {
++                              opts->unicode_xlate = 1;
++                      }
++                      break;
++              case Opt_nonumtail_off:         /* 0 or no or false */
++              case Opt_nonumtail_no:
++              case Opt_nonumtail_false:
++                      if (is_vfat) {
++                                      opts->numtail = 1;      /* negated option */
++                      }
++                      break;
++              case Opt_nonumtail_on:          /* empty or 1 or yes or true */
++              case Opt_nonumtail_yes:
++              case Opt_nonumtail_true:
++              case Opt_nonumtail_opt:
++                      if (is_vfat) {
++                                      opts->numtail = 0;      /* negated option */
++                      }
++                      break;
+-              if (ret == 0)
++              /* obsolete mount options */
++              case Opt_conv_b:
++              case Opt_conv_t:
++              case Opt_conv_a:
++                      print_obsolete_option("conv");
++                      break;
++              case Opt_blocksize:
++                      print_obsolete_option("blocksize");
++                      break;
++              case Opt_posix:
++                      print_obsolete_option("posix");
++                      break;
++              case Opt_fat:
++                      print_obsolete_option("fat");
++                      break;
++              case Opt_cvf_format:
++              case Opt_cvf_options:
++                      print_obsolete_option("cvf");
+                       break;
++              /* unknown option */
++              default:
++                      printk(KERN_ERR "FAT: Unrecognized mount option \"%s\" "
++                                      "or missing value\n", p);
++                      return 0;
++              }
+       }
+-out:
++
+       if (opts->unicode_xlate)
+               opts->utf8 = 0;
+       
+-      return ret;
++      return 1;
+ }
+ static int fat_calc_dir_size(struct inode *inode)
+--- linux-2.6.0-test6/fs/fcntl.c       2003-09-08 13:58:58.000000000 -0700
++++ 25/fs/fcntl.c      2003-10-05 00:34:08.000000000 -0700
+@@ -229,8 +229,8 @@ static int setfl(int fd, struct file * f
+                  arg |= O_NONBLOCK;
+       if (arg & O_DIRECT) {
+-              if (!inode->i_mapping || !inode->i_mapping->a_ops ||
+-                      !inode->i_mapping->a_ops->direct_IO)
++              if (!filp->f_mapping || !filp->f_mapping->a_ops ||
++                      !filp->f_mapping->a_ops->direct_IO)
+                               return -EINVAL;
+       }
+@@ -619,3 +619,6 @@ module_init(fasync_init)
+ EXPORT_SYMBOL(f_setown);
+ EXPORT_SYMBOL(f_delown);
++#ifdef CONFIG_NET
++EXPORT_SYMBOL(__kill_fasync);
++#endif
+--- linux-2.6.0-test6/fs/file_table.c  2003-08-08 22:55:13.000000000 -0700
++++ 25/fs/file_table.c 2003-10-05 00:34:03.000000000 -0700
+@@ -114,6 +114,7 @@ int open_private_file(struct file *filp,
+       filp->f_mode   = (flags+1) & O_ACCMODE;
+       atomic_set(&filp->f_count, 1);
+       filp->f_dentry = dentry;
++      filp->f_mapping = dentry->d_inode->i_mapping;
+       filp->f_uid    = current->fsuid;
+       filp->f_gid    = current->fsgid;
+       filp->f_op     = dentry->d_inode->i_fop;
+@@ -285,3 +286,5 @@ void __init files_init(unsigned long mem
+               files_stat.max_files = NR_FILE;
+ } 
++/* Needed by unix.o */
++EXPORT_SYMBOL(files_stat);
+--- linux-2.6.0-test6/fs/freevxfs/vxfs_immed.c 2003-06-14 12:18:25.000000000 -0700
++++ 25/fs/freevxfs/vxfs_immed.c        2003-10-05 00:33:24.000000000 -0700
+@@ -39,7 +39,7 @@
+ #include "vxfs_inode.h"
+-static int    vxfs_immed_readlink(struct dentry *, char *, int);
++static int    vxfs_immed_readlink(struct dentry *, char __user *, int);
+ static int    vxfs_immed_follow_link(struct dentry *, struct nameidata *);
+ static int    vxfs_immed_readpage(struct file *, struct page *);
+@@ -77,7 +77,7 @@ struct address_space_operations vxfs_imm
+  *   Number of bytes successfully copied to userspace.
+  */
+ static int
+-vxfs_immed_readlink(struct dentry *dp, char *bp, int buflen)
++vxfs_immed_readlink(struct dentry *dp, char __user *bp, int buflen)
+ {
+       struct vxfs_inode_info          *vip = VXFS_INO(dp->d_inode);
+--- linux-2.6.0-test6/fs/fs-writeback.c        2003-07-10 18:50:31.000000000 -0700
++++ 25/fs/fs-writeback.c       2003-10-05 00:34:09.000000000 -0700
+@@ -510,7 +510,7 @@ void write_inode_now(struct inode *inode
+  *    OSYNC_INODE:    the inode itself
+  */
+-int generic_osync_inode(struct inode *inode, int what)
++int generic_osync_inode(struct inode *inode, struct address_space *mapping, int what)
+ {
+       int err = 0;
+       int need_write_inode_now = 0;
+@@ -518,14 +518,14 @@ int generic_osync_inode(struct inode *in
+       current->flags |= PF_SYNCWRITE;
+       if (what & OSYNC_DATA)
+-              err = filemap_fdatawrite(inode->i_mapping);
++              err = filemap_fdatawrite(mapping);
+       if (what & (OSYNC_METADATA|OSYNC_DATA)) {
+-              err2 = sync_mapping_buffers(inode->i_mapping);
++              err2 = sync_mapping_buffers(mapping);
+               if (!err)
+                       err = err2;
+       }
+       if (what & OSYNC_DATA) {
+-              err2 = filemap_fdatawait(inode->i_mapping);
++              err2 = filemap_fdatawait(mapping);
+               if (!err)
+                       err = err2;
+       }
+--- linux-2.6.0-test6/fs/hfs/file.c    2003-06-14 12:18:06.000000000 -0700
++++ 25/fs/hfs/file.c   2003-10-05 00:33:24.000000000 -0700
+@@ -25,10 +25,10 @@
+ /*================ Forward declarations ================*/
+-static hfs_rwret_t hfs_file_read(struct file *, char *, hfs_rwarg_t,
++static hfs_rwret_t hfs_file_read(struct file *, char __user *, hfs_rwarg_t,
+                                loff_t *);
+-static hfs_rwret_t hfs_file_write(struct file *, const char *, hfs_rwarg_t,
+-                                loff_t *);
++static hfs_rwret_t hfs_file_write(struct file *, const char __user *,
++                                hfs_rwarg_t, loff_t *);
+ static void hfs_file_truncate(struct inode *);
+ /*================ Global variables ================*/
+@@ -139,7 +139,7 @@ int hfs_get_block(struct inode *inode, s
+  * user-space at the address 'buf'.  Returns the number of bytes
+  * successfully transferred.  This function checks the arguments, does
+  * some setup and then calls hfs_do_read() to do the actual transfer.  */
+-static hfs_rwret_t hfs_file_read(struct file * filp, char * buf, 
++static hfs_rwret_t hfs_file_read(struct file *filp, char __user *buf, 
+                                hfs_rwarg_t count, loff_t *ppos)
+ {
+         struct inode *inode = filp->f_dentry->d_inode;
+@@ -181,7 +181,7 @@ static hfs_rwret_t hfs_file_read(struct 
+  * 'file->f_pos' from user-space at the address 'buf'.  The return
+  * value is the number of bytes actually transferred.
+  */
+-static hfs_rwret_t hfs_file_write(struct file * filp, const char * buf,
++static hfs_rwret_t hfs_file_write(struct file *filp, const char __user *buf,
+                                 hfs_rwarg_t count, loff_t *ppos)
+ {
+         struct inode    *inode = filp->f_dentry->d_inode;
+@@ -242,7 +242,7 @@ static void hfs_file_truncate(struct ino
+  *
+  * Like copy_to_user() while translating CR->NL.
+  */
+-static inline void xlate_to_user(char *buf, const char *data, int count)
++static inline void xlate_to_user(char __user *buf, const char *data, int count)
+ {
+       char ch;
+@@ -257,7 +257,8 @@ static inline void xlate_to_user(char *b
+  *
+  * Like copy_from_user() while translating NL->CR;
+  */
+-static inline int xlate_from_user(char *data, const char *buf, int count)
++static inline
++int xlate_from_user(char *data, const char __user *buf, int count)
+ {
+       int i;
+@@ -290,8 +291,8 @@ static inline int xlate_from_user(char *
+  * This is based on Linus's minix_file_read().
+  * It has been changed to take into account that HFS files have no holes.
+  */
+-hfs_s32 hfs_do_read(struct inode *inode, struct hfs_fork * fork, hfs_u32 pos,
+-                  char * buf, hfs_u32 count)
++hfs_s32 hfs_do_read(struct inode *inode, struct hfs_fork *fork, hfs_u32 pos,
++                  char __user *buf, hfs_u32 count)
+ {
+       hfs_s32 size, chars, offset, block, blocks, read = 0;
+       int bhrequest, uptodate;
+@@ -436,8 +437,8 @@ hfs_s32 hfs_do_read(struct inode *inode,
+  * 
+  * This is just a minor edit of Linus's minix_file_write().
+  */
+-hfs_s32 hfs_do_write(struct inode *inode, struct hfs_fork * fork, hfs_u32 pos,
+-                   const char * buf, hfs_u32 count)
++hfs_s32 hfs_do_write(struct inode *inode, struct hfs_fork *fork, hfs_u32 pos,
++                   const char __user *buf, hfs_u32 count)
+ {
+       hfs_s32 written, c;
+       struct buffer_head * bh;
+--- linux-2.6.0-test6/fs/hfs/file_cap.c        2003-06-14 12:18:22.000000000 -0700
++++ 25/fs/hfs/file_cap.c       2003-10-05 00:33:24.000000000 -0700
+@@ -29,9 +29,9 @@
+ /*================ Forward declarations ================*/
+ static loff_t      cap_info_llseek(struct file *, loff_t,
+                                    int);
+-static hfs_rwret_t cap_info_read(struct file *, char *,
++static hfs_rwret_t cap_info_read(struct file *, char __user *,
+                                hfs_rwarg_t, loff_t *);
+-static hfs_rwret_t cap_info_write(struct file *, const char *,
++static hfs_rwret_t cap_info_write(struct file *, const char __user *,
+                                 hfs_rwarg_t, loff_t *);
+ /*================ Function-like macros ================*/
+@@ -121,7 +121,7 @@ static loff_t cap_info_llseek(struct fil
+  * 'file->f_pos' to user-space at the address 'buf'.  The return value
+  * is the number of bytes actually transferred.
+  */
+-static hfs_rwret_t cap_info_read(struct file *filp, char *buf,
++static hfs_rwret_t cap_info_read(struct file *filp, char __user *buf,
+                                hfs_rwarg_t count, loff_t *ppos)
+ {
+       struct inode *inode = filp->f_dentry->d_inode;
+@@ -189,7 +189,7 @@ static hfs_rwret_t cap_info_read(struct 
+  * '*ppos' from user-space at the address 'buf'.
+  * The return value is the number of bytes actually transferred.
+  */
+-static hfs_rwret_t cap_info_write(struct file *filp, const char *buf, 
++static hfs_rwret_t cap_info_write(struct file *filp, const char __user *buf, 
+                                 hfs_rwarg_t count, loff_t *ppos)
+ {
+         struct inode *inode = filp->f_dentry->d_inode;
+--- linux-2.6.0-test6/fs/hfs/file_hdr.c        2003-06-14 12:18:25.000000000 -0700
++++ 25/fs/hfs/file_hdr.c       2003-10-05 00:33:24.000000000 -0700
+@@ -41,8 +41,9 @@
+ /*================ Forward declarations ================*/
+ static loff_t      hdr_llseek(struct file *, loff_t, int);
+-static hfs_rwret_t hdr_read(struct file *, char *, hfs_rwarg_t, loff_t *);
+-static hfs_rwret_t hdr_write(struct file *, const char *,
++static hfs_rwret_t hdr_read(struct file *, char __user *,
++                          hfs_rwarg_t, loff_t *);
++static hfs_rwret_t hdr_write(struct file *, const char __user *,
+                            hfs_rwarg_t, loff_t *);
+ /*================ Global variables ================*/
+@@ -382,7 +383,7 @@ loff_t hdr_llseek(struct file *file, lof
+  * successfully transferred.
+  */
+ /* XXX: what about the entry count changing on us? */
+-static hfs_rwret_t hdr_read(struct file * filp, char * buf, 
++static hfs_rwret_t hdr_read(struct file *filp, char __user *buf, 
+                           hfs_rwarg_t count, loff_t *ppos)
+ {
+       struct inode *inode = filp->f_dentry->d_inode;
+@@ -633,7 +634,7 @@ done:
+  * '*ppos' from user-space at the address 'buf'.
+  * The return value is the number of bytes actually transferred.
+  */
+-static hfs_rwret_t hdr_write(struct file *filp, const char *buf,
++static hfs_rwret_t hdr_write(struct file *filp, const char __user *buf,
+                            hfs_rwarg_t count, loff_t *ppos)
+ {
+       struct inode *inode = filp->f_dentry->d_inode;
+--- linux-2.6.0-test6/fs/hfs/super.c   2003-06-22 12:04:44.000000000 -0700
++++ 25/fs/hfs/super.c  2003-10-05 00:33:24.000000000 -0700
+@@ -31,6 +31,7 @@
+ #include <linux/blkdev.h>
+ #include <linux/module.h>
+ #include <linux/init.h>
++#include <linux/parser.h>
+ #include <linux/smp_lock.h>
+ #include <linux/vfs.h>
+@@ -211,6 +212,60 @@ static int hfs_statfs(struct super_block
+       return 0;
+ }
++enum {
++      Opt_version, Opt_uid, Opt_gid, Opt_umask, Opt_part,
++      Opt_type, Opt_creator, Opt_quiet, Opt_afpd,
++      Opt_names_netatalk, Opt_names_trivial, Opt_names_alpha, Opt_names_latin,
++      Opt_names_7bit, Opt_names_8bit, Opt_names_cap,
++      Opt_fork_netatalk, Opt_fork_single, Opt_fork_double, Opt_fork_cap,
++      Opt_case_lower, Opt_case_asis,
++      Opt_conv_binary, Opt_conv_text, Opt_conv_auto,
++};
++
++static match_table_t tokens = {
++      {Opt_version, "version=%u"},
++      {Opt_uid, "uid=%u"},
++      {Opt_gid, "gid=%u"},
++      {Opt_umask, "umask=%o"},
++      {Opt_part, "part=%u"},
++      {Opt_type, "type=%s"},
++      {Opt_creator, "creator=%s"},
++      {Opt_quiet, "quiet"},
++      {Opt_afpd, "afpd"},
++      {Opt_names_netatalk, "names=netatalk"},
++      {Opt_names_trivial, "names=trivial"},
++      {Opt_names_alpha, "names=alpha"},
++      {Opt_names_latin, "names=latin"},
++      {Opt_names_7bit, "names=7bit"},
++      {Opt_names_8bit, "names=8bit"},
++      {Opt_names_cap, "names=cap"},
++      {Opt_names_netatalk, "names=n"},
++      {Opt_names_trivial, "names=t"},
++      {Opt_names_alpha, "names=a"},
++      {Opt_names_latin, "names=l"},
++      {Opt_names_7bit, "names=7"},
++      {Opt_names_8bit, "names=8"},
++      {Opt_names_cap, "names=c"},
++      {Opt_fork_netatalk, "fork=netatalk"},
++      {Opt_fork_single, "fork=single"},
++      {Opt_fork_double, "fork=double"},
++      {Opt_fork_cap, "fork=cap"},
++      {Opt_fork_netatalk, "fork=n"},
++      {Opt_fork_single, "fork=s"},
++      {Opt_fork_double, "fork=d"},
++      {Opt_fork_cap, "fork=c"},
++      {Opt_case_lower, "case=lower"},
++      {Opt_case_asis, "case=asis"},
++      {Opt_case_lower, "case=l"},
++      {Opt_case_asis, "case=a"},
++      {Opt_conv_binary, "conv=binary"},
++      {Opt_conv_text, "conv=text"},
++      {Opt_conv_auto, "conv=auto"},
++      {Opt_conv_binary, "conv=b"},
++      {Opt_conv_text, "conv=t"},
++      {Opt_conv_auto, "conv=a"},
++};
++
+ /*
+  * parse_options()
+  * 
+@@ -219,8 +274,10 @@ static int hfs_statfs(struct super_block
+  */
+ static int parse_options(char *options, struct hfs_sb_info *hsb, int *part)
+ {
+-      char *this_char, *value;
++      char *p;
+       char names, fork;
++      substring_t args[MAX_OPT_ARGS];
++      int option;
+       /* initialize the sb with defaults */
+       memset(hsb, 0, sizeof(*hsb));
+@@ -243,117 +300,109 @@ static int parse_options(char *options, 
+       if (!options) {
+               goto done;
+       }
+-      while ((this_char = strsep(&options,",")) != NULL) {
+-              if (!*this_char)
++      while ((p = strsep(&options,",")) != NULL) {
++              int token;
++              if (!*p)
+                       continue;
+-              if ((value = strchr(this_char,'=')) != NULL) {
+-                      *value++ = 0;
+-              }
+-      /* Numeric-valued options */
+-              if (!strcmp(this_char, "version")) {
+-                      if (!value || !*value) {
+-                              return 0;
+-                      }
+-                      hsb->s_version = simple_strtoul(value,&value,0);
+-                      if (*value) {
+-                              return 0;
+-                      }
+-              } else if (!strcmp(this_char,"uid")) {
+-                      if (!value || !*value) {
+-                              return 0;
+-                      }
+-                      hsb->s_uid = simple_strtoul(value,&value,0);
+-                      if (*value) {
+-                              return 0;
+-                      }
+-              } else if (!strcmp(this_char,"gid")) {
+-                      if (!value || !*value) {
+-                              return 0;
+-                      }
+-                      hsb->s_gid = simple_strtoul(value,&value,0);
+-                      if (*value) {
+-                              return 0;
+-                      }
+-              } else if (!strcmp(this_char,"umask")) {
+-                      if (!value || !*value) {
+-                              return 0;
+-                      }
+-                      hsb->s_umask = simple_strtoul(value,&value,8);
+-                      if (*value) {
+-                              return 0;
+-                      }
+-              } else if (!strcmp(this_char,"part")) {
+-                      if (!value || !*value) {
+-                              return 0;
+-                      }
+-                      *part = simple_strtoul(value,&value,0);
+-                      if (*value) {
+-                              return 0;
+-                      }
+-      /* String-valued options */
+-              } else if (!strcmp(this_char,"type") && value) {
+-                      if (strlen(value) != 4) {
+-                              return 0;
+-                      }
+-                      hsb->s_type = hfs_get_nl(value);
+-              } else if (!strcmp(this_char,"creator") && value) {
+-                      if (strlen(value) != 4) {
+-                              return 0;
+-                      }
+-                      hsb->s_creator = hfs_get_nl(value);
+-      /* Boolean-valued options */
+-              } else if (!strcmp(this_char,"quiet")) {
+-                      if (value) {
+-                              return 0;
+-                      }
++
++              token = match_token(p, tokens, args);
++              switch (token) {
++              /* Numeric-valued options */
++              case Opt_version:
++                      if (match_int(&args[0], &option))
++                              return 0;
++                      hsb->s_version = option;
++                      break;
++              case Opt_uid:
++                      if (match_int(&args[0], &option))
++                              return 0;
++                      hsb->s_uid = option;
++                      break;
++              case Opt_gid:
++                      if (match_int(&args[0], &option))
++                              return 0;
++                      hsb->s_gid = option;
++                      break;
++              case Opt_umask:
++                      if (match_octal(&args[0], &option))
++                              return 0;
++                      hsb->s_umask = option;
++                      break;
++              case Opt_part:
++                      if (match_int(&args[0], &option))
++                              return 0;
++                      *part = option;
++                      break;
++              /* String-valued options */
++              case Opt_type:
++                      if (strlen(args[0].from) != 4) {
++                              return 0;
++                      }
++                      hsb->s_type = hfs_get_nl(args[0].from);
++                      break;
++              case Opt_creator:
++                      if (strlen(args[0].from) != 4) {
++                              return 0;
++                      }
++                      hsb->s_creator = hfs_get_nl(args[0].from);
++                      break;
++              /* Boolean-valued options */
++              case Opt_quiet:
+                       hsb->s_quiet = 1;
+-              } else if (!strcmp(this_char,"afpd")) {
+-                      if (value) {
+-                              return 0;
+-                      }
++                      break;
++              case Opt_afpd:
+                       hsb->s_afpd = 1;
+-      /* Multiple choice options */
+-              } else if (!strcmp(this_char,"names") && value) {
+-                      if ((*value && !value[1] && strchr("ntal78c",*value)) ||
+-                          !strcmp(value,"netatalk") ||
+-                          !strcmp(value,"trivial") ||
+-                          !strcmp(value,"alpha") ||
+-                          !strcmp(value,"latin") ||
+-                          !strcmp(value,"7bit") ||
+-                          !strcmp(value,"8bit") ||
+-                          !strcmp(value,"cap")) {
+-                              names = *value;
+-                      } else {
+-                              return 0;
+-                      }
+-              } else if (!strcmp(this_char,"fork") && value) {
+-                      if ((*value && !value[1] && strchr("nsdc",*value)) ||
+-                          !strcmp(value,"netatalk") ||
+-                          !strcmp(value,"single") ||
+-                          !strcmp(value,"double") ||
+-                          !strcmp(value,"cap")) {
+-                              fork = *value;
+-                      } else {
+-                              return 0;
+-                      }
+-              } else if (!strcmp(this_char,"case") && value) {
+-                      if ((*value && !value[1] && strchr("la",*value)) ||
+-                          !strcmp(value,"lower") ||
+-                          !strcmp(value,"asis")) {
+-                              hsb->s_lowercase = (*value == 'l');
+-                      } else {
+-                              return 0;
+-                      }
+-              } else if (!strcmp(this_char,"conv") && value) {
+-                      if ((*value && !value[1] && strchr("bta",*value)) ||
+-                          !strcmp(value,"binary") ||
+-                          !strcmp(value,"text") ||
+-                          !strcmp(value,"auto")) {
+-                              hsb->s_conv = *value;
+-                      } else {
+-                              return 0;
+-                      }
+-              } else {
++                      break;
++              /* Multiple choice options */
++              case Opt_names_netatalk:
++                      names = 'n';
++                      break;
++              case Opt_names_trivial:
++                      names = 't';
++                      break;
++              case Opt_names_alpha:
++                      names = 'a';
++                      break;
++              case Opt_names_latin:
++                      names = 'l';
++                      break;
++              case Opt_names_7bit:
++                      names = '7';
++                      break;
++              case Opt_names_8bit:
++                      names = '8';
++                      break;
++              case Opt_names_cap:
++                      names = 'c';
++                      break;
++              case Opt_fork_netatalk:
++                      fork = 'n';
++                      break;
++              case Opt_fork_single:
++                      fork = 's';
++                      break;
++              case Opt_fork_double:
++                      fork = 'd';
++                      break;
++              case Opt_fork_cap:
++                      fork = 'c';
++                      break;
++              case Opt_case_lower:
++                      hsb->s_lowercase = 1;
++                      break;
++              case Opt_case_asis:
++                      hsb->s_lowercase = 0;
++                      break;
++              case Opt_conv_binary:
++                      hsb->s_conv = 'b';
++                      break;
++              case Opt_conv_text:
++                      hsb->s_conv = 't';
++                      break;
++              case Opt_conv_auto:
++                      hsb->s_conv = 'a';
++                      break;
++              default:
+                       return 0;
+               }
+       }
+--- linux-2.6.0-test6/fs/hpfs/file.c   2003-06-14 12:18:35.000000000 -0700
++++ 25/fs/hpfs/file.c  2003-10-05 00:33:24.000000000 -0700
+@@ -124,7 +124,8 @@ struct address_space_operations hpfs_aop
+       .bmap = _hpfs_bmap
+ };
+-ssize_t hpfs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
++ssize_t hpfs_file_write(struct file *file, const char __user *buf,
++                      size_t count, loff_t *ppos)
+ {
+       ssize_t retval;
+--- linux-2.6.0-test6/fs/hpfs/hpfs_fn.h        2003-07-10 18:50:31.000000000 -0700
++++ 25/fs/hpfs/hpfs_fn.h       2003-10-05 00:33:24.000000000 -0700
+@@ -249,7 +249,7 @@ int hpfs_file_fsync(struct file *, struc
+ secno hpfs_bmap(struct inode *, unsigned);
+ void hpfs_truncate(struct inode *);
+ int hpfs_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create);
+-ssize_t hpfs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos);
++ssize_t hpfs_file_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos);
+ /* inode.c */
+--- linux-2.6.0-test6/fs/hpfs/super.c  2003-06-22 12:04:44.000000000 -0700
++++ 25/fs/hpfs/super.c 2003-10-05 00:33:24.000000000 -0700
+@@ -10,6 +10,7 @@
+ #include <linux/string.h>
+ #include "hpfs_fn.h"
+ #include <linux/module.h>
++#include <linux/parser.h>
+ #include <linux/init.h>
+ #include <linux/vfs.h>
+@@ -219,15 +220,52 @@ static struct super_operations hpfs_sops
+ /*
+  * A tiny parser for option strings, stolen from dosfs.
+- *
+  * Stolen again from read-only hpfs.
++ * And updated for table-driven option parsing.
+  */
++enum {
++      Opt_help, Opt_uid, Opt_gid, Opt_umask, Opt_case_lower, Opt_case_asis,
++      Opt_conv_binary, Opt_conv_text, Opt_conv_auto,
++      Opt_check_none, Opt_check_normal, Opt_check_strict,
++      Opt_err_cont, Opt_err_ro, Opt_err_panic,
++      Opt_eas_no, Opt_eas_ro, Opt_eas_rw,
++      Opt_chkdsk_no, Opt_chkdsk_errors, Opt_chkdsk_always,
++      Opt_timeshift, Opt_err,
++};
++
++static match_table_t tokens = {
++      {Opt_help, "help"},
++      {Opt_uid, "uid=%u"},
++      {Opt_gid, "gid=%u"},
++      {Opt_umask, "umask=%o"},
++      {Opt_case_lower, "case=lower"},
++      {Opt_case_asis, "case=asis"},
++      {Opt_conv_binary, "conv=binary"},
++      {Opt_conv_text, "conv=text"},
++      {Opt_conv_auto, "conv=auto"},
++      {Opt_check_none, "check=none"},
++      {Opt_check_normal, "check=normal"},
++      {Opt_check_strict, "check=strict"},
++      {Opt_err_cont, "errors=continue"},
++      {Opt_err_ro, "errors=remount-ro"},
++      {Opt_err_panic, "errors=panic"},
++      {Opt_eas_no, "eas=no"},
++      {Opt_eas_ro, "eas=ro"},
++      {Opt_eas_rw, "eas=rw"},
++      {Opt_chkdsk_no, "chkdsk=no"},
++      {Opt_chkdsk_errors, "chkdsk=errors"},
++      {Opt_chkdsk_always, "chkdsk=always"},
++      {Opt_timeshift, "timeshift=%d"},
++      {Opt_err, NULL},
++};
++
+ int parse_opts(char *opts, uid_t *uid, gid_t *gid, umode_t *umask,
+              int *lowercase, int *conv, int *eas, int *chk, int *errs,
+              int *chkdsk, int *timeshift)
+ {
+-      char *p, *rhs;
++      char *p;
++      int option;
+       if (!opts)
+               return 1;
+@@ -235,34 +273,85 @@ int parse_opts(char *opts, uid_t *uid, g
+       /*printk("Parsing opts: '%s'\n",opts);*/
+       while ((p = strsep(&opts, ",")) != NULL) {
++              substring_t args[MAX_OPT_ARGS];
++              int token;
+               if (!*p)
+                       continue;
+-              if ((rhs = strchr(p, '=')) != 0)
+-                      *rhs++ = '\0';
+-              if (!strcmp(p, "help")) return 2;
+-              if (!strcmp(p, "uid")) {
+-                      if (!rhs || !*rhs)
+-                              return 0;
+-                      *uid = simple_strtoul(rhs, &rhs, 0);
+-                      if (*rhs)
+-                              return 0;
+-              }
+-              else if (!strcmp(p, "gid")) {
+-                      if (!rhs || !*rhs)
+-                              return 0;
+-                      *gid = simple_strtoul(rhs, &rhs, 0);
+-                      if (*rhs)
+-                              return 0;
+-              }
+-              else if (!strcmp(p, "umask")) {
+-                      if (!rhs || !*rhs)
+-                              return 0;
+-                      *umask = simple_strtoul(rhs, &rhs, 8);
+-                      if (*rhs)
+-                              return 0;
+-              }
+-              else if (!strcmp(p, "timeshift")) {
++
++              token = match_token(p, tokens, args);
++              switch (token) {
++              case Opt_help:
++                      return 2;
++              case Opt_uid:
++                      if (match_int(args, &option))
++                              return 0;
++                      *uid = option;
++                      break;
++              case Opt_gid:
++                      if (match_int(args, &option))
++                              return 0;
++                      *gid = option;
++                      break;
++              case Opt_umask:
++                      if (match_octal(args, &option))
++                              return 0;
++                      *umask = option;
++                      break;
++              case Opt_case_lower:
++                      *lowercase = 1;
++                      break;
++              case Opt_case_asis:
++                      *lowercase = 0;
++                      break;
++              case Opt_conv_binary:
++                      *conv = CONV_BINARY;
++                      break;
++              case Opt_conv_text:
++                      *conv = CONV_TEXT;
++                      break;
++              case Opt_conv_auto:
++                      *conv = CONV_AUTO;
++                      break;
++              case Opt_check_none:
++                      *chk = 0;
++                      break;
++              case Opt_check_normal:
++                      *chk = 1;
++                      break;
++              case Opt_check_strict:
++                      *chk = 2;
++                      break;
++              case Opt_err_cont:
++                      *errs = 0;
++                      break;
++              case Opt_err_ro:
++                      *errs = 1;
++                      break;
++              case Opt_err_panic:
++                      *errs = 2;
++                      break;
++              case Opt_eas_no:
++                      *eas = 0;
++                      break;
++              case Opt_eas_ro:
++                      *eas = 1;
++                      break;
++              case Opt_eas_rw:
++                      *eas = 2;
++                      break;
++              case Opt_chkdsk_no:
++                      *chkdsk = 0;
++                      break;
++              case Opt_chkdsk_errors:
++                      *chkdsk = 1;
++                      break;
++              case Opt_chkdsk_always:
++                      *chkdsk = 2;
++                      break;
++              case Opt_timeshift:
++              {
+                       int m = 1;
++                      char *rhs = args[0].from;
+                       if (!rhs || !*rhs)
+                               return 0;
+                       if (*rhs == '-') m = -1;
+@@ -270,79 +359,11 @@ int parse_opts(char *opts, uid_t *uid, g
+                       *timeshift = simple_strtoul(rhs, &rhs, 0) * m;
+                       if (*rhs)
+                               return 0;
++                      break;
+               }
+-              else if (!strcmp(p, "case")) {
+-                      if (!rhs || !*rhs)
+-                              return 0;
+-                      if (!strcmp(rhs, "lower"))
+-                              *lowercase = 1;
+-                      else if (!strcmp(rhs, "asis"))
+-                              *lowercase = 0;
+-                      else
+-                              return 0;
+-              }
+-              else if (!strcmp(p, "conv")) {
+-                      if (!rhs || !*rhs)
+-                              return 0;
+-                      if (!strcmp(rhs, "binary"))
+-                              *conv = CONV_BINARY;
+-                      else if (!strcmp(rhs, "text"))
+-                              *conv = CONV_TEXT;
+-                      else if (!strcmp(rhs, "auto"))
+-                              *conv = CONV_AUTO;
+-                      else
+-                              return 0;
+-              }
+-              else if (!strcmp(p, "check")) {
+-                      if (!rhs || !*rhs)
+-                              return 0;
+-                      if (!strcmp(rhs, "none"))
+-                              *chk = 0;
+-                      else if (!strcmp(rhs, "normal"))
+-                              *chk = 1;
+-                      else if (!strcmp(rhs, "strict"))
+-                              *chk = 2;
+-                      else
+-                              return 0;
+-              }
+-              else if (!strcmp(p, "errors")) {
+-                      if (!rhs || !*rhs)
+-                              return 0;
+-                      if (!strcmp(rhs, "continue"))
+-                              *errs = 0;
+-                      else if (!strcmp(rhs, "remount-ro"))
+-                              *errs = 1;
+-                      else if (!strcmp(rhs, "panic"))
+-                              *errs = 2;
+-                      else
+-                              return 0;
+-              }
+-              else if (!strcmp(p, "eas")) {
+-                      if (!rhs || !*rhs)
+-                              return 0;
+-                      if (!strcmp(rhs, "no"))
+-                              *eas = 0;
+-                      else if (!strcmp(rhs, "ro"))
+-                              *eas = 1;
+-                      else if (!strcmp(rhs, "rw"))
+-                              *eas = 2;
+-                      else
+-                              return 0;
+-              }
+-              else if (!strcmp(p, "chkdsk")) {
+-                      if (!rhs || !*rhs)
+-                              return 0;
+-                      if (!strcmp(rhs, "no"))
+-                              *chkdsk = 0;
+-                      else if (!strcmp(rhs, "errors"))
+-                              *chkdsk = 1;
+-                      else if (!strcmp(rhs, "always"))
+-                              *chkdsk = 2;
+-                      else
+-                              return 0;
+-              }
+-              else
++              default:
+                       return 0;
++              }
+       }
+       return 1;
+ }
+--- linux-2.6.0-test6/fs/hugetlbfs/inode.c     2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/hugetlbfs/inode.c    2003-10-05 00:37:03.000000000 -0700
+@@ -165,7 +165,7 @@ void truncate_hugepages(struct address_s
+       pagevec_init(&pvec, 0);
+       next = start;
+       while (1) {
+-              if (!pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) {
++              if (!pagevec_lookup(&pvec, mapping, &next, PAGEVEC_SIZE)) {
+                       if (next == start)
+                               break;
+                       next = start;
+@@ -176,9 +176,6 @@ void truncate_hugepages(struct address_s
+                       struct page *page = pvec.pages[i];
+                       lock_page(page);
+-                      if (page->index > next)
+-                              next = page->index;
+-                      ++next;
+                       truncate_huge_page(page);
+                       unlock_page(page);
+                       hugetlb_put_quota(mapping);
+@@ -648,11 +645,6 @@ hugetlbfs_fill_super(struct super_block 
+       struct hugetlbfs_config config;
+       struct hugetlbfs_sb_info *sbinfo;
+-      sbinfo = kmalloc(sizeof(struct hugetlbfs_sb_info), GFP_KERNEL);
+-      if (!sbinfo)
+-              return -ENOMEM;
+-      sb->s_fs_info = sbinfo;
+-
+       config.nr_blocks = -1; /* No limit on size by default */
+       config.nr_inodes = -1; /* No limit on number of inodes by default */
+       config.uid = current->fsuid;
+@@ -663,6 +655,10 @@ hugetlbfs_fill_super(struct super_block 
+       if (ret)
+               return ret;
++      sbinfo = kmalloc(sizeof(struct hugetlbfs_sb_info), GFP_KERNEL);
++      if (!sbinfo)
++              return -ENOMEM;
++      sb->s_fs_info = sbinfo;
+       spin_lock_init(&sbinfo->stat_lock);
+       sbinfo->max_blocks = config.nr_blocks;
+       sbinfo->free_blocks = config.nr_blocks;
+@@ -675,15 +671,18 @@ hugetlbfs_fill_super(struct super_block 
+       inode = hugetlbfs_get_inode(sb, config.uid, config.gid,
+                                       S_IFDIR | config.mode, 0);
+       if (!inode)
+-              return -ENOMEM;
++              goto out_free;
+       root = d_alloc_root(inode);
+       if (!root) {
+               iput(inode);
+-              return -ENOMEM;
++              goto out_free;
+       }
+       sb->s_root = root;
+       return 0;
++out_free:
++      kfree(sbinfo);
++      return -ENOMEM;
+ }
+ int hugetlb_get_quota(struct address_space *mapping)
+@@ -772,6 +771,7 @@ struct file *hugetlb_zero_setup(size_t s
+       inode->i_nlink = 0;
+       file->f_vfsmnt = mntget(hugetlbfs_vfsmount);
+       file->f_dentry = dentry;
++      file->f_mapping = inode->i_mapping;
+       file->f_op = &hugetlbfs_file_operations;
+       file->f_mode = FMODE_WRITE | FMODE_READ;
+       return file;
+--- linux-2.6.0-test6/fs/inode.c       2003-09-08 13:58:58.000000000 -0700
++++ 25/fs/inode.c      2003-10-05 00:36:52.000000000 -0700
+@@ -183,6 +183,7 @@ void inode_init_once(struct inode *inode
+       INIT_LIST_HEAD(&inode->i_dentry);
+       INIT_LIST_HEAD(&inode->i_devices);
+       sema_init(&inode->i_sem, 1);
++      init_rwsem(&inode->i_alloc_sem);
+       INIT_RADIX_TREE(&inode->i_data.page_tree, GFP_ATOMIC);
+       spin_lock_init(&inode->i_data.page_lock);
+       init_MUTEX(&inode->i_data.i_shared_sem);
+@@ -195,6 +196,8 @@ void inode_init_once(struct inode *inode
+       i_size_ordered_init(inode);
+ }
++EXPORT_SYMBOL(inode_init_once);
++
+ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+ {
+       struct inode * inode = (struct inode *) foo;
+@@ -229,7 +232,6 @@ void __iget(struct inode * inode)
+  * that the inode is no longer useful. We just
+  * terminate it with extreme prejudice.
+  */
+- 
+ void clear_inode(struct inode *inode)
+ {
+       invalidate_inode_buffers(inode);
+@@ -251,7 +253,12 @@ void clear_inode(struct inode *inode)
+       inode->i_state = I_CLEAR;
+ }
++EXPORT_SYMBOL(clear_inode);
++
+ /*
++ * dispose_list - dispose of the contents of a local list
++ * @head: the head of the list to free
++ *
+  * Dispose-list gets a local list with local inodes in it, so it doesn't
+  * need to worry about list corruption and SMP locks.
+  */
+@@ -327,7 +334,6 @@ static int invalidate_list(struct list_h
+  *    fails because there are busy inodes then a non zero value is returned.
+  *    If the discard is successful all the inodes have been discarded.
+  */
+- 
+ int invalidate_inodes(struct super_block * sb)
+ {
+       int busy;
+@@ -346,6 +352,8 @@ int invalidate_inodes(struct super_block
+       return busy;
+ }
++
++EXPORT_SYMBOL(invalidate_inodes);
+  
+ int __invalidate_device(struct block_device *bdev, int do_sync)
+ {
+@@ -372,6 +380,8 @@ int __invalidate_device(struct block_dev
+       return res;
+ }
++EXPORT_SYMBOL(__invalidate_device);
++
+ static int can_unuse(struct inode *inode)
+ {
+       if (inode->i_state)
+@@ -532,7 +542,6 @@ repeat:
+  *
+  *    Allocates a new inode for given superblock.
+  */
+- 
+ struct inode *new_inode(struct super_block *sb)
+ {
+       static unsigned long last_ino;
+@@ -552,6 +561,8 @@ struct inode *new_inode(struct super_blo
+       return inode;
+ }
++EXPORT_SYMBOL(new_inode);
++
+ void unlock_new_inode(struct inode *inode)
+ {
+       /*
+@@ -565,6 +576,7 @@ void unlock_new_inode(struct inode *inod
+       inode->i_state &= ~(I_LOCK|I_NEW);
+       wake_up_inode(inode);
+ }
++
+ EXPORT_SYMBOL(unlock_new_inode);
+ /*
+@@ -685,7 +697,6 @@ static inline unsigned long hash(struct 
+  *    With a large number of inodes live on the file system this function
+  *    currently becomes quite slow.
+  */
+- 
+ ino_t iunique(struct super_block *sb, ino_t max_reserved)
+ {
+       static ino_t counter;
+@@ -709,6 +720,8 @@ retry:
+       
+ }
++EXPORT_SYMBOL(iunique);
++
+ struct inode *igrab(struct inode *inode)
+ {
+       spin_lock(&inode_lock);
+@@ -725,14 +738,16 @@ struct inode *igrab(struct inode *inode)
+       return inode;
+ }
++EXPORT_SYMBOL(igrab);
++
+ /**
+  * ifind - internal function, you want ilookup5() or iget5().
+  * @sb:               super block of file system to search
+- * @hashval:  hash value (usually inode number) to search for
++ * @head:       the head of the list to search
+  * @test:     callback used for comparisons between inodes
+  * @data:     opaque data pointer to pass to @test
+  *
+- * ifind() searches for the inode specified by @hashval and @data in the inode
++ * ifind() searches for the inode specified by @data in the inode
+  * cache. This is a generalized version of ifind_fast() for file systems where
+  * the inode number is not sufficient for unique identification of an inode.
+  *
+@@ -764,6 +779,7 @@ static inline struct inode *ifind(struct
+ /**
+  * ifind_fast - internal function, you want ilookup() or iget().
+  * @sb:               super block of file system to search
++ * @head:       head of the list to search
+  * @ino:      inode number to search for
+  *
+  * ifind_fast() searches for the inode @ino in the inode cache. This is for
+@@ -818,6 +834,7 @@ struct inode *ilookup5(struct super_bloc
+       return ifind(sb, head, test, data);
+ }
++
+ EXPORT_SYMBOL(ilookup5);
+ /**
+@@ -840,6 +857,7 @@ struct inode *ilookup(struct super_block
+       return ifind_fast(sb, head, ino);
+ }
++
+ EXPORT_SYMBOL(ilookup);
+ /**
+@@ -880,6 +898,7 @@ struct inode *iget5_locked(struct super_
+        */
+       return get_new_inode(sb, head, test, set, data);
+ }
++
+ EXPORT_SYMBOL(iget5_locked);
+ /**
+@@ -913,6 +932,7 @@ struct inode *iget_locked(struct super_b
+        */
+       return get_new_inode_fast(sb, head, ino);
+ }
++
+ EXPORT_SYMBOL(iget_locked);
+ /**
+@@ -923,7 +943,6 @@ EXPORT_SYMBOL(iget_locked);
+  *
+  *    Add an inode to the inode hash for this superblock.
+  */
+- 
+ void __insert_inode_hash(struct inode *inode, unsigned long hashval)
+ {
+       struct hlist_head *head = inode_hashtable + hash(inode->i_sb, hashval);
+@@ -932,13 +951,14 @@ void __insert_inode_hash(struct inode *i
+       spin_unlock(&inode_lock);
+ }
++EXPORT_SYMBOL(__insert_inode_hash);
++
+ /**
+  *    remove_inode_hash - remove an inode from the hash
+  *    @inode: inode to unhash
+  *
+  *    Remove an inode from the superblock.
+  */
+- 
+ void remove_inode_hash(struct inode *inode)
+ {
+       spin_lock(&inode_lock);
+@@ -946,6 +966,8 @@ void remove_inode_hash(struct inode *ino
+       spin_unlock(&inode_lock);
+ }
++EXPORT_SYMBOL(remove_inode_hash);
++
+ /*
+  * Tell the filesystem that this inode is no longer of any interest and should
+  * be completely destroyed.
+@@ -988,6 +1010,7 @@ void generic_delete_inode(struct inode *
+               BUG();
+       destroy_inode(inode);
+ }
++
+ EXPORT_SYMBOL(generic_delete_inode);
+ static void generic_forget_inode(struct inode *inode)
+@@ -1059,7 +1082,6 @@ static inline void iput_final(struct ino
+  *    Puts an inode, dropping its usage count. If the inode use count hits
+  *    zero the inode is also then freed and may be destroyed.
+  */
+- 
+ void iput(struct inode *inode)
+ {
+       if (inode) {
+@@ -1076,6 +1098,8 @@ void iput(struct inode *inode)
+       }
+ }
++EXPORT_SYMBOL(iput);
++
+ /**
+  *    bmap    - find a block number in a file
+  *    @inode: inode of file
+@@ -1087,7 +1111,6 @@ void iput(struct inode *inode)
+  *    disk block relative to the disk start that holds that block of the 
+  *    file.
+  */
+- 
+ sector_t bmap(struct inode * inode, sector_t block)
+ {
+       sector_t res = 0;
+@@ -1096,6 +1119,8 @@ sector_t bmap(struct inode * inode, sect
+       return res;
+ }
++EXPORT_SYMBOL(bmap);
++
+ /*
+  * Return true if the filesystem which backs this inode considers the two
+  * passed timespecs to be sufficiently different to warrant flushing the
+@@ -1117,7 +1142,6 @@ static int inode_times_differ(struct ino
+  *    This function automatically handles read only file systems and media,
+  *    as well as the "noatime" flag and inode specific "noatime" markers.
+  */
+- 
+ void update_atime(struct inode *inode)
+ {
+       struct timespec now;
+@@ -1139,6 +1163,8 @@ void update_atime(struct inode *inode)
+       }
+ }
++EXPORT_SYMBOL(update_atime);
++
+ /**
+  *    inode_update_time       -       update mtime and ctime time
+  *    @inode: inode accessed
+@@ -1170,6 +1196,7 @@ void inode_update_time(struct inode *ino
+       if (sync_it)
+               mark_inode_dirty_sync(inode);
+ }
++
+ EXPORT_SYMBOL(inode_update_time);
+ int inode_needs_sync(struct inode *inode)
+@@ -1180,6 +1207,7 @@ int inode_needs_sync(struct inode *inode
+               return 1;
+       return 0;
+ }
++
+ EXPORT_SYMBOL(inode_needs_sync);
+ /*
+@@ -1375,3 +1403,5 @@ void init_special_inode(struct inode *in
+               printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o)\n",
+                      mode);
+ }
++
++EXPORT_SYMBOL(init_special_inode);
+--- linux-2.6.0-test6/fs/intermezzo/file.c     2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/intermezzo/file.c    2003-10-05 00:34:01.000000000 -0700
+@@ -337,7 +337,7 @@ static void presto_apply_write_policy(st
+                                 unlock_kernel();
+                                 return; 
+                         }
+-                        error = presto_journal_close(&rec, fset, file,
++                        error = presto_journal_close(&rec, fset, fdata,
+                                                      file->f_dentry,
+                                                      &fdata->fd_version,
+                                                      &new_file_ver);
+--- linux-2.6.0-test6/fs/intermezzo/intermezzo_fs.h    2003-07-10 18:50:31.000000000 -0700
++++ 25/fs/intermezzo/intermezzo_fs.h   2003-10-05 00:34:01.000000000 -0700
+@@ -603,7 +603,7 @@ int presto_journal_rename(struct rec_inf
+ int presto_journal_open(struct rec_info *, struct presto_file_set *,
+                         struct dentry *, struct presto_version *old_ver);
+ int presto_journal_close(struct rec_info *rec, struct presto_file_set *,
+-                         struct file *, struct dentry *,
++                         struct presto_file_data *, struct dentry *,
+                          struct presto_version *old_file_ver,
+                          struct presto_version *new_file_ver);
+ int presto_write_lml_close(struct rec_info *rec,
+--- linux-2.6.0-test6/fs/intermezzo/journal.c  2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/intermezzo/journal.c 2003-10-05 00:34:01.000000000 -0700
+@@ -2104,12 +2104,11 @@ int presto_journal_unlink(struct rec_inf
+ int
+ presto_journal_close(struct rec_info *rec, struct presto_file_set *fset,
+-                     struct file *file, struct dentry *dentry,
++                     struct presto_file_data *fd, struct dentry *dentry,
+                      struct presto_version *old_file_ver,
+                      struct presto_version *new_file_ver)
+ {
+         int opcode = KML_OPCODE_CLOSE;
+-        struct presto_file_data *fd;
+         char *buffer, *path, *logrecord, record[316];
+         struct dentry *root;
+         int error, size, i;
+@@ -2138,7 +2137,6 @@ presto_journal_close(struct rec_info *re
+         root = fset->fset_dentry;
+-        fd = (struct presto_file_data *)file->private_data;
+         if (fd) {
+                 open_ngroups = fd->fd_ngroups;
+                 for (i = 0; i < fd->fd_ngroups; i++)
+--- linux-2.6.0-test6/fs/intermezzo/presto.c   2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/intermezzo/presto.c  2003-10-05 00:34:01.000000000 -0700
+@@ -260,11 +260,8 @@ int lento_cancel_lml(char *path, 
+         if (info->flags & LENTO_FL_WRITE_KML) {
+-                struct file file;
+-                file.private_data = NULL;
+-                file.f_dentry = dentry; 
+                 presto_getversion(&new_ver, dentry->d_inode);
+-                error = presto_journal_close(&rec, fset, &file, dentry, 
++                error = presto_journal_close(&rec, fset, NULL, dentry, 
+                                              &new_ver);
+                 if ( error ) {
+                         EXIT; 
+--- linux-2.6.0-test6/fs/intermezzo/vfs.c      2003-09-08 13:58:58.000000000 -0700
++++ 25/fs/intermezzo/vfs.c     2003-10-05 00:34:03.000000000 -0700
+@@ -322,7 +322,7 @@ int presto_do_close(struct presto_file_s
+         }
+         if (fdata->fd_info.flags & LENTO_FL_KML) 
+-                rc = presto_journal_close(&rec, fset, file, file->f_dentry,
++                rc = presto_journal_close(&rec, fset, fdata, file->f_dentry,
+                                           &fdata->fd_version, 
+                                           &fdata->fd_info.remote_version);
+         if (rc) { 
+@@ -432,14 +432,11 @@ int presto_do_setattr(struct presto_file
+         if ( presto_do_kml(info, dentry) ) {
+                 if ((iattr->ia_valid & ATTR_SIZE) && (old_size != inode->i_size)) {
+-                        struct file file;
+                         /* Journal a close whenever we see a potential truncate
+                         * At the receiving end, lento should explicitly remove
+                         * ATTR_SIZE from the list of valid attributes */
+                         presto_getversion(&new_ver, inode);
+-                        file.private_data = NULL;
+-                        file.f_dentry = dentry;
+-                        error = presto_journal_close(&rec, fset, &file, dentry,
++                        error = presto_journal_close(&rec, fset, NULL, dentry,
+                                                      &old_ver, &new_ver);
+                 }
+@@ -2087,7 +2084,9 @@ static struct file *presto_filp_dopen(st
+                 }
+         }
++      /* XXX: where the fuck is ->f_vfsmnt? */
+         f->f_dentry = dentry;
++        f->f_mapping = dentry->d_inode->i_mapping;
+         f->f_pos = 0;
+         //f->f_reada = 0;
+         f->f_op = NULL;
+--- linux-2.6.0-test6/fs/ioctl.c       2003-07-13 21:44:35.000000000 -0700
++++ 25/fs/ioctl.c      2003-10-05 00:34:08.000000000 -0700
+@@ -22,7 +22,7 @@ static int file_ioctl(struct file *filp,
+       switch (cmd) {
+               case FIBMAP:
+               {
+-                      struct address_space *mapping = inode->i_mapping;
++                      struct address_space *mapping = filp->f_mapping;
+                       int res;
+                       /* do we support this mess? */
+                       if (!mapping->a_ops->bmap)
+--- linux-2.6.0-test6/fs/isofs/inode.c 2003-09-08 13:58:58.000000000 -0700
++++ 25/fs/isofs/inode.c        2003-10-05 00:33:24.000000000 -0700
+@@ -29,6 +29,7 @@
+ #include <linux/blkdev.h>
+ #include <linux/buffer_head.h>
+ #include <linux/vfs.h>
++#include <linux/parser.h>
+ #include <asm/system.h>
+ #include <asm/uaccess.h>
+@@ -328,9 +329,52 @@ isofs_dentry_cmpi_ms(struct dentry *dent
+ }
+ #endif
++enum {
++      Opt_block, Opt_check_r, Opt_check_s, Opt_cruft, Opt_gid, Opt_ignore,
++      Opt_iocharset, Opt_map_a, Opt_map_n, Opt_map_o, Opt_mode, Opt_nojoliet,
++      Opt_norock, Opt_sb, Opt_session, Opt_uid, Opt_unhide, Opt_utf8, Opt_err,
++      Opt_nocompress,
++};
++
++static match_table_t tokens = {
++      {Opt_norock, "norock"},
++      {Opt_nojoliet, "nojoliet"},
++      {Opt_unhide, "unhide"},
++      {Opt_cruft, "cruft"},
++      {Opt_utf8, "utf8"},
++      {Opt_iocharset, "iocharset=%s"},
++      {Opt_map_a, "map=acorn"},
++      {Opt_map_a, "map=a"},
++      {Opt_map_n, "map=normal"},
++      {Opt_map_n, "map=n"},
++      {Opt_map_o, "map=off"},
++      {Opt_map_o, "map=o"},
++      {Opt_session, "session=%u"},
++      {Opt_sb, "sbsector=%u"},
++      {Opt_check_r, "check=relaxed"},
++      {Opt_check_r, "check=r"},
++      {Opt_check_s, "check=strict"},
++      {Opt_check_s, "check=s"},
++      {Opt_uid, "uid=%u"},
++      {Opt_gid, "gid=%u"},
++      {Opt_mode, "mode=%u"},
++      {Opt_block, "block=%u"},
++      {Opt_ignore, "conv=binary"},
++      {Opt_ignore, "conv=b"},
++      {Opt_ignore, "conv=text"},
++      {Opt_ignore, "conv=t"},
++      {Opt_ignore, "conv=mtext"},
++      {Opt_ignore, "conv=m"},
++      {Opt_ignore, "conv=auto"},
++      {Opt_ignore, "conv=a"},
++      {Opt_nocompress, "nocompress"},
++      {Opt_err, NULL}
++};
++
+ static int parse_options(char *options, struct iso9660_options * popt)
+ {
+-      char *this_char,*value;
++      char *p;
++      int option;
+       popt->map = 'n';
+       popt->rock = 'y';
+@@ -350,112 +394,101 @@ static int parse_options(char *options, 
+       popt->utf8 = 0;
+       popt->session=-1;
+       popt->sbsector=-1;
+-      if (!options) return 1;
+-      while ((this_char = strsep(&options,",")) != NULL) {
+-              if (!*this_char)
++      if (!options)
++              return 1;
++
++      while ((p = strsep(&options, ",")) != NULL) {
++              int token;
++              substring_t args[MAX_OPT_ARGS];
++              unsigned n;
++
++              if (!*p)
+                       continue;
+-              if (strncmp(this_char,"norock",6) == 0) {
+-                popt->rock = 'n';
+-                continue;
+-              }
+-              if (strncmp(this_char,"nojoliet",8) == 0) {
+-                popt->joliet = 'n';
+-                continue;
+-              }
+-              if (strncmp(this_char,"unhide",6) == 0) {
+-                popt->unhide = 'y';
+-                continue;
+-              }
+-              if (strncmp(this_char,"cruft",5) == 0) {
+-                popt->cruft = 'y';
+-                continue;
+-              }
+-              if (strncmp(this_char,"utf8",4) == 0) {
+-                popt->utf8 = 1;
+-                continue;
+-              }
+-              if (strncmp(this_char,"nocompress",10) == 0) {
+-                popt->nocompress = 1;
+-                continue;
+-              }
+-              if ((value = strchr(this_char,'=')) != NULL)
+-                      *value++ = 0;
++              token = match_token(p, tokens, args);
++              switch (token) {
++              case Opt_norock:
++                      popt->rock = 'n';
++                      break;
++              case Opt_nojoliet:
++                      popt->joliet = 'n';
++                      break;
++              case Opt_unhide:
++                      popt->unhide = 'y';
++                      break;
++              case Opt_cruft:
++                      popt->cruft = 'y';
++                      break;
++              case Opt_utf8:
++                      popt->utf8 = 1;
++                      break;
+ #ifdef CONFIG_JOLIET
+-              if (!strcmp(this_char,"iocharset") && value) {
+-                      popt->iocharset = value;
+-                      while (*value && *value != ',')
+-                              value++;
+-                      if (value == popt->iocharset)
+-                              return 0;
+-                      *value = 0;
+-              } else
++              case Opt_iocharset:
++                      popt->iocharset = match_strdup(&args[0]);
++                      break;
+ #endif
+-              if (!strcmp(this_char,"map") && value) {
+-                      if (value[0] && !value[1] && strchr("ano",*value))
+-                              popt->map = *value;
+-                      else if (!strcmp(value,"off")) popt->map = 'o';
+-                      else if (!strcmp(value,"normal")) popt->map = 'n';
+-                      else if (!strcmp(value,"acorn")) popt->map = 'a';
+-                      else return 0;
+-              }
+-              if (!strcmp(this_char,"session") && value) {
+-                      char * vpnt = value;
+-                      unsigned int ivalue = simple_strtoul(vpnt, &vpnt, 0);
+-                      if(ivalue < 0 || ivalue >99) return 0;
+-                      popt->session=ivalue+1;
+-              }
+-              if (!strcmp(this_char,"sbsector") && value) {
+-                      char * vpnt = value;
+-                      unsigned int ivalue = simple_strtoul(vpnt, &vpnt, 0);
+-                      if(ivalue < 0 || ivalue >660*512) return 0;
+-                      popt->sbsector=ivalue;
+-              }
+-              else if (!strcmp(this_char,"check") && value) {
+-                      if (value[0] && !value[1] && strchr("rs",*value))
+-                              popt->check = *value;
+-                      else if (!strcmp(value,"relaxed")) popt->check = 'r';
+-                      else if (!strcmp(value,"strict")) popt->check = 's';
+-                      else return 0;
+-              }
+-              else if (!strcmp(this_char,"conv") && value) {
+-                      /* no conversion is done anymore;
+-                         we still accept the same mount options,
+-                         but ignore them */
+-                      if (value[0] && !value[1] && strchr("btma",*value)) ;
+-                      else if (!strcmp(value,"binary")) ;
+-                      else if (!strcmp(value,"text")) ;
+-                      else if (!strcmp(value,"mtext")) ;
+-                      else if (!strcmp(value,"auto")) ;
+-                      else return 0;
+-              }
+-              else if (value &&
+-                       (!strcmp(this_char,"block") ||
+-                        !strcmp(this_char,"mode") ||
+-                        !strcmp(this_char,"uid") ||
+-                        !strcmp(this_char,"gid"))) {
+-                char * vpnt = value;
+-                unsigned int ivalue = simple_strtoul(vpnt, &vpnt, 0);
+-                if (*vpnt) return 0;
+-                switch(*this_char) {
+-                case 'b':
+-                  if (   ivalue != 512
+-                      && ivalue != 1024
+-                      && ivalue != 2048) return 0;
+-                  popt->blocksize = ivalue;
+-                  break;
+-                case 'u':
+-                  popt->uid = ivalue;
+-                  break;
+-                case 'g':
+-                  popt->gid = ivalue;
+-                  break;
+-                case 'm':
+-                  popt->mode = ivalue;
+-                  break;
+-                }
++              case Opt_map_a:
++                      popt->map = 'a';
++                      break;
++              case Opt_map_o:
++                      popt->map = 'o';
++                      break;
++              case Opt_map_n:
++                      popt->map = 'n';
++                      break;
++              case Opt_session:
++                      if (match_int(&args[0], &option))
++                              return 0;
++                      n = option;
++                      if (n > 99)
++                              return 0;
++                      popt->session = n + 1;
++                      break;
++              case Opt_sb:
++                      if (match_int(&args[0], &option))
++                              return 0;
++                      n = option;
++                      if (n > 660 * 512)
++                              return 0;
++                      popt->sbsector = n;
++                      break;
++              case Opt_check_r:
++                      popt->check = 'r';
++                      break;
++              case Opt_check_s:
++                      popt->check = 's';
++                      break;
++              case Opt_ignore:
++                      break;
++              case Opt_uid:
++                      if (match_int(&args[0], &option))
++                              return 0;
++                      popt->uid = option;
++                      break;
++              case Opt_gid:
++                      if (match_int(&args[0], &option))
++                              return 0;
++                      popt->gid = option;
++                      break;
++              case Opt_mode:
++                      if (match_int(&args[0], &option))
++                              return 0;
++                      popt->mode = option;
++                      break;
++              case Opt_block:
++                      if (match_int(&args[0], &option))
++                              return 0;
++                      n = option;
++                      if (n != 512 && n != 1024 && n != 2048)
++                              return 0;
++                      popt->blocksize = n;
++                      break;
++              case Opt_nocompress:
++                      popt->nocompress = 1;
++                      break;
++              default:
++                      return 0;
+               }
+-              else return 1;
+       }
+       return 1;
+ }
+@@ -842,6 +875,9 @@ root_found:
+       if (opt.check == 'r') table++;
+       s->s_root->d_op = &isofs_dentry_ops[table];
++      if (opt.iocharset)
++              kfree(opt.iocharset);
++
+       return 0;
+       /*
+@@ -879,6 +915,8 @@ out_unknown_format:
+ out_freebh:
+       brelse(bh);
+ out_freesbi:
++      if (opt.iocharset)
++              kfree(opt.iocharset);
+       kfree(sbi);
+       s->s_fs_info = NULL;
+       return -EINVAL;
+--- linux-2.6.0-test6/fs/jbd/journal.c 2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/jbd/journal.c        2003-10-05 00:33:24.000000000 -0700
+@@ -1800,7 +1800,7 @@ int read_jbd_debug(char *page, char **st
+       return ret;
+ }
+-int write_jbd_debug(struct file *file, const char *buffer,
++int write_jbd_debug(struct file *file, const char __user *buffer,
+                          unsigned long count, void *data)
+ {
+       char buf[32];
+--- linux-2.6.0-test6/fs/jffs/intrep.c 2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/jffs/intrep.c        2003-10-05 00:34:48.000000000 -0700
+@@ -3337,18 +3337,16 @@ jffs_garbage_collect_thread(void *ptr)
+       int result = 0;
+       D1(int i = 1);
++      daemonize("jffs_gcd");
++
+       c->gc_task = current;
+       lock_kernel();
+-      exit_mm(c->gc_task);
+-
+-      set_special_pids(1, 1);
+       init_completion(&c->gc_thread_comp); /* barrier */ 
+       spin_lock_irq(&current->sighand->siglock);
+       siginitsetinv (&current->blocked, sigmask(SIGHUP) | sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT));
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
+-      strcpy(current->comm, "jffs_gcd");
+       D1(printk (KERN_NOTICE "jffs_garbage_collect_thread(): Starting infinite loop.\n"));
+--- linux-2.6.0-test6/fs/jfs/inode.c   2003-09-08 13:58:58.000000000 -0700
++++ 25/fs/jfs/inode.c  2003-10-05 00:34:07.000000000 -0700
+@@ -302,7 +302,7 @@ static int jfs_direct_IO(int rw, struct 
+                       loff_t offset, unsigned long nr_segs)
+ {
+       struct file *file = iocb->ki_filp;
+-      struct inode *inode = file->f_dentry->d_inode->i_mapping->host;
++      struct inode *inode = file->f_mapping->host;
+       return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
+                               offset, nr_segs, jfs_get_blocks, NULL);
+--- linux-2.6.0-test6/fs/jfs/jfs_debug.c       2003-06-14 12:18:29.000000000 -0700
++++ 25/fs/jfs/jfs_debug.c      2003-10-05 00:33:24.000000000 -0700
+@@ -81,7 +81,7 @@ static int loglevel_read(char *page, cha
+       return len;
+ }
+-static int loglevel_write(struct file *file, const char *buffer,
++static int loglevel_write(struct file *file, const char __user *buffer,
+                       unsigned long count, void *data)
+ {
+       char c;
+--- linux-2.6.0-test6/fs/jfs/jfs_imap.c        2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/jfs/jfs_imap.c       2003-10-05 00:33:24.000000000 -0700
+@@ -838,7 +838,7 @@ int diWrite(tid_t tid, struct inode *ip)
+        */
+       if (S_ISDIR(ip->i_mode)
+           && (ip->i_ipmnt->i_mntflag & JFS_DASD_ENABLED))
+-              bcopy(&ip->i_DASD, &dp->di_DASD, sizeof(struct dasd));
++              memcpy(&dp->di_DASD, &ip->i_DASD, sizeof(struct dasd));
+ #endif                                /*  _JFS_FASTDASD */
+       /* release the buffer holding the updated on-disk inode. 
+--- linux-2.6.0-test6/fs/jfs/super.c   2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/jfs/super.c  2003-10-05 00:33:24.000000000 -0700
+@@ -20,6 +20,7 @@
+ #include <linux/fs.h>
+ #include <linux/config.h>
+ #include <linux/module.h>
++#include <linux/parser.h>
+ #include <linux/completion.h>
+ #include <linux/vfs.h>
+ #include <asm/uaccess.h>
+@@ -164,59 +165,82 @@ static void jfs_put_super(struct super_b
+       kfree(sbi);
+ }
++enum {
++      Opt_integrity, Opt_nointegrity, Opt_iocharset, Opt_resize,
++      Opt_ignore, Opt_err,
++};
++
++static match_table_t tokens = {
++      {Opt_integrity, "integrity"},
++      {Opt_nointegrity, "nointegrity"},
++      {Opt_iocharset, "iocharset=%s"},
++      {Opt_resize, "resize=%u"},
++      {Opt_ignore, "noquota"},
++      {Opt_ignore, "quota"},
++      {Opt_ignore, "usrquota"},
++      {Opt_ignore, "grpquota"},
++      {Opt_err, NULL}
++};
++
+ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize,
+                        int *flag)
+ {
+       void *nls_map = NULL;
+-      char *this_char;
+-      char *value;
++      char *p;
+       struct jfs_sb_info *sbi = JFS_SBI(sb);
+       *newLVSize = 0;
+       if (!options)
+               return 1;
+-      while ((this_char = strsep(&options, ",")) != NULL) {
+-              if (!*this_char)
++
++      while ((p = strsep(&options, ",")) != NULL) {
++              substring_t args[MAX_OPT_ARGS];
++              int token;
++              if (!*p)
+                       continue;
+-              if ((value = strchr(this_char, '=')) != NULL)
+-                      *value++ = 0;
+-              if (!strcmp(this_char, "integrity")) {
++
++              token = match_token(p, tokens, args);
++              switch (token) {
++              case Opt_integrity:
+                       *flag &= ~JFS_NOINTEGRITY;
+-              } else  if (!strcmp(this_char, "nointegrity")) {
++                      break;
++              case Opt_nointegrity:
+                       *flag |= JFS_NOINTEGRITY;
+-              } else if (!strcmp(this_char, "iocharset")) {
+-                      if (!value || !*value)
+-                              goto needs_arg;
++                      break;
++              case Opt_ignore:
++                      /* Silently ignore the quota options */
++                      /* Don't do anything ;-) */
++                      break;
++              case Opt_iocharset:
+                       if (nls_map)    /* specified iocharset twice! */
+                               unload_nls(nls_map);
+-                      nls_map = load_nls(value);
++                      nls_map = load_nls(args[0].from);
+                       if (!nls_map) {
+                               printk(KERN_ERR "JFS: charset not found\n");
+                               goto cleanup;
+                       }
+-              } else if (!strcmp(this_char, "resize")) {
+-                      if (!value || !*value) {
++                      break;
++              case Opt_resize:
++              {
++                      char *resize = args[0].from;
++                      if (!resize || !*resize) {
+                               *newLVSize = sb->s_bdev->bd_inode->i_size >>
+                                       sb->s_blocksize_bits;
+                               if (*newLVSize == 0)
+                                       printk(KERN_ERR
+-                                       "JFS: Cannot determine volume size\n");
++                                      "JFS: Cannot determine volume size\n");
+                       } else
+-                              *newLVSize = simple_strtoull(value, &value, 0);
+-
+-                      /* Silently ignore the quota options */
+-              } else if (!strcmp(this_char, "grpquota")
+-                         || !strcmp(this_char, "noquota")
+-                         || !strcmp(this_char, "quota")
+-                         || !strcmp(this_char, "usrquota"))
+-                      /* Don't do anything ;-) */ ;
+-              else {
+-                      printk("jfs: Unrecognized mount option %s\n",
+-                             this_char);
++                              *newLVSize = simple_strtoull(resize, &resize, 0);
++                      break;
++              }
++              default:
++                      printk("jfs: Unrecognized mount option \"%s\" "
++                                      " or missing value\n", p);
+                       goto cleanup;
+               }
+       }
++
+       if (nls_map) {
+               /* Discard old (if remount) */
+               if (sbi->nls_tab)
+@@ -224,8 +248,7 @@ static int parse_options(char *options, 
+               sbi->nls_tab = nls_map;
+       }
+       return 1;
+-needs_arg:
+-      printk(KERN_ERR "JFS: %s needs an argument\n", this_char);
++
+ cleanup:
+       if (nls_map)
+               unload_nls(nls_map);
+--- linux-2.6.0-test6/fs/jfs/symlink.c 2003-06-14 12:18:51.000000000 -0700
++++ 25/fs/jfs/symlink.c        2003-10-05 00:33:24.000000000 -0700
+@@ -26,7 +26,7 @@ static int jfs_follow_link(struct dentry
+       return vfs_follow_link(nd, s);
+ }
+-static int jfs_readlink(struct dentry *dentry, char *buffer, int buflen)
++static int jfs_readlink(struct dentry *dentry, char __user *buffer, int buflen)
+ {
+       char *s = JFS_IP(dentry->d_inode)->i_inline;
+       return vfs_readlink(dentry, buffer, buflen, s);
+--- linux-2.6.0-test6/fs/Kconfig       2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/Kconfig      2003-10-05 00:36:47.000000000 -0700
+@@ -874,6 +874,7 @@ config TMPFS
+ config HUGETLBFS
+       bool "HugeTLB file system support"
++      depends X86 || IA64 || PPC64 || SPARC64 || X86_64 || BROKEN
+ config HUGETLB_PAGE
+       def_bool HUGETLBFS
+@@ -1254,6 +1255,8 @@ menu "Network File Systems"
+ config NFS_FS
+       tristate "NFS file system support"
+       depends on INET
++      select LOCKD
++      select SUNRPC
+       help
+         If you are connected to some other (usually local) Unix computer
+         (using SLIP, PLIP, PPP or Ethernet) and want to mount files residing
+@@ -1306,9 +1309,36 @@ config NFS_V4
+         If unsure, say N.
++config NFS_DIRECTIO
++      bool
++      depends on NFS_FS
++      default y
++      help
++        This option enables applications to perform uncached I/O on files
++        in NFS file systems using the O_DIRECT open() flag.  When O_DIRECT
++        is set for a file, its data is not cached in the system's page
++        cache.  Data is moved to and from user-level application buffers
++        directly.  Unlike local disk-based file systems, NFS O_DIRECT has
++        no alignment restrictions.
++
++        Unless your program is designed to use O_DIRECT properly, you are
++        much better off allowing the NFS client to manage data caching for
++        you.  Misusing O_DIRECT can cause poor server performance or network
++        storms.  This kernel build option defaults OFF to avoid exposing
++        system administrators unwittingly to a potentially hazardous
++        feature.
++
++        For more details on NFS O_DIRECT, see fs/nfs/direct.c.
++
++        If unsure, say N.  This reduces the size of the NFS client, and
++        causes open() to return EINVAL if a file residing in NFS is
++        opened with the O_DIRECT flag.
++
+ config NFSD
+       tristate "NFS server support"
+       depends on INET
++      select LOCKD
++      select SUNRPC
+       help
+         If you want your Linux box to act as an NFS *server*, so that other
+         computers on your local network which support NFS can access certain
+@@ -1371,8 +1401,6 @@ config ROOT_NFS
+ config LOCKD
+       tristate
+-      default m if NFS_FS!=y && NFSD!=y && (NFS_FS=m || NFSD=m)
+-      default y if NFS_FS=y || NFSD=y
+ config LOCKD_V4
+       bool
+@@ -1385,8 +1413,6 @@ config EXPORTFS
+ config SUNRPC
+       tristate
+-      default m if NFS_FS!=y && NFSD!=y && (NFS_FS=m || NFSD=m)
+-      default y if NFS_FS=y || NFSD=y
+ config SUNRPC_GSS
+       tristate "Provide RPCSEC_GSS authentication (EXPERIMENTAL)"
+@@ -1565,6 +1591,7 @@ config AFS_FS
+ # for fs/nls/Config.in
+       tristate "Andrew File System support (AFS) (Experimental)"
+       depends on INET && EXPERIMENTAL
++      select RXRPC
+       help
+         If you say Y here, you will get an experimental Andrew File System
+         driver. It currently only supports unsecured read-only AFS access.
+@@ -1575,8 +1602,6 @@ config AFS_FS
+ config RXRPC
+       tristate
+-      default m if AFS_FS=m
+-      default y if AFS_FS=y
+ endmenu
+--- linux-2.6.0-test6/fs/libfs.c       2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/libfs.c      2003-10-05 00:33:24.000000000 -0700
+@@ -429,3 +429,26 @@ void simple_release_fs(struct vfsmount *
+       spin_unlock(&pin_fs_lock);
+       mntput(mnt);
+ }
++
++EXPORT_SYMBOL(dcache_dir_close);
++EXPORT_SYMBOL(dcache_dir_lseek);
++EXPORT_SYMBOL(dcache_dir_open);
++EXPORT_SYMBOL(dcache_readdir);
++EXPORT_SYMBOL(generic_read_dir);
++EXPORT_SYMBOL(simple_commit_write);
++EXPORT_SYMBOL(simple_dir_inode_operations);
++EXPORT_SYMBOL(simple_dir_operations);
++EXPORT_SYMBOL(simple_empty);
++EXPORT_SYMBOL(simple_fill_super);
++EXPORT_SYMBOL(simple_getattr);
++EXPORT_SYMBOL(simple_link);
++EXPORT_SYMBOL(simple_lookup);
++EXPORT_SYMBOL(simple_pin_fs);
++EXPORT_SYMBOL(simple_prepare_write);
++EXPORT_SYMBOL(simple_readpage);
++EXPORT_SYMBOL(simple_release_fs);
++EXPORT_SYMBOL(simple_rename);
++EXPORT_SYMBOL(simple_rmdir);
++EXPORT_SYMBOL(simple_statfs);
++EXPORT_SYMBOL(simple_sync_file);
++EXPORT_SYMBOL(simple_unlink);
+--- linux-2.6.0-test6/fs/locks.c       2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/locks.c      2003-10-05 00:36:10.000000000 -0700
+@@ -928,10 +928,10 @@ int locks_mandatory_locked(struct inode 
+  * locks_mandatory_area - Check for a conflicting lock
+  * @read_write: %FLOCK_VERIFY_WRITE for exclusive access, %FLOCK_VERIFY_READ
+  *            for shared
+- * @inode: the file to check
+- * @file: how the file was opened (if it was)
+- * @offset: start of area to check
+- * @count: length of area to check
++ * @inode:      the file to check
++ * @filp:       how the file was opened (if it was)
++ * @offset:     start of area to check
++ * @count:      length of area to check
+  *
+  * Searches the inode's list of locks to find any POSIX locks which conflict.
+  * This function is called from locks_verify_area() and
+@@ -1119,6 +1119,7 @@ out:
+ /**
+  *    lease_get_mtime
+  *    @inode: the inode
++ *      @time:  pointer to a timespec which will contain the last modified time
+  *
+  * This is to force NFS clients to flush their caches for files with
+  * exclusive leases.  The justification is that if someone has an
+@@ -1434,7 +1435,7 @@ int fcntl_setlk(struct file *filp, unsig
+        */
+       if (IS_MANDLOCK(inode) &&
+           (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) {
+-              struct address_space *mapping = inode->i_mapping;
++              struct address_space *mapping = filp->f_mapping;
+               if (!list_empty(&mapping->i_mmap_shared)) {
+                       error = -EAGAIN;
+@@ -1572,7 +1573,7 @@ int fcntl_setlk64(struct file *filp, uns
+        */
+       if (IS_MANDLOCK(inode) &&
+           (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) {
+-              struct address_space *mapping = inode->i_mapping;
++              struct address_space *mapping = filp->f_mapping;
+               if (!list_empty(&mapping->i_mmap_shared)) {
+                       error = -EAGAIN;
+@@ -1726,6 +1727,7 @@ posix_block_lock(struct file_lock *block
+ /**
+  *    posix_unblock_lock - stop waiting for a file lock
++ *      @filp:   how the file was opened
+  *    @waiter: the lock which was waiting
+  *
+  *    lockd needs to block waiting for locks.
+--- linux-2.6.0-test6/fs/namei.c       2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/namei.c      2003-10-05 00:33:24.000000000 -0700
+@@ -15,6 +15,7 @@
+  */
+ #include <linux/init.h>
++#include <linux/module.h>
+ #include <linux/slab.h>
+ #include <linux/fs.h>
+ #include <linux/namei.h>
+@@ -218,7 +219,7 @@ int permission(struct inode * inode,int 
+       if (retval)
+               return retval;
+-      return security_inode_permission(inode, mask);
++      return security_inode_permission(inode, mask, nd);
+ }
+ /*
+@@ -302,7 +303,8 @@ static struct dentry * cached_lookup(str
+  * short-cut DAC fails, then call permission() to do more
+  * complete permission check.
+  */
+-static inline int exec_permission_lite(struct inode *inode)
++static inline int exec_permission_lite(struct inode *inode,
++                                     struct nameidata *nd)
+ {
+       umode_t mode = inode->i_mode;
+@@ -325,7 +327,7 @@ static inline int exec_permission_lite(s
+       return -EACCES;
+ ok:
+-      return security_inode_permission(inode, MAY_EXEC);
++      return security_inode_permission(inode, MAY_EXEC, nd);
+ }
+ /*
+@@ -584,7 +586,7 @@ int link_path_walk(const char * name, st
+               struct qstr this;
+               unsigned int c;
+-              err = exec_permission_lite(inode);
++              err = exec_permission_lite(inode, nd);
+               if (err == -EAGAIN) { 
+                       err = permission(inode, MAY_EXEC, nd);
+               }
+@@ -2275,3 +2277,33 @@ struct inode_operations page_symlink_ino
+       .readlink       = page_readlink,
+       .follow_link    = page_follow_link,
+ };
++
++EXPORT_SYMBOL(__user_walk);
++EXPORT_SYMBOL(follow_down);
++EXPORT_SYMBOL(follow_up);
++EXPORT_SYMBOL(get_write_access); /* binfmt_aout */
++EXPORT_SYMBOL(getname);
++EXPORT_SYMBOL(lock_rename);
++EXPORT_SYMBOL(lookup_create);
++EXPORT_SYMBOL(lookup_hash);
++EXPORT_SYMBOL(lookup_one_len);
++EXPORT_SYMBOL(page_follow_link);
++EXPORT_SYMBOL(page_readlink);
++EXPORT_SYMBOL(page_symlink);
++EXPORT_SYMBOL(page_symlink_inode_operations);
++EXPORT_SYMBOL(path_lookup);
++EXPORT_SYMBOL(path_release);
++EXPORT_SYMBOL(path_walk);
++EXPORT_SYMBOL(permission);
++EXPORT_SYMBOL(unlock_rename);
++EXPORT_SYMBOL(vfs_create);
++EXPORT_SYMBOL(vfs_follow_link);
++EXPORT_SYMBOL(vfs_link);
++EXPORT_SYMBOL(vfs_mkdir);
++EXPORT_SYMBOL(vfs_mknod);
++EXPORT_SYMBOL(vfs_permission);
++EXPORT_SYMBOL(vfs_readlink);
++EXPORT_SYMBOL(vfs_rename);
++EXPORT_SYMBOL(vfs_rmdir);
++EXPORT_SYMBOL(vfs_symlink);
++EXPORT_SYMBOL(vfs_unlink);
+--- linux-2.6.0-test6/fs/nfs/direct.c  2003-06-26 22:07:25.000000000 -0700
++++ 25/fs/nfs/direct.c 2003-10-05 00:36:46.000000000 -0700
+@@ -1,7 +1,7 @@
+ /*
+  * linux/fs/nfs/direct.c
+  *
+- * Copyright (C) 2001 by Chuck Lever <cel@netapp.com>
++ * Copyright (C) 2003 by Chuck Lever <cel@netapp.com>
+  *
+  * High-performance uncached I/O for the Linux NFS client
+  *
+@@ -26,19 +26,23 @@
+  * also supports uncaching whole NFS partitions with "-o forcedirectio,"
+  * an undocumented mount option.
+  *
+- * Designed by Jeff Kimmel, Chuck Lever, and Trond Myklebust.
++ * Designed by Jeff Kimmel, Chuck Lever, and Trond Myklebust, with
++ * help from Andrew Morton.
+  *
+  * 18 Dec 2001        Initial implementation for 2.4  --cel
+  * 08 Jul 2002        Version for 2.4.19, with bug fixes --trondmy
+- * 24 Sep 2002        Rewrite to use asynchronous RPCs, port to 2.5  --cel
++ * 08 Jun 2003        Port to 2.5 APIs  --cel
+  *
+  */
+ #include <linux/config.h>
++#include <linux/errno.h>
+ #include <linux/sched.h>
+ #include <linux/kernel.h>
++#include <linux/smp_lock.h>
+ #include <linux/file.h>
+-#include <linux/errno.h>
++#include <linux/pagemap.h>
++
+ #include <linux/nfs_fs.h>
+ #include <linux/nfs_page.h>
+ #include <linux/sunrpc/clnt.h>
+@@ -46,35 +50,41 @@
+ #include <asm/system.h>
+ #include <asm/uaccess.h>
+-#define NFSDBG_FACILITY               (NFSDBG_PAGECACHE | NFSDBG_VFS)
++#define NFSDBG_FACILITY               NFSDBG_VFS
+ #define VERF_SIZE             (2 * sizeof(__u32))
++#define MAX_DIRECTIO_SIZE     (4096UL << PAGE_SHIFT)
+ /**
+- * nfs_get_user_pages - find and set up page representing user buffer
+- * addr: user-space address of target buffer
+- * size: total size in bytes of target buffer
+- * @pages: returned array of page struct pointers underlying target buffer
+- * write: whether or not buffer is target of a write operation
++ * nfs_get_user_pages - find and set up pages underlying user's buffer
++ * rw: direction (read or write)
++ * user_addr: starting address of this segment of user's buffer
++ * count: size of this segment
++ * @pages: returned array of page struct pointers underlying user's buffer
+  */
+ static inline int
+-nfs_get_user_pages(unsigned long addr, size_t size,
+-              struct page ***pages, int rw)
++nfs_get_user_pages(int rw, unsigned long user_addr, size_t size,
++              struct page ***pages)
+ {
+       int result = -ENOMEM;
+-      unsigned page_count = (unsigned) size >> PAGE_SHIFT;
+-      unsigned array_size = (page_count * sizeof(struct page *)) + 2U;
++      unsigned long page_count;
++      size_t array_size;
++
++      /* set an arbitrary limit to prevent arithmetic overflow */
++      if (size > MAX_DIRECTIO_SIZE)
++              return -EFBIG;
+-      *pages = (struct page **) kmalloc(array_size, GFP_KERNEL);
++      page_count = (user_addr + size + PAGE_SIZE - 1) >> PAGE_SHIFT;
++      page_count -= user_addr >> PAGE_SHIFT;
++
++      array_size = (page_count * sizeof(struct page *));
++      *pages = kmalloc(array_size, GFP_KERNEL);
+       if (*pages) {
+               down_read(&current->mm->mmap_sem);
+-              result = get_user_pages(current, current->mm, addr,
+-                                      page_count, (rw == WRITE), 0,
++              result = get_user_pages(current, current->mm, user_addr,
++                                      page_count, (rw == READ), 0,
+                                       *pages, NULL);
+               up_read(&current->mm->mmap_sem);
+-              if (result < 0)
+-                      printk(KERN_ERR "%s: get_user_pages result %d\n",
+-                                      __FUNCTION__, result);
+       }
+       return result;
+ }
+@@ -84,176 +94,349 @@ nfs_get_user_pages(unsigned long addr, s
+  * @pages: array of page struct pointers underlying target buffer
+  */
+ static inline void
+-nfs_free_user_pages(struct page **pages, unsigned count)
++nfs_free_user_pages(struct page **pages)
+ {
+-      unsigned page = 0;
++      kfree(pages);
++}
+-      while (count--)
+-              page_cache_release(pages[page++]);
++/**
++ * nfs_direct_read_seg - Read in one iov segment.  Generate separate
++ *                        read RPCs for each "rsize" bytes.
++ * @inode: target inode
++ * @cred: user's credential
++ * user_addr: starting address of this segment of user's buffer
++ * count: size of this segment
++ * file_offset: offset in file to begin the operation
++ * @pages: array of addresses of page structs defining user's buffer
++ * nr_pages: size of pages array
++ */
++static int
++nfs_direct_read_seg(struct inode *inode, struct rpc_cred *cred,
++              unsigned long user_addr, size_t count, loff_t file_offset,
++              struct page **pages, int nr_pages)
++{
++      const unsigned int rsize = NFS_SERVER(inode)->rsize;
++      int tot_bytes = 0;
++      int curpage = 0;
++      struct nfs_read_data    rdata = {
++              .flags          = 0,
++              .cred           = cred,
++              .inode          = inode,
++              .args           = {
++                      .fh             = NFS_FH(inode),
++              },
++              .res            = {
++                      .fattr          = &rdata.fattr,
++              },
++      };
++
++        do {
++              int request, result;
++
++                request = count;
++                if (count > rsize)
++                        request = rsize;
++              rdata.args.count = request,
++              rdata.args.pgbase = user_addr & ~PAGE_MASK;
++              rdata.args.offset = file_offset;
++              rdata.args.pages = &pages[curpage];
++
++              dprintk("NFS: direct read: c=%u o=%Ld ua=%lu, pb=%u, cp=%u\n",
++                      rdata.args.count, (long long) rdata.args.offset,
++                      user_addr, rdata.args.pgbase, curpage);
++
++              lock_kernel();
++              result = NFS_PROTO(inode)->read(&rdata);
++              unlock_kernel();
++
++              if (result < 0) {
++                      if (result == -EISDIR)
++                              result = -EINVAL;
++                      return result;
++              }
+-      kfree(pages);
++                tot_bytes += result;
++                count -= result;
++                file_offset += result;
++              user_addr += result;
++
++              if (rdata.res.eof)
++                      break;
++
++              curpage += (rdata.args.pgbase + result) >> PAGE_SHIFT;
++      } while (count);
++
++      /* XXX: should we zero the rest of the user's buffer if we
++       *      hit eof? */
++
++      return tot_bytes;
+ }
+ /**
+- * nfs_iov2pagelist - convert an array of iovecs to a list of page requests
+- * @inode: inode of target file
+- * @cred: credentials of user who requested I/O
++ * nfs_direct_read - For each iov segment, map the user's buffer
++ *                   then generate read RPCs.
++ * @inode: target inode
++ * @cred: user's credential
+  * @iov: array of vectors that define I/O buffer
+- * offset: where in file to begin the read
++ * file_offset: offset in file to begin the operation
+  * nr_segs: size of iovec array
+- * @requests: append new page requests to this list head
++ *
++ * generic_file_direct_IO has already pushed out any non-direct
++ * writes so that this read will see them when we read from the
++ * server.
+  */
+ static int
+-nfs_iov2pagelist(int rw, const struct inode *inode,
+-              const struct rpc_cred *cred,
+-              const struct iovec *iov, loff_t offset,
+-              unsigned long nr_segs, struct list_head *requests)
++nfs_direct_read(struct inode *inode, struct rpc_cred *cred,
++              const struct iovec *iov, loff_t file_offset,
++              unsigned long nr_segs)
+ {
+-      unsigned seg;
+       int tot_bytes = 0;
+-      struct page **pages;
++      unsigned long seg = 0;
+-      /* for each iovec in the array... */
+-      for (seg = 0; seg < nr_segs; seg++) {
+-              const unsigned long user_addr =
+-                                      (unsigned long) iov[seg].iov_base;
+-              size_t bytes = iov[seg].iov_len;
+-              unsigned int pg_offset = (user_addr & ~PAGE_MASK);
+-              int page_count, page = 0;
+-
+-              page_count = nfs_get_user_pages(user_addr, bytes, &pages, rw);
+-              if (page_count < 0) {
+-                      nfs_release_list(requests);
+-                      return page_count;
++      while ((seg < nr_segs) && (tot_bytes >= 0)) {
++              int result, page_count;
++              struct page **pages;
++              const struct iovec *vec = &iov[seg++];
++              unsigned long user_addr = (unsigned long) vec->iov_base;
++              size_t size = vec->iov_len;
++
++                page_count = nfs_get_user_pages(READ, user_addr, size, &pages);
++                if (page_count < 0) {
++                        nfs_free_user_pages(pages);
++                        return page_count;
++                }
++
++              result = nfs_direct_read_seg(inode, cred, user_addr, size,
++                              file_offset, pages, page_count);
++              if (result < 0)
++                      tot_bytes = result;
++              else {
++                      tot_bytes += result;
++                      file_offset += result;
+               }
+-              /* ...build as many page requests as required */
+-              while (bytes > 0) {
+-                      struct nfs_page *new;
+-                      const unsigned int pg_bytes = (bytes > PAGE_SIZE) ?
+-                                                      PAGE_SIZE : bytes;
+-
+-                      new = nfs_create_request((struct rpc_cred *) cred,
+-                                               (struct inode *) inode,
+-                                               pages[page],
+-                                               pg_offset, pg_bytes);
+-                      if (IS_ERR(new)) {
+-                              nfs_free_user_pages(pages, page_count);
+-                              nfs_release_list(requests);
+-                              return PTR_ERR(new);
+-                      }
+-                      new->wb_index = offset;
+-                      nfs_list_add_request(new, requests);
+-
+-                      /* after the first page */
+-                      pg_offset = 0;
+-                      offset += PAGE_SIZE;
+-                      tot_bytes += pg_bytes;
+-                      bytes -= pg_bytes;
+-                      page++;
++              nfs_free_user_pages(pages);
++      }
++
++      return tot_bytes;
++}
++
++/**
++ * nfs_direct_write_seg - Write out one iov segment.  Generate separate
++ *                        write RPCs for each "wsize" bytes, then commit.
++ * @inode: target inode
++ * @cred: user's credential
++ * user_addr: starting address of this segment of user's buffer
++ * count: size of this segment
++ * file_offset: offset in file to begin the operation
++ * @pages: array of addresses of page structs defining user's buffer
++ * nr_pages: size of pages array
++ */
++static int
++nfs_direct_write_seg(struct inode *inode, struct rpc_cred *cred,
++              unsigned long user_addr, size_t count, loff_t file_offset,
++              struct page **pages, int nr_pages)
++{
++      const unsigned int wsize = NFS_SERVER(inode)->wsize;
++      loff_t save_offset = file_offset;
++      size_t save_count = count;
++      int need_commit = 0;
++      int tot_bytes = 0;
++      int curpage = 0;
++      struct nfs_writeverf first_verf;
++      struct nfs_write_data   wdata = {
++              .cred           = cred,
++              .inode          = inode,
++              .args           = {
++                      .fh             = NFS_FH(inode),
++              },
++              .res            = {
++                      .fattr          = &wdata.fattr,
++                      .verf           = &wdata.verf,
++              },
++      };
++
++      wdata.args.stable = NFS_UNSTABLE;
++      if (IS_SYNC(inode) || NFS_PROTO(inode)->version == 2 || count <= wsize)
++              wdata.args.stable = NFS_FILE_SYNC;
++
++retry:
++        do {
++              int request, result;
++
++                request = count;
++                if (count > wsize)
++                        request = wsize;
++              wdata.args.count = request,
++              wdata.args.pgbase = user_addr & ~PAGE_MASK;
++              wdata.args.offset = file_offset;
++              wdata.args.pages = &pages[curpage];
++
++              dprintk("NFS: direct write: c=%u o=%Ld ua=%lu, pb=%u, cp=%u\n",
++                      wdata.args.count, (long long) wdata.args.offset,
++                      user_addr, wdata.args.pgbase, curpage);
++
++              lock_kernel();
++              result = NFS_PROTO(inode)->write(&wdata);
++              unlock_kernel();
++
++              if (result < 0)
++                      return result;
++
++              if (!tot_bytes)
++                      memcpy(&first_verf.verifier, &wdata.verf.verifier,
++                                                              VERF_SIZE);
++              if (wdata.verf.committed != NFS_FILE_SYNC) {
++                      need_commit = 1;
++                      if (memcmp(&first_verf.verifier,
++                                      &wdata.verf.verifier, VERF_SIZE))
++                              goto sync_retry;
+               }
+-              /* don't release pages here -- I/O completion will do that */
+-              nfs_free_user_pages(pages, 0);
++                tot_bytes += result;
++                count -= result;
++                file_offset += result;
++              user_addr += result;
++
++              curpage += (wdata.args.pgbase + result) >> PAGE_SHIFT;
++      } while (count);
++
++      /*
++       * Commit data written so far, even in the event of an error
++       */
++      if (need_commit) {
++              int result;
++
++              wdata.args.count = tot_bytes;
++              wdata.args.offset = save_offset;
++
++              lock_kernel();
++              result = NFS_PROTO(inode)->commit(&wdata);
++              unlock_kernel();
++
++              if (result < 0)
++                      goto sync_retry;
++              if (memcmp(&first_verf.verifier, &wdata.verf.verifier,
++                                                              VERF_SIZE))
++                      goto sync_retry;
+       }
+       return tot_bytes;
++
++sync_retry:
++      wdata.args.stable = NFS_FILE_SYNC;
++      file_offset = save_offset;
++      count = save_count;
++      goto retry;
+ }
+ /**
+- * do_nfs_direct_IO - Read or write data without caching
+- * @inode: inode of target file
+- * @cred: credentials of user who requested I/O
++ * nfs_direct_write - For each iov segment, map the user's buffer
++ *                    then generate write and commit RPCs.
++ * @inode: target inode
++ * @cred: user's credential
+  * @iov: array of vectors that define I/O buffer
+- * offset: where in file to begin the read
++ * file_offset: offset in file to begin the operation
+  * nr_segs: size of iovec array
+  *
+- * Break the passed-in iovec into a series of page-sized or smaller
+- * requests, where each page is mapped for direct user-land I/O.
+- *
+- * For each of these pages, create an NFS page request and
+- * append it to an automatic list of page requests.
+- *
+- * When all page requests have been queued, start the I/O on the
+- * whole list.  The underlying routines coalesce the pages on the
+- * list into a bunch of asynchronous "r/wsize" network requests.
+- *
+- * I/O completion automatically unmaps and releases the pages.
++ * Upon return, generic_file_direct_IO invalidates any cached pages
++ * that non-direct readers might access, so they will pick up these
++ * writes immediately.
+  */
+ static int
+-do_nfs_direct_IO(int rw, const struct inode *inode,
+-              const struct rpc_cred *cred, const struct iovec *iov,
+-              loff_t offset, unsigned long nr_segs)
++nfs_direct_write(struct inode *inode, struct rpc_cred *cred,
++              const struct iovec *iov, loff_t file_offset,
++              unsigned long nr_segs)
+ {
+-      LIST_HEAD(requests);
+-      int result, tot_bytes;
++      int tot_bytes = 0;
++      unsigned long seg = 0;
+-      result = nfs_iov2pagelist(rw, inode, cred, iov, offset, nr_segs,
+-                                                              &requests);
+-      if (result < 0)
+-              return result;
+-      tot_bytes = result;
++      while ((seg < nr_segs) && (tot_bytes >= 0)) {
++              int result, page_count;
++              struct page **pages;
++              const struct iovec *vec = &iov[seg++];
++              unsigned long user_addr = (unsigned long) vec->iov_base;
++              size_t size = vec->iov_len;
++
++                page_count = nfs_get_user_pages(WRITE, user_addr, size, &pages);
++                if (page_count < 0) {
++                        nfs_free_user_pages(pages);
++                        return page_count;
++                }
+-      switch (rw) {
+-      case READ:
+-              if (IS_SYNC(inode) || (NFS_SERVER(inode)->rsize < PAGE_SIZE)) {
+-                      result = nfs_direct_read_sync(inode, cred, iov, offset, nr_segs);
+-                      break;
++              result = nfs_direct_write_seg(inode, cred, user_addr, size,
++                              file_offset, pages, page_count);
++              if (result < 0)
++                      tot_bytes = result;
++              else {
++                      tot_bytes += result;
++                      file_offset += result;
+               }
+-              result = nfs_pagein_list(&requests, NFS_SERVER(inode)->rpages);
+-              nfs_wait_for_reads(&requests);
+-              break;
+-      case WRITE:
+-              if (IS_SYNC(inode) || (NFS_SERVER(inode)->wsize < PAGE_SIZE))
+-                      result = nfs_direct_write_sync(inode, cred, iov, offset, nr_segs);
+-              else
+-                      result = nfs_flush_list(&requests,
+-                                      NFS_SERVER(inode)->wpages, FLUSH_WAIT);
+-              /* invalidate cache so non-direct readers pick up changes */
+-              invalidate_inode_pages((struct inode *) inode);
+-              break;
+-      default:
+-              result = -EINVAL;
+-              break;
++              nfs_free_user_pages(pages);
+       }
+-      if (result < 0)
+-              return result;
+       return tot_bytes;
+ }
+ /**
+  * nfs_direct_IO - NFS address space operation for direct I/O
+  * rw: direction (read or write)
+- * @file: file struct of target file
++ * @iocb: target I/O control block
+  * @iov: array of vectors that define I/O buffer
+- * offset: offset in file to begin the operation
++ * file_offset: offset in file to begin the operation
+  * nr_segs: size of iovec array
+  *
++ * Usually a file system implements direct I/O by calling out to
++ * blockdev_direct_IO.  The NFS client doesn't have a backing block
++ * device, so we do everything by hand instead.
++ *
+  * The inode's i_sem is no longer held by the VFS layer before it calls
+  * this function to do a write.
+  */
+ int
+ nfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
+-              loff_t offset, unsigned long nr_segs)
++              loff_t file_offset, unsigned long nr_segs)
+ {
+-      /* None of this works yet, so prevent it from compiling. */
+-#if 0
+-      int result;
++      int result = -EINVAL;
++      struct file *file = iocb->ki_filp;
+       struct dentry *dentry = file->f_dentry;
+-      const struct inode *inode = dentry->d_inode->i_mapping->host;
+-      const struct rpc_cred *cred = nfs_file_cred(file);
+-#endif
+-
+-      dfprintk(VFS, "NFS: direct_IO(%s) (%s/%s) off/no(%Lu/%lu)\n",
+-                              ((rw == READ) ? "READ" : "WRITE"),
+-                              dentry->d_parent->d_name.name,
+-                              dentry->d_name.name, offset, nr_segs);
++      struct inode *inode = dentry->d_inode;
++      struct rpc_cred *cred;
++
++      /*
++       * No support for async yet
++       */
++      if (!is_sync_kiocb(iocb))
++              goto out;
++
++      cred = get_rpccred(nfs_file_cred(file));
++      if (!cred)
++              cred = get_rpccred(NFS_I(inode)->mm_cred);
++
++      switch (rw) {
++      case READ:
++              dprintk("NFS: direct_IO(read) (%s) off/no(%Lu/%lu)\n",
++                              dentry->d_name.name, file_offset, nr_segs);
++
++              result = nfs_direct_read(inode, cred, iov,
++                                              file_offset, nr_segs);
++              break;
++      case WRITE:
++              dprintk("NFS: direct_IO(write) (%s) off/no(%Lu/%lu)\n",
++                              dentry->d_name.name, file_offset, nr_segs);
+-      result = do_nfs_direct_IO(rw, inode, cred, iov, offset, nr_segs);
++              result = nfs_direct_write(inode, cred, iov,
++                                              file_offset, nr_segs);
++              break;
++      default:
++              break;
++      }
+-      dfprintk(VFS, "NFS: direct_IO result = %d\n", result);
++      if (cred)
++              put_rpccred(cred);
++out:
++      dprintk("NFS: direct_IO result=%d\n", result);
+       return result;
+ }
+--- linux-2.6.0-test6/fs/nfsd/nfsctl.c 2003-07-02 14:53:16.000000000 -0700
++++ 25/fs/nfsd/nfsctl.c        2003-10-05 00:33:24.000000000 -0700
+@@ -429,6 +429,7 @@ static struct file_system_type nfsd_fs_t
+ static int __init init_nfsd(void)
+ {
++      int retval;
+       printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
+       nfsd_stat_init();       /* Statistics */
+@@ -441,8 +442,16 @@ static int __init init_nfsd(void)
+               if (entry)
+                       entry->proc_fops =  &exports_operations;
+       }
+-      register_filesystem(&nfsd_fs_type);
+-      return 0;
++      retval = register_filesystem(&nfsd_fs_type);
++      if (retval) {
++              nfsd_export_shutdown();
++              nfsd_cache_shutdown();
++              remove_proc_entry("fs/nfs/exports", NULL);
++              remove_proc_entry("fs/nfs", NULL);
++              nfsd_stat_shutdown();
++              nfsd_lockd_shutdown();
++      }
++      return retval;
+ }
+ static void __exit exit_nfsd(void)
+--- linux-2.6.0-test6/fs/nfs/file.c    2003-07-10 18:50:32.000000000 -0700
++++ 25/fs/nfs/file.c   2003-10-05 00:34:08.000000000 -0700
+@@ -262,7 +262,7 @@ out_swapfile:
+ int
+ nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
+ {
+-      struct inode * inode = filp->f_dentry->d_inode;
++      struct inode * inode = filp->f_mapping->host;
+       int     status = 0;
+       int     status2;
+@@ -305,13 +305,13 @@ nfs_lock(struct file *filp, int cmd, str
+        * Flush all pending writes before doing anything
+        * with locks..
+        */
+-      status = filemap_fdatawrite(inode->i_mapping);
++      status = filemap_fdatawrite(filp->f_mapping);
+       down(&inode->i_sem);
+       status2 = nfs_wb_all(inode);
+       if (!status)
+               status = status2;
+       up(&inode->i_sem);
+-      status2 = filemap_fdatawait(inode->i_mapping);
++      status2 = filemap_fdatawait(filp->f_mapping);
+       if (!status)
+               status = status2;
+       if (status < 0)
+@@ -331,11 +331,11 @@ nfs_lock(struct file *filp, int cmd, str
+        */
+  out_ok:
+       if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
+-              filemap_fdatawrite(inode->i_mapping);
++              filemap_fdatawrite(filp->f_mapping);
+               down(&inode->i_sem);
+               nfs_wb_all(inode);      /* we may have slept */
+               up(&inode->i_sem);
+-              filemap_fdatawait(inode->i_mapping);
++              filemap_fdatawait(filp->f_mapping);
+               nfs_zap_caches(inode);
+       }
+       return status;
+--- linux-2.6.0-test6/fs/nfs/nfs3proc.c        2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/nfs/nfs3proc.c       2003-10-05 00:36:45.000000000 -0700
+@@ -225,81 +225,74 @@ nfs3_proc_readlink(struct inode *inode, 
+ }
+ static int
+-nfs3_proc_read(struct inode *inode, struct rpc_cred *cred,
+-             struct nfs_fattr *fattr, int flags,
+-             unsigned int base, unsigned int count, struct page *page,
+-             int *eofp)
+-{
+-      u64                     offset = page_offset(page) + base;
+-      struct nfs_readargs     arg = {
+-              .fh             = NFS_FH(inode),
+-              .offset         = offset,
+-              .count          = count,
+-              .pgbase         = base,
+-              .pages          = &page
+-      };
+-      struct nfs_readres      res = {
+-              .fattr          = fattr,
+-              .count          = count,
+-      };
++nfs3_proc_read(struct nfs_read_data *rdata)
++{
++      int                     flags = rdata->flags;
++      struct inode *          inode = rdata->inode;
++      struct nfs_fattr *      fattr = rdata->res.fattr;
+       struct rpc_message      msg = {
+               .rpc_proc       = &nfs3_procedures[NFS3PROC_READ],
+-              .rpc_argp       = &arg,
+-              .rpc_resp       = &res,
+-              .rpc_cred       = cred
++              .rpc_argp       = &rdata->args,
++              .rpc_resp       = &rdata->res,
++              .rpc_cred       = rdata->cred,
+       };
+       int                     status;
+-      dprintk("NFS call  read %d @ %Ld\n", count, (long long)offset);
++      dprintk("NFS call  read %d @ %Ld\n", rdata->args.count,
++                      (long long) rdata->args.offset);
+       fattr->valid = 0;
+       status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags);
+       if (status >= 0)
+               nfs_refresh_inode(inode, fattr);
+       dprintk("NFS reply read: %d\n", status);
+-      *eofp = res.eof;
+       return status;
+ }
+ static int
+-nfs3_proc_write(struct inode *inode, struct rpc_cred *cred,
+-              struct nfs_fattr *fattr, int flags,
+-              unsigned int base, unsigned int count,
+-              struct page *page, struct nfs_writeverf *verf)
++nfs3_proc_write(struct nfs_write_data *wdata)
+ {
+-      u64                     offset = page_offset(page) + base;
+-      struct nfs_writeargs    arg = {
+-              .fh             = NFS_FH(inode),
+-              .offset         = offset,
+-              .count          = count,
+-              .stable         = NFS_FILE_SYNC,
+-              .pgbase         = base,
+-              .pages          = &page
+-      };
+-      struct nfs_writeres     res = {
+-              .fattr          = fattr,
+-              .verf           = verf,
+-      };
++      int                     rpcflags = wdata->flags;
++      struct inode *          inode = wdata->inode;
++      struct nfs_fattr *      fattr = wdata->res.fattr;
+       struct rpc_message      msg = {
+               .rpc_proc       = &nfs3_procedures[NFS3PROC_WRITE],
+-              .rpc_argp       = &arg,
+-              .rpc_resp       = &res,
+-              .rpc_cred       = cred
++              .rpc_argp       = &wdata->args,
++              .rpc_resp       = &wdata->res,
++              .rpc_cred       = wdata->cred,
+       };
+-      int                     status, rpcflags = 0;
++      int                     status;
+-      dprintk("NFS call  write %d @ %Ld\n", count, (long long)offset);
++      dprintk("NFS call  write %d @ %Ld\n", wdata->args.count,
++                      (long long) wdata->args.offset);
+       fattr->valid = 0;
+-      if (flags & NFS_RW_SWAP)
+-              rpcflags |= NFS_RPC_SWAPFLAGS;
+-      arg.stable = (flags & NFS_RW_SYNC) ? NFS_FILE_SYNC : NFS_UNSTABLE;
+-
+       status = rpc_call_sync(NFS_CLIENT(inode), &msg, rpcflags);
+-
+       if (status >= 0)
+               nfs3_write_refresh_inode(inode, fattr);
++      dprintk("NFS reply write: %d\n", status);
++      return status < 0? status : wdata->res.count;
++}
+-      dprintk("NFS reply read: %d\n", status);
+-      return status < 0? status : res.count;
++static int
++nfs3_proc_commit(struct nfs_write_data *cdata)
++{
++      struct inode *          inode = cdata->inode;
++      struct nfs_fattr *      fattr = cdata->res.fattr;
++      struct rpc_message      msg = {
++              .rpc_proc       = &nfs3_procedures[NFS3PROC_COMMIT],
++              .rpc_argp       = &cdata->args,
++              .rpc_resp       = &cdata->res,
++              .rpc_cred       = cdata->cred,
++      };
++      int                     status;
++
++      dprintk("NFS call  commit %d @ %Ld\n", cdata->args.count,
++                      (long long) cdata->args.offset);
++      fattr->valid = 0;
++      status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
++      if (status >= 0)
++              nfs3_write_refresh_inode(inode, fattr);
++      dprintk("NFS reply commit: %d\n", status);
++      return status;
+ }
+ /*
+@@ -863,6 +856,7 @@ struct nfs_rpc_ops nfs_v3_clientops = {
+       .readlink       = nfs3_proc_readlink,
+       .read           = nfs3_proc_read,
+       .write          = nfs3_proc_write,
++      .commit         = nfs3_proc_commit,
+       .create         = nfs3_proc_create,
+       .remove         = nfs3_proc_remove,
+       .unlink_setup   = nfs3_proc_unlink_setup,
+--- linux-2.6.0-test6/fs/nfs/nfs4proc.c        2003-06-26 22:07:25.000000000 -0700
++++ 25/fs/nfs/nfs4proc.c       2003-10-05 00:36:45.000000000 -0700
+@@ -1012,45 +1012,36 @@ nfs4_proc_readlink(struct inode *inode, 
+ }
+ static int
+-nfs4_proc_read(struct inode *inode, struct rpc_cred *cred,
+-             struct nfs_fattr *fattr, int flags,
+-             unsigned int base, unsigned int count,
+-             struct page *page, int *eofp)
++nfs4_proc_read(struct nfs_read_data *rdata)
+ {
++      int flags = rdata->flags;
++      struct inode *inode = rdata->inode;
++      struct nfs_fattr *fattr = rdata->res.fattr;
++      nfs4_stateid *stateid = &rdata->args.stateid;
+       struct nfs_server *server = NFS_SERVER(inode);
+       struct nfs4_shareowner  *sp;
+-      uint64_t offset = page_offset(page) + base;
+-      struct nfs_readargs arg = {
+-              .fh             = NFS_FH(inode),
+-              .offset         = offset,
+-              .count          = count,
+-              .pgbase         = base,
+-              .pages          = &page,
+-      };
+-      struct nfs_readres res = {
+-              .fattr          = fattr,
+-              .count          = count,
+-      };
+       struct rpc_message msg = {
+               .rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_READ],
+-              .rpc_argp       = &arg,
+-              .rpc_resp       = &res,
+-              .rpc_cred       = cred,
++              .rpc_argp       = &rdata->args,
++              .rpc_resp       = &rdata->res,
++              .rpc_cred       = rdata->cred,
+       };
+       unsigned long timestamp = jiffies;
+       int status;
+-      dprintk("NFS call  read %d @ %Ld\n", count, (long long)offset);
++      dprintk("NFS call  read %d @ %Ld\n", rdata->args.count,
++                      (long long) rdata->args.offset);
++
+       /*
+-      * Try first to use O_RDONLY, then O_RDWR stateid.
+-      */
++       * Try first to use O_RDONLY, then O_RDWR stateid.
++       */
+       sp = nfs4_get_inode_share(inode, O_RDONLY);
+       if (!sp)
+               sp = nfs4_get_inode_share(inode, O_RDWR);
+       if (sp)
+-              memcpy(arg.stateid,sp->so_stateid, sizeof(nfs4_stateid));
++              memcpy(stateid, sp->so_stateid, sizeof(nfs4_stateid));
+       else
+-              memcpy(arg.stateid, zero_stateid, sizeof(nfs4_stateid));
++              memcpy(stateid, zero_stateid, sizeof(nfs4_stateid));
+       fattr->valid = 0;
+       status = rpc_call_sync(server->client, &msg, flags);
+@@ -1061,56 +1052,82 @@ nfs4_proc_read(struct inode *inode, stru
+                       nfs_zap_caches(inode);
+       }
+       dprintk("NFS reply read: %d\n", status);
+-      *eofp = res.eof;
+       return status;
+ }
+ static int
+-nfs4_proc_write(struct inode *inode, struct rpc_cred *cred,
+-              struct nfs_fattr *fattr, int flags,
+-              unsigned int base, unsigned int count,
+-              struct page *page, struct nfs_writeverf *verf)
++nfs4_proc_write(struct nfs_write_data *wdata)
+ {
++      int rpcflags = wdata->flags;
++      struct inode *inode = wdata->inode;
++      struct nfs_fattr *fattr = wdata->res.fattr;
++      nfs4_stateid *stateid = &wdata->args.stateid;
+       struct nfs_server *server = NFS_SERVER(inode);
+-      struct nfs4_shareowner  *sp;
+-      uint64_t offset = page_offset(page) + base;
+-      struct nfs_writeargs arg = {
+-              .fh             = NFS_FH(inode),
+-              .offset         = offset,
+-              .count          = count,
+-              .stable         = (flags & NFS_RW_SYNC) ? NFS_FILE_SYNC : NFS_UNSTABLE,
+-              .pgbase         = base,
+-              .pages          = &page,
+-      };
+-      struct nfs_writeres res = {
+-              .fattr          = fattr,
+-              .count          = count,
+-              .verf           = verf,
+-      };
++      struct nfs4_shareowner *sp;
+       struct rpc_message msg = {
+               .rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_WRITE],
+-              .rpc_argp       = &arg,
+-              .rpc_resp       = &res,
+-              .rpc_cred       = cred,
++              .rpc_argp       = &wdata->args,
++              .rpc_resp       = &wdata->res,
++              .rpc_cred       = wdata->cred,
++      };
++      int status;
++
++      dprintk("NFS call  write %d @ %Ld\n", wdata->args.count,
++                      (long long) wdata->args.offset);
++
++      /*
++       * Try first to use O_WRONLY, then O_RDWR stateid.
++       */
++      sp = nfs4_get_inode_share(inode, O_WRONLY);
++      if (!sp)
++              sp = nfs4_get_inode_share(inode, O_RDWR);
++
++      if (sp)
++              memcpy(stateid, sp->so_stateid, sizeof(nfs4_stateid));
++      else
++              memcpy(stateid, zero_stateid, sizeof(nfs4_stateid));
++
++      fattr->valid = 0;
++      status = rpc_call_sync(server->client, &msg, rpcflags);
++      dprintk("NFS reply write: %d\n", status);
++      return status;
++}
++
++static int
++nfs4_proc_commit(struct nfs_write_data *cdata)
++{
++      struct inode *inode = cdata->inode;
++      struct nfs_fattr *fattr = cdata->res.fattr;
++      nfs4_stateid *stateid = &cdata->args.stateid;
++      struct nfs_server *server = NFS_SERVER(inode);
++      struct nfs4_shareowner *sp;
++      struct rpc_message msg = {
++              .rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_COMMIT],
++              .rpc_argp       = &cdata->args,
++              .rpc_resp       = &cdata->res,
++              .rpc_cred       = cdata->cred,
+       };
+-      int                     rpcflags = (flags & NFS_RW_SWAP) ? NFS_RPC_SWAPFLAGS : 0;
++      int status;
+-      dprintk("NFS call  write %d @ %Ld\n", count, (long long)offset);
++      dprintk("NFS call  commit %d @ %Ld\n", cdata->args.count,
++                      (long long) cdata->args.offset);
+       /*
+-      * Try first to use O_WRONLY, then O_RDWR stateid.
+-      */
++       * Try first to use O_WRONLY, then O_RDWR stateid.
++       */
+       sp = nfs4_get_inode_share(inode, O_WRONLY);
+       if (!sp)
+               sp = nfs4_get_inode_share(inode, O_RDWR);
+       if (sp)
+-              memcpy(arg.stateid,sp->so_stateid, sizeof(nfs4_stateid));
++              memcpy(stateid, sp->so_stateid, sizeof(nfs4_stateid));
+       else
+-              memcpy(arg.stateid, zero_stateid, sizeof(nfs4_stateid));
++              memcpy(stateid, zero_stateid, sizeof(nfs4_stateid));
+       fattr->valid = 0;
+-      return rpc_call_sync(server->client, &msg, rpcflags);
++      status = rpc_call_sync(server->client, &msg, 0);
++      dprintk("NFS reply commit: %d\n", status);
++      return status;
+ }
+ /*
+@@ -1752,7 +1769,7 @@ struct nfs_rpc_ops       nfs_v4_clientops = {
+       .readlink       = nfs4_proc_readlink,
+       .read           = nfs4_proc_read,
+       .write          = nfs4_proc_write,
+-      .commit         = NULL,
++      .commit         = nfs4_proc_commit,
+       .create         = nfs4_proc_create,
+       .remove         = nfs4_proc_remove,
+       .unlink_setup   = nfs4_proc_unlink_setup,
+--- linux-2.6.0-test6/fs/nfs/pagelist.c        2003-06-26 22:07:25.000000000 -0700
++++ 25/fs/nfs/pagelist.c       2003-10-05 00:36:43.000000000 -0700
+@@ -154,26 +154,6 @@ nfs_release_request(struct nfs_page *req
+ }
+ /**
+- * nfs_release_list - cleanly dispose of an unattached list of page requests
+- * @list: list of doomed page requests
+- */
+-void
+-nfs_release_list(struct list_head *list)
+-{
+-      while (!list_empty(list)) {
+-              struct nfs_page *req = nfs_list_entry(list);
+-
+-              nfs_list_remove_request(req);
+-
+-              page_cache_release(req->wb_page);
+-
+-              /* Release struct file or cached credential */
+-              nfs_clear_request(req);
+-              nfs_page_free(req);
+-      }
+-}
+-
+-/**
+  * nfs_list_add_request - Insert a request into a sorted list
+  * @req: request
+  * @head: head of list into which to insert the request.
+@@ -222,37 +202,6 @@ nfs_wait_on_request(struct nfs_page *req
+ }
+ /**
+- * nfs_wait_for_reads - wait for outstanding requests to complete
+- * @head: list of page requests to wait for
+- */
+-int
+-nfs_wait_for_reads(struct list_head *head)
+-{
+-      struct list_head *p = head->next;
+-      unsigned int res = 0;
+-
+-      while (p != head) {
+-              struct nfs_page *req = nfs_list_entry(p);
+-              int error;
+-
+-              if (!NFS_WBACK_BUSY(req))
+-                      continue;
+-
+-              req->wb_count++;
+-              error = nfs_wait_on_request(req);
+-              if (error < 0)
+-                      return error;
+-              nfs_list_remove_request(req);
+-              nfs_clear_request(req);
+-              nfs_page_free(req);
+-
+-              p = head->next;
+-              res++;
+-      }
+-      return res;
+-}
+-
+-/**
+  * nfs_coalesce_requests - Split coalesced requests out from a list.
+  * @head: source list
+  * @dst: destination list
+--- linux-2.6.0-test6/fs/nfs/proc.c    2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/nfs/proc.c   2003-10-05 00:36:44.000000000 -0700
+@@ -149,82 +149,62 @@ nfs_proc_readlink(struct inode *inode, s
+ }
+ static int
+-nfs_proc_read(struct inode *inode, struct rpc_cred *cred,
+-            struct nfs_fattr *fattr, int flags,
+-            unsigned int base, unsigned int count, struct page *page,
+-            int *eofp)
+-{
+-      u64                     offset = page_offset(page) + base;
+-      struct nfs_readargs     arg = {
+-              .fh             = NFS_FH(inode),
+-              .offset         = offset,
+-              .count          = count,
+-              .pgbase         = base,
+-              .pages          = &page
+-      };
+-      struct nfs_readres      res = {
+-              .fattr          = fattr,
+-              .count          = count
+-      };
++nfs_proc_read(struct nfs_read_data *rdata)
++{
++      int                     flags = rdata->flags;
++      struct inode *          inode = rdata->inode;
++      struct nfs_fattr *      fattr = rdata->res.fattr;
+       struct rpc_message      msg = {
+               .rpc_proc       = &nfs_procedures[NFSPROC_READ],
+-              .rpc_argp       = &arg,
+-              .rpc_resp       = &res,
+-              .rpc_cred       = cred
++              .rpc_argp       = &rdata->args,
++              .rpc_resp       = &rdata->res,
++              .rpc_cred       = rdata->cred,
+       };
+       int                     status;
+-      dprintk("NFS call  read %d @ %Ld\n", count, (long long)offset);
++      dprintk("NFS call  read %d @ %Ld\n", rdata->args.count,
++                      (long long) rdata->args.offset);
+       fattr->valid = 0;
+       status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags);
+-
+-      if (status >= 0)
++      if (status >= 0) {
+               nfs_refresh_inode(inode, fattr);
++              /* NFSv2 reads don't return an eof flag, so we make
++               * up a value here.  XDR has already set eof to 0. */
++              if (status < rdata->args.count)
++                      rdata->res.eof = 1;
++      }
+       dprintk("NFS reply read: %d\n", status);
+-      *eofp = res.eof;
+       return status;
+ }
+ static int
+-nfs_proc_write(struct inode *inode, struct rpc_cred *cred,
+-             struct nfs_fattr *fattr, int how,
+-             unsigned int base, unsigned int count,
+-             struct page *page, struct nfs_writeverf *verf)
++nfs_proc_write(struct nfs_write_data *wdata)
+ {
+-      u64                     offset = page_offset(page) + base;
+-      struct nfs_writeargs    arg = {
+-              .fh             = NFS_FH(inode),
+-              .offset         = offset,
+-              .count          = count,
+-              .stable         = NFS_FILE_SYNC,
+-              .pgbase         = base,
+-              .pages          = &page
+-      };
+-      struct nfs_writeres     res = {
+-              .fattr          = fattr,
+-              .verf           = verf,
+-              .count          = count
+-      };
++      int                     flags = wdata->flags;
++      struct inode *          inode = wdata->inode;
++      struct nfs_fattr *      fattr = wdata->res.fattr;
+       struct rpc_message      msg = {
+               .rpc_proc       = &nfs_procedures[NFSPROC_WRITE],
+-              .rpc_argp       = &arg,
+-              .rpc_resp       = &res,
+-              .rpc_cred       = cred
++              .rpc_argp       = &wdata->args,
++              .rpc_resp       = &wdata->res,
++              .rpc_cred       = wdata->cred
+       };
+-      int                     status, flags = 0;
++      int                     status;
+-      dprintk("NFS call  write %d @ %Ld\n", count, (long long)offset);
++      dprintk("NFS call  write %d @ %Ld\n", wdata->args.count,
++                      (long long) wdata->args.offset);
+       fattr->valid = 0;
+-      if (how & NFS_RW_SWAP)
+-              flags |= NFS_RPC_SWAPFLAGS;
+       status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags);
+-
+-      if (status >= 0)
++      if (status >= 0) {
+               nfs_write_refresh_inode(inode, fattr);
+-
++              /* NFSv2 writes don't return a byte count or write
++               * verifier, so we make up values here.  Note that
++               * v2 writes are always NFS_FILE_SYNC writes. */
++              wdata->res.count = wdata->args.count;
++              wdata->verf.committed = NFS_FILE_SYNC;
++      }
+       dprintk("NFS reply write: %d\n", status);
+-      verf->committed = NFS_FILE_SYNC;      /* NFSv2 always syncs data */
+-      return status < 0? status : count;
++      return status < 0? status : wdata->res.count;
+ }
+ static int
+--- linux-2.6.0-test6/fs/nfs/read.c    2003-06-26 22:07:25.000000000 -0700
++++ 25/fs/nfs/read.c   2003-10-05 00:36:44.000000000 -0700
+@@ -69,19 +69,28 @@ void nfs_readdata_release(struct rpc_tas
+ static int
+ nfs_readpage_sync(struct file *file, struct inode *inode, struct page *page)
+ {
+-      struct rpc_cred *cred = NULL;
+-      struct nfs_fattr fattr;
+-      unsigned int    offset = 0;
+       unsigned int    rsize = NFS_SERVER(inode)->rsize;
+       unsigned int    count = PAGE_CACHE_SIZE;
+       int             result;
+-      int             flags = IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0;
+-      int             eof;
++      struct nfs_read_data    rdata = {
++              .flags          = (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0),
++              .cred           = NULL,
++              .inode          = inode,
++              .args           = {
++                      .fh             = NFS_FH(inode),
++                      .pages          = &page,
++                      .pgbase         = 0UL,
++                      .count          = rsize,
++              },
++              .res            = {
++                      .fattr          = &rdata.fattr,
++              }
++      };
+       dprintk("NFS: nfs_readpage_sync(%p)\n", page);
+       if (file)
+-              cred = nfs_file_cred(file);
++              rdata.cred = nfs_file_cred(file);
+       /*
+        * This works now because the socket layer never tries to DMA
+@@ -89,17 +98,19 @@ nfs_readpage_sync(struct file *file, str
+        */
+       do {
+               if (count < rsize)
+-                      rsize = count;
++                      rdata.args.count = count;
++              rdata.res.count = rdata.args.count;
++              rdata.args.offset = page_offset(page) + rdata.args.pgbase;
+               dprintk("NFS: nfs_proc_read(%s, (%s/%Ld), %Lu, %u)\n",
+                       NFS_SERVER(inode)->hostname,
+                       inode->i_sb->s_id,
+                       (long long)NFS_FILEID(inode),
+-                      (unsigned long long)offset, rsize);
++                      (unsigned long long)rdata.args.pgbase,
++                      rdata.args.count);
+               lock_kernel();
+-              result = NFS_PROTO(inode)->read(inode, cred, &fattr, flags,
+-                                              offset, rsize, page, &eof);
++              result = NFS_PROTO(inode)->read(&rdata);
+               unlock_kernel();
+               /*
+@@ -111,14 +122,15 @@ nfs_readpage_sync(struct file *file, str
+                               result = -EINVAL;
+                       goto io_error;
+               }
+-              count  -= result;
+-              offset += result;
+-              if (result < rsize)     /* NFSv2ism */
++              count -= result;
++              rdata.args.pgbase += result;
++
++              if (rdata.res.eof)
+                       break;
+       } while (count);
+       if (count)
+-              memclear_highpage_flush(page, offset, count);
++              memclear_highpage_flush(page, rdata.args.pgbase, count);
+       SetPageUptodate(page);
+       if (PageError(page))
+               ClearPageError(page);
+--- linux-2.6.0-test6/fs/nfs/write.c   2003-08-22 19:23:42.000000000 -0700
++++ 25/fs/nfs/write.c  2003-10-05 00:36:44.000000000 -0700
+@@ -132,66 +132,73 @@ static int
+ nfs_writepage_sync(struct file *file, struct inode *inode, struct page *page,
+                  unsigned int offset, unsigned int count)
+ {
+-      struct rpc_cred *cred = NULL;
+-      loff_t          base;
+       unsigned int    wsize = NFS_SERVER(inode)->wsize;
+-      int             result, refresh = 0, written = 0, flags;
+-      u8              *buffer;
+-      struct nfs_fattr fattr;
+-      struct nfs_writeverf verf;
+-
++      int             result, written = 0;
++      int             swapfile = IS_SWAPFILE(inode);
++      struct nfs_write_data   wdata = {
++              .flags          = swapfile ? NFS_RPC_SWAPFLAGS : 0,
++              .cred           = NULL,
++              .inode          = inode,
++              .args           = {
++                      .fh             = NFS_FH(inode),
++                      .pages          = &page,
++                      .stable         = NFS_FILE_SYNC,
++                      .pgbase         = offset,
++                      .count          = wsize,
++              },
++              .res            = {
++                      .fattr          = &wdata.fattr,
++                      .verf           = &wdata.verf,
++              },
++      };
+       if (file)
+-              cred = get_rpccred(nfs_file_cred(file));
+-      if (!cred)
+-              cred = get_rpccred(NFS_I(inode)->mm_cred);
++              wdata.cred = get_rpccred(nfs_file_cred(file));
++      if (!wdata.cred)
++              wdata.cred = get_rpccred(NFS_I(inode)->mm_cred);
+       dprintk("NFS:      nfs_writepage_sync(%s/%Ld %d@%Ld)\n",
+               inode->i_sb->s_id,
+               (long long)NFS_FILEID(inode),
+               count, (long long)(page_offset(page) + offset));
+-      base = page_offset(page) + offset;
+-
+-      flags = ((IS_SWAPFILE(inode)) ? NFS_RW_SWAP : 0) | NFS_RW_SYNC;
+-
+       do {
+-              if (count < wsize && !IS_SWAPFILE(inode))
+-                      wsize = count;
++              if (count < wsize && !swapfile)
++                      wdata.args.count = count;
++              wdata.args.offset = page_offset(page) + wdata.args.pgbase;
+-              result = NFS_PROTO(inode)->write(inode, cred, &fattr, flags,
+-                                               offset, wsize, page, &verf);
++              result = NFS_PROTO(inode)->write(&wdata);
+               if (result < 0) {
+                       /* Must mark the page invalid after I/O error */
+                       ClearPageUptodate(page);
+                       goto io_error;
+               }
+-              if (result != wsize)
+-                      printk("NFS: short write, wsize=%u, result=%d\n",
+-                      wsize, result);
+-              refresh = 1;
+-              buffer  += wsize;
+-              base    += wsize;
+-              offset  += wsize;
+-              written += wsize;
+-              count   -= wsize;
++              if (result < wdata.args.count)
++                      printk(KERN_WARNING "NFS: short write, count=%u, result=%d\n",
++                                      wdata.args.count, result);
++
++              wdata.args.offset += result;
++              wdata.args.pgbase += result;
++              written += result;
++              count -= result;
++
+               /*
+                * If we've extended the file, update the inode
+                * now so we don't invalidate the cache.
+                */
+-              if (base > i_size_read(inode))
+-                      i_size_write(inode, base);
++              if (wdata.args.offset > i_size_read(inode))
++                      i_size_write(inode, wdata.args.offset);
+       } while (count);
+       if (PageError(page))
+               ClearPageError(page);
+ io_error:
+-      if (cred)
+-              put_rpccred(cred);
++      if (wdata.cred)
++              put_rpccred(wdata.cred);
+-      return written? written : result;
++      return written ? written : result;
+ }
+ static int
+--- linux-2.6.0-test6/fs/open.c        2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/open.c       2003-10-05 00:36:52.000000000 -0700
+@@ -190,7 +190,9 @@ int do_truncate(struct dentry *dentry, l
+       newattrs.ia_size = length;
+       newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
+       down(&dentry->d_inode->i_sem);
++      down_write(&dentry->d_inode->i_alloc_sem);
+       err = notify_change(dentry, &newattrs);
++      up_write(&dentry->d_inode->i_alloc_sem);
+       up(&dentry->d_inode->i_sem);
+       return err;
+ }
+@@ -772,7 +774,8 @@ struct file *dentry_open(struct dentry *
+                       goto cleanup_file;
+       }
+-      file_ra_state_init(&f->f_ra, inode->i_mapping);
++      f->f_mapping = inode->i_mapping;
++      file_ra_state_init(&f->f_ra, f->f_mapping);
+       f->f_dentry = dentry;
+       f->f_vfsmnt = mnt;
+       f->f_pos = 0;
+@@ -788,8 +791,8 @@ struct file *dentry_open(struct dentry *
+       /* NB: we're sure to have correct a_ops only after f_op->open */
+       if (f->f_flags & O_DIRECT) {
+-              if (!inode->i_mapping || !inode->i_mapping->a_ops ||
+-                      !inode->i_mapping->a_ops->direct_IO) {
++              if (!f->f_mapping || !f->f_mapping->a_ops ||
++                      !f->f_mapping->a_ops->direct_IO) {
+                               fput(f);
+                               f = ERR_PTR(-EINVAL);
+               }
+@@ -1019,7 +1022,7 @@ out_unlock:
+ asmlinkage long sys_vhangup(void)
+ {
+       if (capable(CAP_SYS_TTY_CONFIG)) {
+-              tty_vhangup(current->tty);
++              tty_vhangup(process_tty(current));
+               return 0;
+       }
+       return -EPERM;
+--- linux-2.6.0-test6/fs/pipe.c        2003-08-22 19:23:42.000000000 -0700
++++ 25/fs/pipe.c       2003-10-05 00:34:03.000000000 -0700
+@@ -580,6 +580,7 @@ int do_pipe(int *fd)
+       d_add(dentry, inode);
+       f1->f_vfsmnt = f2->f_vfsmnt = mntget(mntget(pipe_mnt));
+       f1->f_dentry = f2->f_dentry = dget(dentry);
++      f1->f_mapping = f2->f_mapping = inode->i_mapping;
+       /* read file */
+       f1->f_pos = f2->f_pos = 0;
+--- linux-2.6.0-test6/fs/proc/array.c  2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/proc/array.c 2003-10-05 00:36:15.000000000 -0700
+@@ -304,9 +304,9 @@ int proc_pid_stat(struct task_struct *ta
+       mm = task->mm;
+       if(mm)
+               mm = mmgrab(mm);
+-      if (task->tty) {
+-              tty_pgrp = task->tty->pgrp;
+-              tty_nr = new_encode_dev(tty_devnum(task->tty));
++      if (process_tty(task)) {
++              tty_pgrp = process_tty(task)->pgrp;
++              tty_nr = new_encode_dev(tty_devnum(process_tty(task)));
+       }
+       task_unlock(task);
+       if (mm) {
+@@ -345,7 +345,7 @@ int proc_pid_stat(struct task_struct *ta
+               state,
+               ppid,
+               process_group(task),
+-              task->session,
++              process_session(task),
+               tty_nr,
+               tty_pgrp,
+               task->flags,
+--- linux-2.6.0-test6/fs/proc/base.c   2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/proc/base.c  2003-10-05 00:36:09.000000000 -0700
+@@ -53,6 +53,7 @@ enum pid_directory_inos {
+       PROC_TGID_EXE,
+       PROC_TGID_FD,
+       PROC_TGID_ENVIRON,
++      PROC_TGID_AUXV,
+       PROC_TGID_CMDLINE,
+       PROC_TGID_STAT,
+       PROC_TGID_STATM,
+@@ -75,6 +76,7 @@ enum pid_directory_inos {
+       PROC_TID_EXE,
+       PROC_TID_FD,
+       PROC_TID_ENVIRON,
++      PROC_TID_AUXV,
+       PROC_TID_CMDLINE,
+       PROC_TID_STAT,
+       PROC_TID_STATM,
+@@ -104,6 +106,7 @@ static struct pid_entry tgid_base_stuff[
+       E(PROC_TGID_TASK,      "task",    S_IFDIR|S_IRUGO|S_IXUGO),
+       E(PROC_TGID_FD,        "fd",      S_IFDIR|S_IRUSR|S_IXUSR),
+       E(PROC_TGID_ENVIRON,   "environ", S_IFREG|S_IRUSR),
++      E(PROC_TGID_AUXV,      "auxv",    S_IFREG|S_IRUSR),
+       E(PROC_TGID_STATUS,    "status",  S_IFREG|S_IRUGO),
+       E(PROC_TGID_CMDLINE,   "cmdline", S_IFREG|S_IRUGO),
+       E(PROC_TGID_STAT,      "stat",    S_IFREG|S_IRUGO),
+@@ -125,6 +128,7 @@ static struct pid_entry tgid_base_stuff[
+ static struct pid_entry tid_base_stuff[] = {
+       E(PROC_TID_FD,         "fd",      S_IFDIR|S_IRUSR|S_IXUSR),
+       E(PROC_TID_ENVIRON,    "environ", S_IFREG|S_IRUSR),
++      E(PROC_TID_AUXV,       "auxv",    S_IFREG|S_IRUSR),
+       E(PROC_TID_STATUS,     "status",  S_IFREG|S_IRUGO),
+       E(PROC_TID_CMDLINE,    "cmdline", S_IFREG|S_IRUGO),
+       E(PROC_TID_STAT,       "stat",    S_IFREG|S_IRUGO),
+@@ -322,6 +326,25 @@ out:
+       return res;
+ }
++static int proc_pid_auxv(struct task_struct *task, char *buffer)
++{
++      int res = 0;
++      struct mm_struct *mm = get_task_mm(task);
++      if (mm) {
++              unsigned int nwords = 0;
++              do
++                      nwords += 2;
++              while (mm->saved_auxv[nwords - 2] != 0); /* AT_NULL */
++              res = nwords * sizeof(mm->saved_auxv[0]);
++              if (res > PAGE_SIZE)
++                      res = PAGE_SIZE;
++              memcpy(buffer, mm->saved_auxv, res);
++              mmput(mm);
++      }
++      return res;
++}
++
++
+ #ifdef CONFIG_KALLSYMS
+ /*
+  * Provides a wchan file via kallsyms in a proper one-value-per-file format.
+@@ -1271,6 +1294,11 @@ static struct dentry *proc_pident_lookup
+                       inode->i_fop = &proc_info_file_operations;
+                       ei->op.proc_read = proc_pid_environ;
+                       break;
++              case PROC_TID_AUXV:
++              case PROC_TGID_AUXV:
++                      inode->i_fop = &proc_info_file_operations;
++                      ei->op.proc_read = proc_pid_auxv;
++                      break;
+               case PROC_TID_STATUS:
+               case PROC_TGID_STATUS:
+                       inode->i_fop = &proc_info_file_operations;
+--- linux-2.6.0-test6/fs/proc/inode.c  2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/proc/inode.c 2003-10-05 00:33:24.000000000 -0700
+@@ -14,6 +14,7 @@
+ #include <linux/limits.h>
+ #include <linux/init.h>
+ #include <linux/module.h>
++#include <linux/parser.h>
+ #include <linux/smp_lock.h>
+ #include <asm/system.h>
+@@ -135,34 +136,47 @@ static struct super_operations proc_sops
+       .statfs         = simple_statfs,
+ };
++enum {
++      Opt_uid, Opt_gid, Opt_err
++};
++
++static match_table_t tokens = {
++      {Opt_uid, "uid=%u"},
++      {Opt_gid, "gid=%u"},
++      {Opt_err, NULL}
++};
++
+ static int parse_options(char *options,uid_t *uid,gid_t *gid)
+ {
+-      char *this_char,*value;
++      char *p;
++      int option;
+       *uid = current->uid;
+       *gid = current->gid;
+       if (!options)
+               return 1;
+-      while ((this_char = strsep(&options,",")) != NULL) {
+-              if (!*this_char)
++
++      while ((p = strsep(&options, ",")) != NULL) {
++              substring_t args[MAX_OPT_ARGS];
++              int token;
++              if (!*p)
+                       continue;
+-              if ((value = strchr(this_char,'=')) != NULL)
+-                      *value++ = 0;
+-              if (!strcmp(this_char,"uid")) {
+-                      if (!value || !*value)
+-                              return 0;
+-                      *uid = simple_strtoul(value,&value,0);
+-                      if (*value)
+-                              return 0;
+-              }
+-              else if (!strcmp(this_char,"gid")) {
+-                      if (!value || !*value)
++
++              token = match_token(p, tokens, args);
++              switch (token) {
++              case Opt_uid:
++                      if (match_int(args, &option))
+                               return 0;
+-                      *gid = simple_strtoul(value,&value,0);
+-                      if (*value)
++                      *uid = option;
++                      break;
++              case Opt_gid:
++                      if (match_int(args, &option))
+                               return 0;
++                      *gid = option;
++                      break;
++              default:
++                      return 0;
+               }
+-              else return 1;
+       }
+       return 1;
+ }
+--- linux-2.6.0-test6/fs/proc/proc_misc.c      2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/proc/proc_misc.c     2003-10-05 00:36:40.000000000 -0700
+@@ -638,6 +638,36 @@ static void create_seq_entry(char *name,
+               entry->proc_fops = f;
+ }
++#ifdef CONFIG_LOCKMETER
++extern ssize_t get_lockmeter_info(char *, size_t, loff_t *);
++extern ssize_t put_lockmeter_info(const char *, size_t);
++extern int get_lockmeter_info_size(void);
++
++/*
++ * This function accesses lock metering information.
++ */
++static ssize_t read_lockmeter(struct file *file, char *buf,
++                            size_t count, loff_t *ppos)
++{
++      return get_lockmeter_info(buf, count, ppos);
++}
++
++/*
++ * Writing to /proc/lockmeter resets the counters
++ */
++static ssize_t write_lockmeter(struct file * file, const char * buf,
++                             size_t count, loff_t *ppos)
++{
++      return put_lockmeter_info(buf, count);
++}
++
++static struct file_operations proc_lockmeter_operations = {
++      NULL,           /* lseek */
++      read:           read_lockmeter,
++      write:          write_lockmeter,
++};
++#endif  /* CONFIG_LOCKMETER */
++
+ void __init proc_misc_init(void)
+ {
+       struct proc_dir_entry *entry;
+@@ -705,6 +735,13 @@ void __init proc_misc_init(void)
+       if (entry)
+               entry->proc_fops = &proc_sysrq_trigger_operations;
+ #endif
++#ifdef CONFIG_LOCKMETER
++      entry = create_proc_entry("lockmeter", S_IWUSR | S_IRUGO, NULL);
++      if (entry) {
++              entry->proc_fops = &proc_lockmeter_operations;
++              entry->size = get_lockmeter_info_size();
++      }
++#endif
+ #ifdef CONFIG_PPC32
+       {
+               extern struct file_operations ppc_htab_operations;
+--- linux-2.6.0-test6/fs/read_write.c  2003-07-13 21:44:35.000000000 -0700
++++ 25/fs/read_write.c 2003-10-05 00:34:07.000000000 -0700
+@@ -26,7 +26,7 @@ struct file_operations generic_ro_fops =
+ loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
+ {
+       long long retval;
+-      struct inode *inode = file->f_dentry->d_inode->i_mapping->host;
++      struct inode *inode = file->f_mapping->host;
+       down(&inode->i_sem);
+       switch (origin) {
+--- linux-2.6.0-test6/fs/reiserfs/file.c       2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/reiserfs/file.c      2003-10-05 00:34:11.000000000 -0700
+@@ -1052,7 +1052,7 @@ ssize_t reiserfs_file_write( struct file
+     /* Check if we can write to specified region of file, file
+        is not overly big and this kind of stuff. Adjust pos and
+        count, if needed */
+-    res = generic_write_checks(inode, file, &pos, &count, 0);
++    res = generic_write_checks(file, &pos, &count, 0);
+     if (res)
+       goto out;
+@@ -1179,7 +1179,7 @@ ssize_t reiserfs_file_write( struct file
+     }
+     if ((file->f_flags & O_SYNC) || IS_SYNC(inode))
+-      res = generic_osync_inode(inode, OSYNC_METADATA|OSYNC_DATA);
++      res = generic_osync_inode(inode, file->f_mapping, OSYNC_METADATA|OSYNC_DATA);
+     up(&inode->i_sem);
+     return (already_written != 0)?already_written:res;
+--- linux-2.6.0-test6/fs/reiserfs/inode.c      2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/reiserfs/inode.c     2003-10-05 00:34:07.000000000 -0700
+@@ -2375,7 +2375,7 @@ static int reiserfs_direct_IO(int rw, st
+                             loff_t offset, unsigned long nr_segs)
+ {
+     struct file *file = iocb->ki_filp;
+-    struct inode *inode = file->f_dentry->d_inode->i_mapping->host;
++    struct inode *inode = file->f_mapping->host;
+     return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
+                             offset, nr_segs, reiserfs_get_blocks_direct_io, NULL);
+--- linux-2.6.0-test6/fs/reiserfs/journal.c    2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/reiserfs/journal.c   2003-10-05 00:34:11.000000000 -0700
+@@ -1937,18 +1937,13 @@ static int journal_init_dev( struct supe
+       journal -> j_dev_file = filp_open( jdev_name, 0, 0 );
+       if( !IS_ERR( journal -> j_dev_file ) ) {
+-              struct inode *jdev_inode;
+-
+-              jdev_inode = journal -> j_dev_file -> f_dentry -> d_inode;
+-              journal -> j_dev_bd = jdev_inode -> i_bdev;
++              struct inode *jdev_inode = journal->j_dev_file->f_mapping->host;
+               if( !S_ISBLK( jdev_inode -> i_mode ) ) {
+                       printk( "journal_init_dev: '%s' is not a block device\n", jdev_name );
+                       result = -ENOTBLK;
+-              } else if( jdev_inode -> i_bdev == NULL ) {
+-                      printk( "journal_init_dev: bdev uninitialized for '%s'\n", jdev_name );
+-                      result = -ENOMEM;
+               } else  {
+                       /* ok */
++                      journal->j_dev_bd = I_BDEV(jdev_inode);
+                       set_blocksize(journal->j_dev_bd, super->s_blocksize);
+               }
+       } else {
+--- linux-2.6.0-test6/fs/seq_file.c    2003-06-14 12:18:28.000000000 -0700
++++ 25/fs/seq_file.c   2003-10-05 00:33:24.000000000 -0700
+@@ -6,6 +6,7 @@
+  */
+ #include <linux/fs.h>
++#include <linux/module.h>
+ #include <linux/seq_file.h>
+ #include <linux/slab.h>
+@@ -37,6 +38,8 @@ int seq_open(struct file *file, struct s
+       return 0;
+ }
++EXPORT_SYMBOL(seq_open);
++
+ /**
+  *    seq_read -      ->read() method for sequential files.
+  *    @file, @buf, @size, @ppos: see file_operations method
+@@ -144,6 +147,8 @@ Efault:
+       goto Done;
+ }
++EXPORT_SYMBOL(seq_read);
++
+ static int traverse(struct seq_file *m, loff_t offset)
+ {
+       loff_t pos = 0;
+@@ -228,6 +233,8 @@ loff_t seq_lseek(struct file *file, loff
+       return retval;
+ }
++EXPORT_SYMBOL(seq_lseek);
++
+ /**
+  *    seq_release -   free the structures associated with sequential file.
+  *    @file: file in question
+@@ -244,6 +251,8 @@ int seq_release(struct inode *inode, str
+       return 0;
+ }
++EXPORT_SYMBOL(seq_release);
++
+ /**
+  *    seq_escape -    print string into buffer, escaping some characters
+  *    @m:     target buffer
+@@ -279,6 +288,8 @@ int seq_escape(struct seq_file *m, const
+         return 0;
+ }
++EXPORT_SYMBOL(seq_escape);
++
+ int seq_printf(struct seq_file *m, const char *f, ...)
+ {
+       va_list args;
+@@ -297,9 +308,11 @@ int seq_printf(struct seq_file *m, const
+       return -1;
+ }
++EXPORT_SYMBOL(seq_printf);
++
+ int seq_path(struct seq_file *m,
+-              struct vfsmount *mnt, struct dentry *dentry,
+-              char *esc)
++           struct vfsmount *mnt, struct dentry *dentry,
++           char *esc)
+ {
+       if (m->count < m->size) {
+               char *s = m->buf + m->count;
+@@ -328,6 +341,8 @@ int seq_path(struct seq_file *m,
+       return -1;
+ }
++EXPORT_SYMBOL(seq_path);
++
+ static void *single_start(struct seq_file *p, loff_t *pos)
+ {
+       return NULL + (*pos == 0);
+@@ -343,7 +358,8 @@ static void single_stop(struct seq_file 
+ {
+ }
+-int single_open(struct file *file, int (*show)(struct seq_file *, void*), void *data)
++int single_open(struct file *file, int (*show)(struct seq_file *, void *),
++              void *data)
+ {
+       struct seq_operations *op = kmalloc(sizeof(*op), GFP_KERNEL);
+       int res = -ENOMEM;
+@@ -362,6 +378,8 @@ int single_open(struct file *file, int (
+       return res;
+ }
++EXPORT_SYMBOL(single_open);
++
+ int single_release(struct inode *inode, struct file *file)
+ {
+       struct seq_operations *op = ((struct seq_file *)file->private_data)->op;
+@@ -370,6 +388,8 @@ int single_release(struct inode *inode, 
+       return res;
+ }
++EXPORT_SYMBOL(single_release);
++
+ int seq_release_private(struct inode *inode, struct file *file)
+ {
+       struct seq_file *seq = file->private_data;
+@@ -379,3 +399,4 @@ int seq_release_private(struct inode *in
+       return seq_release(inode, file);
+ }
++EXPORT_SYMBOL(seq_release_private);
+--- linux-2.6.0-test6/fs/smbfs/inode.c 2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/smbfs/inode.c        2003-10-05 00:33:24.000000000 -0700
+@@ -551,8 +551,8 @@ int smb_fill_super(struct super_block *s
+       if (ver == SMB_MOUNT_OLDVERSION) {
+               mnt->version = oldmnt->version;
+-              mnt->uid = low2highuid(oldmnt->uid);
+-              mnt->gid = low2highuid(oldmnt->gid);
++              mnt->uid = OLD_TO_NEW_UID(oldmnt->uid);
++              mnt->gid = OLD_TO_NEW_GID(oldmnt->gid);
+               mnt->file_mode = (oldmnt->file_mode & S_IRWXUGO) | S_IFREG;
+               mnt->dir_mode = (oldmnt->dir_mode & S_IRWXUGO) | S_IFDIR;
+--- linux-2.6.0-test6/fs/super.c       2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/super.c      2003-10-05 00:36:10.000000000 -0700
+@@ -21,6 +21,7 @@
+  */
+ #include <linux/config.h>
++#include <linux/module.h>
+ #include <linux/slab.h>
+ #include <linux/smp_lock.h>
+ #include <linux/acct.h>
+@@ -134,9 +135,11 @@ void deactivate_super(struct super_block
+       }
+ }
++EXPORT_SYMBOL(deactivate_super);
++
+ /**
+- *    grab_super      - acquire an active reference
+- *    @s      - reference we are trying to make active
++ *    grab_super - acquire an active reference
++ *    @s: reference we are trying to make active
+  *
+  *    Tries to acquire an active reference.  grab_super() is used when we
+  *    had just found a superblock in super_blocks or fs_type->fs_supers
+@@ -214,6 +217,8 @@ void generic_shutdown_super(struct super
+       up_write(&sb->s_umount);
+ }
++EXPORT_SYMBOL(generic_shutdown_super);
++
+ /**
+  *    sget    -       find or create a superblock
+  *    @type:  filesystem type superblock should belong to
+@@ -226,13 +231,10 @@ struct super_block *sget(struct file_sys
+                       int (*set)(struct super_block *,void *),
+                       void *data)
+ {
+-      struct super_block *s = alloc_super();
++      struct super_block *s = NULL;
+       struct list_head *p;
+       int err;
+-      if (!s)
+-              return ERR_PTR(-ENOMEM);
+-
+ retry:
+       spin_lock(&sb_lock);
+       if (test) list_for_each(p, &type->fs_supers) {
+@@ -242,9 +244,18 @@ retry:
+                       continue;
+               if (!grab_super(old))
+                       goto retry;
+-              destroy_super(s);
++              if (s)
++                      destroy_super(s);
+               return old;
+       }
++      if (!s) {
++              spin_unlock(&sb_lock);
++              s = alloc_super();
++              if (!s)
++                      return ERR_PTR(-ENOMEM);
++              goto retry;
++      }
++              
+       err = set(s, data);
+       if (err) {
+               spin_unlock(&sb_lock);
+@@ -259,12 +270,16 @@ retry:
+       return s;
+ }
++EXPORT_SYMBOL(sget);
++
+ void drop_super(struct super_block *sb)
+ {
+       up_read(&sb->s_umount);
+       put_super(sb);
+ }
++EXPORT_SYMBOL(drop_super);
++
+ static inline void write_super(struct super_block *sb)
+ {
+       lock_super(sb);
+@@ -353,8 +368,8 @@ restart:
+ }
+ /**
+- *    get_super       -       get the superblock of a device
+- *    @dev: device to get the superblock for
++ *    get_super - get the superblock of a device
++ *    @bdev: device to get the superblock for
+  *    
+  *    Scans the superblock list and finds the superblock of the file system
+  *    mounted on the device given. %NULL is returned if no match is found.
+@@ -382,6 +397,8 @@ rescan:
+       spin_unlock(&sb_lock);
+       return NULL;
+ }
++
++EXPORT_SYMBOL(get_super);
+  
+ struct super_block * user_get_super(dev_t dev)
+ {
+@@ -405,6 +422,8 @@ rescan:
+       return NULL;
+ }
++EXPORT_SYMBOL(user_get_super);
++
+ asmlinkage long sys_ustat(unsigned dev, struct ustat __user * ubuf)
+ {
+         struct super_block *s;
+@@ -442,10 +461,11 @@ static void mark_files_ro(struct super_b
+ }
+ /**
+- *    do_remount_sb   -       asks filesystem to change mount options.
++ *    do_remount_sb - asks filesystem to change mount options.
+  *    @sb:    superblock in question
+  *    @flags: numeric part of options
+  *    @data:  the rest of options
++ *      @force: whether or not to force the change
+  *
+  *    Alters the mount options of a mounted file system.
+  */
+@@ -534,6 +554,8 @@ int set_anon_super(struct super_block *s
+       return 0;
+ }
++EXPORT_SYMBOL(set_anon_super);
++
+ void kill_anon_super(struct super_block *sb)
+ {
+       int slot = MINOR(sb->s_dev);
+@@ -543,6 +565,8 @@ void kill_anon_super(struct super_block 
+       spin_unlock(&unnamed_dev_lock);
+ }
++EXPORT_SYMBOL(kill_anon_super);
++
+ void kill_litter_super(struct super_block *sb)
+ {
+       if (sb->s_root)
+@@ -550,6 +574,8 @@ void kill_litter_super(struct super_bloc
+       kill_anon_super(sb);
+ }
++EXPORT_SYMBOL(kill_litter_super);
++
+ static int set_bdev_super(struct super_block *s, void *data)
+ {
+       s->s_bdev = data;
+@@ -608,6 +634,8 @@ out:
+       return s;
+ }
++EXPORT_SYMBOL(get_sb_bdev);
++
+ void kill_block_super(struct super_block *sb)
+ {
+       struct block_device *bdev = sb->s_bdev;
+@@ -616,6 +644,8 @@ void kill_block_super(struct super_block
+       close_bdev_excl(bdev, BDEV_FS);
+ }
++EXPORT_SYMBOL(kill_block_super);
++
+ struct super_block *get_sb_nodev(struct file_system_type *fs_type,
+       int flags, void *data,
+       int (*fill_super)(struct super_block *, void *, int))
+@@ -638,6 +668,8 @@ struct super_block *get_sb_nodev(struct 
+       return s;
+ }
++EXPORT_SYMBOL(get_sb_nodev);
++
+ static int compare_single(struct super_block *s, void *p)
+ {
+       return 1;
+@@ -667,6 +699,8 @@ struct super_block *get_sb_single(struct
+       return s;
+ }
++EXPORT_SYMBOL(get_sb_single);
++
+ struct vfsmount *
+ do_kern_mount(const char *fstype, int flags, const char *name, void *data)
+ {
+@@ -709,3 +743,5 @@ struct vfsmount *kern_mount(struct file_
+ {
+       return do_kern_mount(type->name, 0, type->name, NULL);
+ }
++
++EXPORT_SYMBOL(kern_mount);
+--- linux-2.6.0-test6/fs/sysfs/dir.c   2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/sysfs/dir.c  2003-10-05 00:34:36.000000000 -0700
+@@ -82,8 +82,16 @@ static void remove_dir(struct dentry * d
+ {
+       struct dentry * parent = dget(d->d_parent);
+       down(&parent->d_inode->i_sem);
+-      d_delete(d);
+-      simple_rmdir(parent->d_inode,d);
++      /*
++       * It is possible that parent has already been removed, in which
++       * case directory is already unhashed and dput.
++       * Note that this won't update parent->d_inode->i_nlink; OTOH
++       * parent should already be dead
++       */
++      if (!d_unhashed(d)) {
++              d_delete(d);
++              simple_rmdir(parent->d_inode,d);
++      }
+       pr_debug(" o %s removing done (%d)\n",d->d_name.name,
+                atomic_read(&d->d_count));
+--- linux-2.6.0-test6/fs/udf/inode.c   2003-09-08 13:58:59.000000000 -0700
++++ 25/fs/udf/inode.c  2003-10-05 00:33:24.000000000 -0700
+@@ -127,6 +127,7 @@ no_delete:
+ void udf_clear_inode(struct inode *inode)
+ {
+       kfree(UDF_I_DATA(inode));
++      UDF_I_DATA(inode) = NULL;
+ }
+ void udf_discard_prealloc(struct inode * inode)
+--- linux-2.6.0-test6/fs/udf/super.c   2003-09-08 13:58:59.000000000 -0700
++++ 25/fs/udf/super.c  2003-10-05 00:33:24.000000000 -0700
+@@ -50,6 +50,7 @@
+ #include <linux/slab.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
++#include <linux/parser.h>
+ #include <linux/stat.h>
+ #include <linux/cdrom.h>
+ #include <linux/nls.h>
+@@ -132,8 +133,10 @@ static void init_once(void * foo, kmem_c
+       struct udf_inode_info *ei = (struct udf_inode_info *) foo;
+       if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+-          SLAB_CTOR_CONSTRUCTOR)
++          SLAB_CTOR_CONSTRUCTOR) {
++              ei->i_ext.i_data = NULL;
+               inode_init_once(&ei->vfs_inode);
++      }
+ }
+ static int init_inodecache(void)
+@@ -225,7 +228,7 @@ module_exit(exit_udf_fs)
+  *    gid=            Set the default group.
+  *    umask=          Set the default umask.
+  *    uid=            Set the default user.
+- *    bs=                     Set the block size.
++ *    bs=             Set the block size.
+  *    unhide          Show otherwise hidden files.
+  *    undelete        Show deleted files in lists.
+  *    adinicb         Embed data in the inode (default)
+@@ -259,18 +262,53 @@ module_exit(exit_udf_fs)
+  *    uopts           Pointer to mount options variable.
+  *
+  * POST-CONDITIONS
+- *    <return>        0       Mount options parsed okay.
+- *    <return>        -1      Error parsing mount options.
++ *    <return>        1       Mount options parsed okay.
++ *    <return>        0       Error parsing mount options.
+  *
+  * HISTORY
+  *    July 1, 1997 - Andrew E. Mileski
+  *    Written, tested, and released.
+  */
++enum {
++      Opt_novrs, Opt_nostrict, Opt_bs, Opt_unhide, Opt_undelete,
++      Opt_noadinicb, Opt_adinicb, Opt_shortad, Opt_longad,
++      Opt_gid, Opt_uid, Opt_umask, Opt_session, Opt_lastblock,
++      Opt_anchor, Opt_volume, Opt_partition, Opt_fileset,
++      Opt_rootdir, Opt_utf8, Opt_iocharset,
++      Opt_err
++};
++
++static match_table_t tokens = {
++      {Opt_novrs, "novrs"},
++      {Opt_nostrict, "nostrict"},
++      {Opt_bs, "bs=%u"},
++      {Opt_unhide, "unhide"},
++      {Opt_undelete, "undelete"},
++      {Opt_noadinicb, "noadinicb"},
++      {Opt_adinicb, "adinicb"},
++      {Opt_shortad, "shortad"},
++      {Opt_longad, "longad"},
++      {Opt_gid, "gid=%u"},
++      {Opt_uid, "uid=%u"},
++      {Opt_umask, "umask=%o"},
++      {Opt_session, "session=%u"},
++      {Opt_lastblock, "lastblock=%u"},
++      {Opt_anchor, "anchor=%u"},
++      {Opt_volume, "volume=%u"},
++      {Opt_partition, "partition=%u"},
++      {Opt_fileset, "fileset=%u"},
++      {Opt_rootdir, "rootdir=%u"},
++      {Opt_utf8, "utf8"},
++      {Opt_iocharset, "iocharset=%s"},
++      {Opt_err, NULL}
++};
++
+ static int
+ udf_parse_options(char *options, struct udf_options *uopt)
+ {
+-      char *opt, *val;
++      char *p;
++      int option;
+       uopt->novrs = 0;
+       uopt->blocksize = 2048;
+@@ -286,71 +324,106 @@ udf_parse_options(char *options, struct 
+       if (!options)
+               return 1;
+-      while ((opt = strsep(&options, ",")) != NULL)
+-      {
+-              if (!*opt)
++      while ((p = strsep(&options, ",")) != NULL) {
++              substring_t args[MAX_OPT_ARGS];
++              int token;
++              if (!*p)
+                       continue;
+-              /* Make "opt=val" into two strings */
+-              val = strchr(opt, '=');
+-              if (val)
+-                      *(val++) = 0;
+-              if (!strcmp(opt, "novrs") && !val)
++
++              token = match_token(p, tokens, args);
++              switch (token) {
++              case Opt_novrs:
+                       uopt->novrs = 1;
+-              else if (!strcmp(opt, "bs") && val)
+-                      uopt->blocksize = simple_strtoul(val, NULL, 0);
+-              else if (!strcmp(opt, "unhide") && !val)
++                      break;
++              case Opt_bs:
++                      if (match_int(&args[0], &option))
++                              return 0;
++                      uopt->blocksize = option;
++                      break;
++              case Opt_unhide:
+                       uopt->flags |= (1 << UDF_FLAG_UNHIDE);
+-              else if (!strcmp(opt, "undelete") && !val)
++                      break;
++              case Opt_undelete:
+                       uopt->flags |= (1 << UDF_FLAG_UNDELETE);
+-              else if (!strcmp(opt, "noadinicb") && !val)
++                      break;
++              case Opt_noadinicb:
+                       uopt->flags &= ~(1 << UDF_FLAG_USE_AD_IN_ICB);
+-              else if (!strcmp(opt, "adinicb") && !val)
++                      break;
++              case Opt_adinicb:
+                       uopt->flags |= (1 << UDF_FLAG_USE_AD_IN_ICB);
+-              else if (!strcmp(opt, "shortad") && !val)
++                      break;
++              case Opt_shortad:
+                       uopt->flags |= (1 << UDF_FLAG_USE_SHORT_AD);
+-              else if (!strcmp(opt, "longad") && !val)
++                      break;
++              case Opt_longad:
+                       uopt->flags &= ~(1 << UDF_FLAG_USE_SHORT_AD);
+-              else if (!strcmp(opt, "gid") && val)
+-                      uopt->gid = simple_strtoul(val, NULL, 0);
+-              else if (!strcmp(opt, "umask") && val)
+-                      uopt->umask = simple_strtoul(val, NULL, 0);
+-              else if (!strcmp(opt, "nostrict") && !val)
++                      break;
++              case Opt_gid:
++                      if (match_int(args, &option))
++                              return 0;
++                      uopt->gid = option;
++                      break;
++              case Opt_uid:
++                      if (match_int(args, &option))
++                              return 0;
++                      uopt->uid = option;
++                      break;
++              case Opt_umask:
++                      if (match_octal(args, &option))
++                              return 0;
++                      uopt->umask = option;
++                      break;
++              case Opt_nostrict:
+                       uopt->flags &= ~(1 << UDF_FLAG_STRICT);
+-              else if (!strcmp(opt, "uid") && val)
+-                      uopt->uid = simple_strtoul(val, NULL, 0);
+-              else if (!strcmp(opt, "session") && val)
+-                      uopt->session = simple_strtoul(val, NULL, 0);
+-              else if (!strcmp(opt, "lastblock") && val)
+-                      uopt->lastblock = simple_strtoul(val, NULL, 0);
+-              else if (!strcmp(opt, "anchor") && val)
+-                      uopt->anchor = simple_strtoul(val, NULL, 0);
+-              else if (!strcmp(opt, "volume") && val)
+-                      uopt->volume = simple_strtoul(val, NULL, 0);
+-              else if (!strcmp(opt, "partition") && val)
+-                      uopt->partition = simple_strtoul(val, NULL, 0);
+-              else if (!strcmp(opt, "fileset") && val)
+-                      uopt->fileset = simple_strtoul(val, NULL, 0);
+-              else if (!strcmp(opt, "rootdir") && val)
+-                      uopt->rootdir = simple_strtoul(val, NULL, 0);
++                      break;
++              case Opt_session:
++                      if (match_int(args, &option))
++                              return 0;
++                      uopt->session = option;
++                      break;
++              case Opt_lastblock:
++                      if (match_int(args, &option))
++                              return 0;
++                      uopt->lastblock = option;
++                      break;
++              case Opt_anchor:
++                      if (match_int(args, &option))
++                              return 0;
++                      uopt->anchor = option;
++                      break;
++              case Opt_volume:
++                      if (match_int(args, &option))
++                              return 0;
++                      uopt->volume = option;
++                      break;
++              case Opt_partition:
++                      if (match_int(args, &option))
++                              return 0;
++                      uopt->partition = option;
++                      break;
++              case Opt_fileset:
++                      if (match_int(args, &option))
++                              return 0;
++                      uopt->fileset = option;
++                      break;
++              case Opt_rootdir:
++                      if (match_int(args, &option))
++                              return 0;
++                      uopt->rootdir = option;
++                      break;
++              case Opt_utf8:
++                      uopt->flags |= (1 << UDF_FLAG_UTF8);
++                      break;
+ #ifdef CONFIG_NLS
+-              else if (!strcmp(opt, "iocharset") && val)
+-              {
+-                      uopt->nls_map = load_nls(val);
++              case Opt_iocharset:
++                      uopt->nls_map = load_nls(args[0].from);
+                       uopt->flags |= (1 << UDF_FLAG_NLS_MAP);
+-              }
++                      break;
+ #endif
+-              else if (!strcmp(opt, "utf8") && !val)
+-                      uopt->flags |= (1 << UDF_FLAG_UTF8);
+-              else if (val)
+-              {
+-                      printk(KERN_ERR "udf: bad mount option \"%s=%s\"\n",
+-                              opt, val);
+-                      return 0;
+-              }
+-              else
+-              {
+-                      printk(KERN_ERR "udf: bad mount option \"%s\"\n",
+-                              opt);
++              default:
++                      printk(KERN_ERR "udf: bad mount option \"%s\" "
++                                      "or missing value\n",
++                              p);
+                       return 0;
+               }
+       }
+--- linux-2.6.0-test6/fs/ufs/super.c   2003-06-22 12:04:44.000000000 -0700
++++ 25/fs/ufs/super.c  2003-10-05 00:33:24.000000000 -0700
+@@ -79,6 +79,7 @@
+ #include <linux/string.h>
+ #include <linux/blkdev.h>
+ #include <linux/init.h>
++#include <linux/parser.h>
+ #include <linux/smp_lock.h>
+ #include <linux/buffer_head.h>
+ #include <linux/vfs.h>
+@@ -250,64 +251,99 @@ void ufs_warning (struct super_block * s
+               sb->s_id, function, error_buf);
+ }
++enum {
++      Opt_type_old, Opt_type_sunx86, Opt_type_sun, Opt_type_44bsd,
++      Opt_type_hp, Opt_type_nextstepcd, Opt_type_nextstep,
++      Opt_type_openstep, Opt_onerror_panic, Opt_onerror_lock,
++      Opt_onerror_umount, Opt_onerror_repair, Opt_err
++};
++
++static match_table_t tokens = {
++      {Opt_type_old, "ufstype=old"},
++      {Opt_type_sunx86, "ufstype=sunx86"},
++      {Opt_type_sun, "ufstype=sun"},
++      {Opt_type_44bsd, "ufstype=44bsd"},
++      {Opt_type_hp, "ufstype=hp"},
++      {Opt_type_nextstepcd, "ufstype=nextstep-cd"},
++      {Opt_type_nextstep, "ufstype=nextstep"},
++      {Opt_type_openstep, "ufstype=openstep"},
++      {Opt_onerror_panic, "onerror=panic"},
++      {Opt_onerror_lock, "onerror=lock"},
++      {Opt_onerror_umount, "onerror=umount"},
++      {Opt_onerror_repair, "onerror=repair"},
++      {Opt_err, NULL}
++};
++
+ static int ufs_parse_options (char * options, unsigned * mount_options)
+ {
+-      char * this_char;
+-      char * value;
++      char * p;
+       
+       UFSD(("ENTER\n"))
+       
+       if (!options)
+               return 1;
+-      while ((this_char = strsep (&options, ",")) != NULL) {
+-              if (!*this_char)
++      while ((p = strsep(&options, ",")) != NULL) {
++              substring_t args[MAX_OPT_ARGS];
++              int token;
++              if (!*p)
+                       continue;
+-              if ((value = strchr (this_char, '=')) != NULL)
+-                      *value++ = 0;
+-              if (!strcmp (this_char, "ufstype")) {
++
++              token = match_token(p, tokens, args);
++              switch (token) {
++              case Opt_type_old:
+                       ufs_clear_opt (*mount_options, UFSTYPE);
+-                      if (!strcmp (value, "old"))
+-                              ufs_set_opt (*mount_options, UFSTYPE_OLD);
+-                      else if (!strcmp (value, "sun"))
+-                              ufs_set_opt (*mount_options, UFSTYPE_SUN);
+-                      else if (!strcmp (value, "44bsd"))
+-                              ufs_set_opt (*mount_options, UFSTYPE_44BSD);
+-                      else if (!strcmp (value, "nextstep"))
+-                              ufs_set_opt (*mount_options, UFSTYPE_NEXTSTEP);
+-                      else if (!strcmp (value, "nextstep-cd"))
+-                              ufs_set_opt (*mount_options, UFSTYPE_NEXTSTEP_CD);
+-                      else if (!strcmp (value, "openstep"))
+-                              ufs_set_opt (*mount_options, UFSTYPE_OPENSTEP);
+-                      else if (!strcmp (value, "sunx86"))
+-                              ufs_set_opt (*mount_options, UFSTYPE_SUNx86);
+-                      else if (!strcmp (value, "hp"))
+-                              ufs_set_opt (*mount_options, UFSTYPE_HP);
+-                      else {
+-                              printk ("UFS-fs: Invalid type option: %s\n", value);
+-                              return 0;
+-                      }
+-              }
+-              else if (!strcmp (this_char, "onerror")) {
++                      ufs_set_opt (*mount_options, UFSTYPE_OLD);
++                      break;
++              case Opt_type_sunx86:
++                      ufs_clear_opt (*mount_options, UFSTYPE);
++                      ufs_set_opt (*mount_options, UFSTYPE_SUNx86);
++                      break;
++              case Opt_type_sun:
++                      ufs_clear_opt (*mount_options, UFSTYPE);
++                      ufs_set_opt (*mount_options, UFSTYPE_SUN);
++                      break;
++              case Opt_type_44bsd:
++                      ufs_clear_opt (*mount_options, UFSTYPE);
++                      ufs_set_opt (*mount_options, UFSTYPE_44BSD);
++                      break;
++              case Opt_type_hp:
++                      ufs_clear_opt (*mount_options, UFSTYPE);
++                      ufs_set_opt (*mount_options, UFSTYPE_HP);
++                      break;
++              case Opt_type_nextstepcd:
++                      ufs_clear_opt (*mount_options, UFSTYPE);
++                      ufs_set_opt (*mount_options, UFSTYPE_NEXTSTEP_CD);
++                      break;
++              case Opt_type_nextstep:
++                      ufs_clear_opt (*mount_options, UFSTYPE);
++                      ufs_set_opt (*mount_options, UFSTYPE_NEXTSTEP);
++                      break;
++              case Opt_type_openstep:
++                      ufs_clear_opt (*mount_options, UFSTYPE);
++                      ufs_set_opt (*mount_options, UFSTYPE_OPENSTEP);
++                      break;
++              case Opt_onerror_panic:
+                       ufs_clear_opt (*mount_options, ONERROR);
+-                      if (!strcmp (value, "panic"))
+-                              ufs_set_opt (*mount_options, ONERROR_PANIC);
+-                      else if (!strcmp (value, "lock"))
+-                              ufs_set_opt (*mount_options, ONERROR_LOCK);
+-                      else if (!strcmp (value, "umount"))
+-                              ufs_set_opt (*mount_options, ONERROR_UMOUNT);
+-                      else if (!strcmp (value, "repair")) {
+-                              printk("UFS-fs: Unable to do repair on error, "
+-                                      "will lock lock instead \n");
+-                              ufs_set_opt (*mount_options, ONERROR_REPAIR);
+-                      }
+-                      else {
+-                              printk ("UFS-fs: Invalid action onerror: %s\n", value);
+-                              return 0;
+-                      }
+-              }
+-              else {
+-                      printk("UFS-fs: Invalid option: %s\n", this_char);
++                      ufs_set_opt (*mount_options, ONERROR_PANIC);
++                      break;
++              case Opt_onerror_lock:
++                      ufs_clear_opt (*mount_options, ONERROR);
++                      ufs_set_opt (*mount_options, ONERROR_LOCK);
++                      break;
++              case Opt_onerror_umount:
++                      ufs_clear_opt (*mount_options, ONERROR);
++                      ufs_set_opt (*mount_options, ONERROR_UMOUNT);
++                      break;
++              case Opt_onerror_repair:
++                      printk("UFS-fs: Unable to do repair on error, "
++                              "will lock lock instead\n");
++                      ufs_clear_opt (*mount_options, ONERROR);
++                      ufs_set_opt (*mount_options, ONERROR_REPAIR);
++                      break;
++              default:
++                      printk("UFS-fs: Invalid option: \"%s\" "
++                                      "or missing value\n", p);
+                       return 0;
+               }
+       }
+--- linux-2.6.0-test6/fs/xfs/linux/xfs_aops.c  2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/xfs/linux/xfs_aops.c 2003-10-05 00:36:53.000000000 -0700
+@@ -461,7 +461,8 @@ map_unwritten(
+               struct page             *page;
+               tlast = i_size_read(inode) >> PAGE_CACHE_SHIFT;
+-              tloff = min(tlast, start_page->index + pb->pb_page_count - 1);
++              tloff = (mp->pbm_offset + mp->pbm_bsize) >> PAGE_CACHE_SHIFT;
++              tloff = min(tlast, tloff);
+               for (tindex = start_page->index + 1; tindex < tloff; tindex++) {
+                       page = probe_unwritten_page(mapping, tindex, mp, pb,
+                                               PAGE_CACHE_SIZE, &bs, bbits);
+@@ -973,7 +974,7 @@ linvfs_direct_IO(
+       unsigned long           nr_segs)
+ {
+       struct file     *file = iocb->ki_filp;
+-      struct inode    *inode = file->f_dentry->d_inode->i_mapping->host;
++      struct inode    *inode = file->f_mapping->host;
+       vnode_t         *vp = LINVFS_GET_VP(inode);
+       page_buf_bmap_t pbmap;
+       int             maps = 1;
+@@ -983,7 +984,7 @@ linvfs_direct_IO(
+       if (error)
+               return -error;
+-        return blockdev_direct_IO(rw, iocb, inode,
++        return blockdev_direct_IO_no_locking(rw, iocb, inode,
+               pbmap.pbm_target->pbr_bdev,
+               iov, offset, nr_segs,
+               linvfs_get_blocks_direct,
+@@ -1041,6 +1042,8 @@ count_page_state(
+       do {
+               if (buffer_uptodate(bh) && !buffer_mapped(bh))
+                       (*unmapped) = 1;
++              else if (buffer_unwritten(bh) && !buffer_delay(bh))
++                      clear_buffer_unwritten(bh);
+               else if (buffer_unwritten(bh))
+                       (*unwritten) = 1;
+               else if (buffer_delay(bh))
+--- linux-2.6.0-test6/fs/xfs/linux/xfs_file.c  2003-08-22 19:23:42.000000000 -0700
++++ 25/fs/xfs/linux/xfs_file.c 2003-10-05 00:34:07.000000000 -0700
+@@ -86,7 +86,7 @@ linvfs_write(
+ {
+       struct iovec    iov = {(void *)buf, count};
+       struct file     *file = iocb->ki_filp;
+-      struct inode    *inode = file->f_dentry->d_inode->i_mapping->host;
++      struct inode    *inode = file->f_mapping->host;
+       vnode_t         *vp = LINVFS_GET_VP(inode);
+       int             error;
+       int             direct = file->f_flags & O_DIRECT;
+@@ -111,7 +111,7 @@ linvfs_readv(
+       unsigned long           nr_segs,
+       loff_t                  *ppos)
+ {
+-      struct inode    *inode = file->f_dentry->d_inode->i_mapping->host;
++      struct inode    *inode = file->f_mapping->host;
+       vnode_t         *vp = LINVFS_GET_VP(inode);
+       struct          kiocb kiocb;
+       int             error;
+@@ -133,7 +133,7 @@ linvfs_writev(
+       unsigned long           nr_segs,
+       loff_t                  *ppos)
+ {
+-      struct inode    *inode = file->f_dentry->d_inode->i_mapping->host;
++      struct inode    *inode = file->f_mapping->host;
+       vnode_t         *vp = LINVFS_GET_VP(inode);
+       struct          kiocb kiocb;
+       int             error;
+--- linux-2.6.0-test6/fs/xfs/linux/xfs_iops.c  2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/xfs/linux/xfs_iops.c 2003-10-05 00:33:24.000000000 -0700
+@@ -386,6 +386,7 @@ linvfs_readlink(
+       uio.uio_segflg = UIO_USERSPACE;
+       uio.uio_resid = size;
+       uio.uio_iovcnt = 1;
++      uio.uio_fmode = 0;
+       VOP_READLINK(vp, &uio, NULL, error);
+       if (error)
+--- linux-2.6.0-test6/fs/xfs/linux/xfs_lrw.c   2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/xfs/linux/xfs_lrw.c  2003-10-05 00:33:24.000000000 -0700
+@@ -218,7 +218,7 @@ xfs_read(
+               int error;
+               vrwlock_t locktype = VRWLOCK_READ;
+-              error = XFS_SEND_DATA(mp, DM_EVENT_READ, bdp, *offset, size,
++              error = XFS_SEND_DATA(mp, DM_EVENT_READ, BHV_TO_VNODE(bdp), *offset, size,
+                                     FILP_DELAY_FLAG(file), &locktype);
+               if (error) {
+                       xfs_iunlock(ip, XFS_IOLOCK_SHARED);
+@@ -278,7 +278,7 @@ xfs_sendfile(
+               vrwlock_t locktype = VRWLOCK_READ;
+               int error;
+-              error = XFS_SEND_DATA(mp, DM_EVENT_READ, bdp, *offset, count,
++              error = XFS_SEND_DATA(mp, DM_EVENT_READ, BHV_TO_VNODE(bdp), *offset, count,
+                                     FILP_DELAY_FLAG(filp), &locktype);
+               if (error) {
+                       xfs_iunlock(ip, XFS_IOLOCK_SHARED);
+@@ -612,7 +612,7 @@ start:
+               loff_t          savedsize = *offset;
+               xfs_iunlock(xip, XFS_ILOCK_EXCL);
+-              error = XFS_SEND_DATA(xip->i_mount, DM_EVENT_WRITE, bdp,
++              error = XFS_SEND_DATA(xip->i_mount, DM_EVENT_WRITE, vp,
+                                     *offset, size,
+                                     FILP_DELAY_FLAG(file), &locktype);
+               if (error) {
+--- linux-2.6.0-test6/fs/xfs/linux/xfs_stats.c 2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/xfs/linux/xfs_stats.c        2003-10-05 00:33:24.000000000 -0700
+@@ -33,7 +33,7 @@
+ #include "xfs.h"
+ #include <linux/proc_fs.h>
+-struct xfsstats xfsstats;
++DEFINE_PER_CPU(struct xfsstats, xfsstats);
+ STATIC int
+ xfs_read_xfsstats(
+@@ -44,7 +44,11 @@ xfs_read_xfsstats(
+       int             *eof,
+       void            *data)
+ {
+-      int             i, j, len;
++      int             c, i, j, len, val;
++      __uint64_t      xs_xstrat_bytes = 0;
++      __uint64_t      xs_write_bytes = 0;
++      __uint64_t      xs_read_bytes = 0;
++
+       static struct xstats_entry {
+               char    *desc;
+               int     endpoint;
+@@ -65,21 +69,32 @@ xfs_read_xfsstats(
+               { "vnodes",             XFSSTAT_END_VNODE_OPS           },
+       };
++      /* Loop over all stats groups */
+       for (i=j=len = 0; i < sizeof(xstats)/sizeof(struct xstats_entry); i++) {
+               len += sprintf(buffer + len, xstats[i].desc);
+               /* inner loop does each group */
+               while (j < xstats[i].endpoint) {
+-                      len += sprintf(buffer + len, " %u",
+-                                      *(((__u32*)&xfsstats) + j));
++                      val = 0;
++                      /* sum over all cpus */
++                      for (c = 0; c < NR_CPUS; c++) {
++                              if (!cpu_possible(c)) continue;
++                              val += *(((__u32*)&per_cpu(xfsstats, c) + j));
++                      }
++                      len += sprintf(buffer + len, " %u", val);
+                       j++;
+               }
+               buffer[len++] = '\n';
+       }
+       /* extra precision counters */
++      for (i = 0; i < NR_CPUS; i++) {
++              if (!cpu_possible(i)) continue;
++              xs_xstrat_bytes += per_cpu(xfsstats, i).xs_xstrat_bytes;
++              xs_write_bytes += per_cpu(xfsstats, i).xs_write_bytes;
++              xs_read_bytes += per_cpu(xfsstats, i).xs_read_bytes;
++      }
++
+       len += sprintf(buffer + len, "xpc %Lu %Lu %Lu\n",
+-                      xfsstats.xs_xstrat_bytes,
+-                      xfsstats.xs_write_bytes,
+-                      xfsstats.xs_read_bytes);
++                      xs_xstrat_bytes, xs_write_bytes, xs_read_bytes);
+       len += sprintf(buffer + len, "debug %u\n",
+ #if defined(XFSDEBUG)
+               1);
+--- linux-2.6.0-test6/fs/xfs/linux/xfs_stats.h 2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/xfs/linux/xfs_stats.h        2003-10-05 00:33:24.000000000 -0700
+@@ -35,6 +35,8 @@
+ #if defined(CONFIG_PROC_FS) && !defined(XFS_STATS_OFF)
++#include <linux/percpu.h>
++
+ /*
+  * XFS global statistics
+  */
+@@ -126,11 +128,13 @@ struct xfsstats {
+       __uint64_t              xs_read_bytes;
+ };
+-extern struct xfsstats xfsstats;
++DECLARE_PER_CPU(struct xfsstats, xfsstats);
+-# define XFS_STATS_INC(count)         ( xfsstats.count++ )
+-# define XFS_STATS_DEC(count)         ( xfsstats.count-- )
+-# define XFS_STATS_ADD(count, inc)    ( xfsstats.count += (inc) )
++/* We don't disable preempt, not too worried about poking the
++ * wrong cpu's stat for now */
++#define XFS_STATS_INC(count)          (__get_cpu_var(xfsstats).count++)
++#define XFS_STATS_DEC(count)          (__get_cpu_var(xfsstats).count--)
++#define XFS_STATS_ADD(count, inc)     (__get_cpu_var(xfsstats).count += (inc))
+ extern void xfs_init_procfs(void);
+ extern void xfs_cleanup_procfs(void);
+--- linux-2.6.0-test6/fs/xfs/linux/xfs_super.c 2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/xfs/linux/xfs_super.c        2003-10-05 00:33:24.000000000 -0700
+@@ -315,8 +315,8 @@ xfs_setsize_buftarg(
+       if (set_blocksize(btp->pbr_bdev, sectorsize)) {
+               printk(KERN_WARNING
+-                      "XFS: Cannot set_blocksize to %u on device %u:%u\n",
+-                      sectorsize, MAJOR(btp->pbr_dev), MINOR(btp->pbr_dev));
++                      "XFS: Cannot set_blocksize to %u on device %s\n",
++                      sectorsize, XFS_BUFTARG_NAME(btp));
+       }
+ }
+--- linux-2.6.0-test6/fs/xfs/linux/xfs_sysctl.c        2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/xfs/linux/xfs_sysctl.c       2003-10-05 00:33:24.000000000 -0700
+@@ -48,17 +48,23 @@ xfs_stats_clear_proc_handler(
+       void            *buffer,
+       size_t          *lenp)
+ {
+-      int             ret, *valp = ctl->data;
++      int             c, ret, *valp = ctl->data;
+       __uint32_t      vn_active;
+       ret = proc_doulongvec_minmax(ctl, write, filp, buffer, lenp);
+       if (!ret && write && *valp) {
+               printk("XFS Clearing xfsstats\n");
+-              /* save vn_active, it's a universal truth! */
+-              vn_active = xfsstats.vn_active;
+-              memset(&xfsstats, 0, sizeof(xfsstats));
+-              xfsstats.vn_active = vn_active;
++              for (c = 0; c < NR_CPUS; c++) {
++                      if (!cpu_possible(c)) continue;
++                      preempt_disable();
++                      /* save vn_active, it's a universal truth! */
++                      vn_active = per_cpu(xfsstats, c).vn_active;
++                      memset(&per_cpu(xfsstats, c), 0,
++                             sizeof(struct xfsstats));
++                      per_cpu(xfsstats, c).vn_active = vn_active;
++                      preempt_enable();
++              }
+               xfs_stats_clear = 0;
+       }
+--- linux-2.6.0-test6/fs/xfs/linux/xfs_vnode.c 2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/xfs/linux/xfs_vnode.c        2003-10-05 00:33:24.000000000 -0700
+@@ -200,7 +200,7 @@ vn_revalidate(
+       vn_trace_entry(vp, "vn_revalidate", (inst_t *)__return_address);
+       ASSERT(vp->v_fbhv != NULL);
+-      va.va_mask = XFS_AT_STAT|XFS_AT_GENCOUNT;
++      va.va_mask = XFS_AT_STAT|XFS_AT_XFLAGS;
+       VOP_GETATTR(vp, &va, 0, NULL, error);
+       if (!error) {
+               inode = LINVFS_GET_IP(vp);
+--- linux-2.6.0-test6/fs/xfs/linux/xfs_vnode.h 2003-08-08 22:55:13.000000000 -0700
++++ 25/fs/xfs/linux/xfs_vnode.h        2003-10-05 00:33:24.000000000 -0700
+@@ -28,6 +28,37 @@
+  * For further information regarding this notice, see:
+  *
+  * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
++ *
++ * Portions Copyright (c) 1989, 1993
++ *      The Regents of the University of California.  All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. All advertising materials mentioning features or use of this software
++ *    must display the following acknowledgement:
++ *      This product includes software developed by the University of
++ *      California, Berkeley and its contributors.
++ * 4. Neither the name of the University nor the names of its contributors
++ *    may be used to endorse or promote products derived from this software
++ *    without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
+  */
+ #ifndef __XFS_VNODE_H__
+ #define __XFS_VNODE_H__
+@@ -39,19 +70,9 @@ struct page_buf_bmap_s;
+ struct attrlist_cursor_kern;
+ /*
+- * Vnode types (unrelated to on-disk inodes).  VNON means no type.
++ * Vnode types.  VNON means no type.
+  */
+-typedef enum vtype {
+-      VNON    = 0,
+-      VREG    = 1,
+-      VDIR    = 2,
+-      VBLK    = 3,
+-      VCHR    = 4,
+-      VLNK    = 5,
+-      VFIFO   = 6,
+-      VBAD    = 7,
+-      VSOCK   = 8
+-} vtype_t;
++enum vtype    { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VFIFO, VBAD, VSOCK };
+ typedef xfs_ino_t vnumber_t;
+ typedef struct dentry vname_t;
+@@ -115,14 +136,15 @@ typedef enum {
+ #define LINVFS_GET_IP(vp)     (&(vp)->v_inode)
+ /*
+- * Conversion between vnode types/modes and encoded type/mode as
+- * seen by stat(2) and mknod(2).
++ * Convert between vnode types and inode formats (since POSIX.1
++ * defines mode word of stat structure in terms of inode formats).
+  */
+-extern enum vtype       iftovt_tab[];
+-extern ushort           vttoif_tab[];
+-#define IFTOVT(M)       (iftovt_tab[((M) & S_IFMT) >> 12])
+-#define VTTOIF(T)       (vttoif_tab[(int)(T)])
+-#define MAKEIMODE(T, M)       (VTTOIF(T) | ((M) & ~S_IFMT))
++extern enum vtype     iftovt_tab[];
++extern u_short                vttoif_tab[];
++#define IFTOVT(mode)  (iftovt_tab[((mode) & S_IFMT) >> 12])
++#define VTTOIF(indx)  (vttoif_tab[(int)(indx)])
++#define MAKEIMODE(indx, mode) (int)(VTTOIF(indx) | (mode))
++
+ /*
+  * Vnode flags.
+@@ -370,31 +392,29 @@ typedef struct vnodeops {
+ /*
+  * Vnode attributes.  va_mask indicates those attributes the caller
+- * wants to set (setattr) or extract (getattr).
++ * wants to set or extract.
+  */
+ typedef struct vattr {
+-      int             va_mask;        /* bit-mask of attributes */
+-      vtype_t         va_type;        /* vnode type (for create) */
+-      mode_t          va_mode;        /* file access mode */
++      int             va_mask;        /* bit-mask of attributes present */
++      enum vtype      va_type;        /* vnode type (for create) */
++      mode_t          va_mode;        /* file access mode and type */
++      nlink_t         va_nlink;       /* number of references to file */
+       uid_t           va_uid;         /* owner user id */
+       gid_t           va_gid;         /* owner group id */
+-      xfs_dev_t       va_fsid;        /* file system id (dev for now) */
+-      xfs_ino_t       va_nodeid;      /* node id */
+-      nlink_t         va_nlink;       /* number of references to file */
++      xfs_ino_t       va_nodeid;      /* file id */
+       xfs_off_t       va_size;        /* file size in bytes */
+-      timespec_t      va_atime;       /* time of last access */
+-      timespec_t      va_mtime;       /* time of last modification */
+-      timespec_t      va_ctime;       /* time file ``created'' */
+-      xfs_dev_t       va_rdev;        /* device the file represents */
+-      u_long          va_blksize;     /* fundamental block size */
+-      __int64_t       va_nblocks;     /* # of blocks allocated */
+-      u_long          va_vcode;       /* version code */
++      u_long          va_blocksize;   /* blocksize preferred for i/o */
++      struct timespec va_atime;       /* time of last access */
++      struct timespec va_mtime;       /* time of last modification */
++      struct timespec va_ctime;       /* time file changed */
++      u_int           va_gen;         /* generation number of file */
++      xfs_dev_t       va_rdev;        /* device the special file represents */
++      __int64_t       va_nblocks;     /* number of blocks allocated */
+       u_long          va_xflags;      /* random extended file flags */
+       u_long          va_extsize;     /* file extent size */
+       u_long          va_nextents;    /* number of extents in file */
+       u_long          va_anextents;   /* number of attr extents in file */
+       int             va_projid;      /* project id */
+-      u_int           va_gencount;    /* object generation count */
+ } vattr_t;
+ /*
+@@ -450,11 +470,17 @@ typedef struct vattr {
+               XFS_AT_TYPE|XFS_AT_BLKSIZE|XFS_AT_NBLOCKS|XFS_AT_VCODE|\
+               XFS_AT_NEXTENTS|XFS_AT_ANEXTENTS|XFS_AT_GENCOUNT)
+-#define VREAD         00400
+-#define VWRITE                00200
+-#define VEXEC         00100
+-#define VSGID         02000           /* set group id on execution */
+-#define MODEMASK      07777           /* mode bits plus permission bits */
++/*
++ *  Modes.
++ */
++#define VSUID S_ISUID         /* set user id on execution */
++#define VSGID S_ISGID         /* set group id on execution */
++#define VSVTX S_ISVTX         /* save swapped text even after use */
++#define VREAD S_IRUSR         /* read, write, execute permissions */
++#define VWRITE        S_IWUSR
++#define VEXEC S_IXUSR
++
++#define MODEMASK S_IALLUGO    /* mode bits plus permission bits */
+ /*
+  * Check whether mandatory file locking is enabled.
+@@ -569,13 +595,9 @@ static __inline__ void vn_flagclr(struct
+  * Flags to VOP_SETATTR/VOP_GETATTR.
+  */
+ #define       ATTR_UTIME      0x01    /* non-default utime(2) request */
+-#define       ATTR_EXEC       0x02    /* invocation from exec(2) */
+-#define       ATTR_COMM       0x04    /* yield common vp attributes */
+ #define       ATTR_DMI        0x08    /* invocation from a DMI function */
+ #define       ATTR_LAZY       0x80    /* set/get attributes lazily */
+ #define       ATTR_NONBLOCK   0x100   /* return EAGAIN if operation would block */
+-#define ATTR_NOLOCK   0x200   /* Don't grab any conflicting locks */
+-#define ATTR_NOSIZETOK        0x400   /* Don't get the DVN_SIZE_READ token */
+ /*
+  * Flags to VOP_FSYNC and VOP_RECLAIM.
+--- linux-2.6.0-test6/fs/xfs/pagebuf/page_buf.c        2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/xfs/pagebuf/page_buf.c       2003-10-05 00:33:24.000000000 -0700
+@@ -141,7 +141,7 @@ pagebuf_param_t pb_params = {
+  * Pagebuf statistics variables
+  */
+-struct pbstats pbstats;
++DEFINE_PER_CPU(struct pbstats, pbstats);
+ /*
+  * Pagebuf allocation / freeing.
+@@ -293,7 +293,7 @@ _pagebuf_initialize(
+       atomic_set(&pb->pb_pin_count, 0);
+       init_waitqueue_head(&pb->pb_waiters);
+-      PB_STATS_INC(pbstats.pb_create);
++      PB_STATS_INC(pb_create);
+       PB_TRACE(pb, PB_TRACE_REC(get), target);
+ }
+@@ -485,7 +485,7 @@ _pagebuf_lookup_pages(
+                       page = find_or_create_page(aspace, index, gfp_mask);
+                       if (!page) {
+                               if (--retry_count > 0) {
+-                                      PB_STATS_INC(pbstats.pb_page_retries);
++                                      PB_STATS_INC(pb_page_retries);
+                                       pagebuf_daemon_wakeup(1);
+                                       current->state = TASK_UNINTERRUPTIBLE;
+                                       schedule_timeout(10);
+@@ -495,7 +495,7 @@ _pagebuf_lookup_pages(
+                               all_mapped = 0;
+                               continue;
+                       }
+-                      PB_STATS_INC(pbstats.pb_page_found);
++                      PB_STATS_INC(pb_page_found);
+                       mark_page_accessed(page);
+                       pb->pb_pages[pi] = page;
+               } else {
+@@ -645,7 +645,7 @@ _pagebuf_find(                             /* find buffer for blo
+               h->pb_count++;
+               list_add(&new_pb->pb_hash_list, &h->pb_hash);
+       } else {
+-              PB_STATS_INC(pbstats.pb_miss_locked);
++              PB_STATS_INC(pb_miss_locked);
+       }
+       spin_unlock(&h->pb_hash_lock);
+@@ -665,7 +665,7 @@ found:
+                       /* wait for buffer ownership */
+                       PB_TRACE(pb, PB_TRACE_REC(get_lk), 0);
+                       pagebuf_lock(pb);
+-                      PB_STATS_INC(pbstats.pb_get_locked_waited);
++                      PB_STATS_INC(pb_get_locked_waited);
+               } else {
+                       /* We asked for a trylock and failed, no need
+                        * to look at file offset and length here, we
+@@ -675,7 +675,7 @@ found:
+                        */
+                       pagebuf_rele(pb);
+-                      PB_STATS_INC(pbstats.pb_busy_locked);
++                      PB_STATS_INC(pb_busy_locked);
+                       return (NULL);
+               }
+       } else {
+@@ -691,7 +691,7 @@ found:
+                               _PBF_ADDR_ALLOCATED | \
+                               _PBF_MEM_ALLOCATED;
+       PB_TRACE(pb, PB_TRACE_REC(got_lk), 0);
+-      PB_STATS_INC(pbstats.pb_get_locked);
++      PB_STATS_INC(pb_get_locked);
+       return (pb);
+ }
+@@ -747,7 +747,7 @@ pagebuf_get(                               /* allocate a buffer            */
+                       return (NULL);
+       }
+-      PB_STATS_INC(pbstats.pb_get);
++      PB_STATS_INC(pb_get);
+       /* fill in any missing pages */
+       error = _pagebuf_lookup_pages(pb, pb->pb_target->pbr_mapping, flags);
+@@ -766,7 +766,7 @@ pagebuf_get(                               /* allocate a buffer            */
+       if (flags & PBF_READ) {
+               if (PBF_NOT_DONE(pb)) {
+                       PB_TRACE(pb, PB_TRACE_REC(get_read), flags);
+-                      PB_STATS_INC(pbstats.pb_get_read);
++                      PB_STATS_INC(pb_get_read);
+                       pagebuf_iostart(pb, flags);
+               } else if (flags & PBF_ASYNC) {
+                       /*
+@@ -1677,6 +1677,9 @@ pagebuf_daemon(
+                                       break;
+                               }
++                              pb->pb_flags &= ~PBF_DELWRI;
++                              pb->pb_flags |= PBF_WRITE;
++
+                               list_del(&pb->pb_list);
+                               list_add(&pb->pb_list, &tmp);
+@@ -1688,8 +1691,6 @@ pagebuf_daemon(
+               while (!list_empty(&tmp)) {
+                       pb = list_entry(tmp.next, page_buf_t, pb_list);
+                       list_del_init(&pb->pb_list);
+-                      pb->pb_flags &= ~PBF_DELWRI;
+-                      pb->pb_flags |= PBF_WRITE;
+                       pagebuf_iostrategy(pb);
+               }
+@@ -1720,6 +1721,7 @@ pagebuf_delwri_flush(
+       int                     flush_cnt = 0;
+       pagebuf_runall_queues(pagebuf_dataio_workqueue);
++      pagebuf_runall_queues(pagebuf_logio_workqueue);
+       spin_lock(&pbd_delwrite_lock);
+       INIT_LIST_HEAD(&tmp);
+@@ -1742,47 +1744,32 @@ pagebuf_delwri_flush(
+                       continue;
+               }
+-              if (flags & PBDF_TRYLOCK) {
+-                      if (!pagebuf_cond_lock(pb)) {
+-                              pincount++;
+-                              continue;
+-                      }
+-              }
+-
+-              list_del_init(&pb->pb_list);
+-              if (flags & PBDF_WAIT) {
+-                      list_add(&pb->pb_list, &tmp);
+-                      pb->pb_flags &= ~PBF_ASYNC;
+-              }
+-
+-              spin_unlock(&pbd_delwrite_lock);
+-
+-              if ((flags & PBDF_TRYLOCK) == 0) {
+-                      pagebuf_lock(pb);
+-              }
+-
+               pb->pb_flags &= ~PBF_DELWRI;
+               pb->pb_flags |= PBF_WRITE;
++              list_move(&pb->pb_list, &tmp);
++      }
++      /* ok found all the items that can be worked on 
++       * drop the lock and process the private list */
++      spin_unlock(&pbd_delwrite_lock);
++
++      list_for_each_safe(curr, next, &tmp) {
++              pb = list_entry(curr, page_buf_t, pb_list);
++
++              if (flags & PBDF_WAIT)
++                      pb->pb_flags &= ~PBF_ASYNC;
++              else
++                      list_del_init(curr);
++              pagebuf_lock(pb);
+               pagebuf_iostrategy(pb);
+               if (++flush_cnt > 32) {
+                       blk_run_queues();
+                       flush_cnt = 0;
+               }
+-
+-              spin_lock(&pbd_delwrite_lock);
+       }
+-      spin_unlock(&pbd_delwrite_lock);
+-
+       blk_run_queues();
+-      if (pinptr)
+-              *pinptr = pincount;
+-
+-      if ((flags & PBDF_WAIT) == 0)
+-              return;
+-
+       while (!list_empty(&tmp)) {
+               pb = list_entry(tmp.next, page_buf_t, pb_list);
+@@ -1792,6 +1779,9 @@ pagebuf_delwri_flush(
+                       pagebuf_unlock(pb);
+               pagebuf_rele(pb);
+       }
++
++      if (pinptr)
++              *pinptr = pincount;
+ }
+ STATIC int
+@@ -1846,14 +1836,18 @@ pb_stats_clear_handler(
+       void                    *buffer,
+       size_t                  *lenp)
+ {
+-      int                     ret;
++      int                     c, ret;
+       int                     *valp = ctl->data;
+       ret = proc_doulongvec_minmax(ctl, write, filp, buffer, lenp);
+       if (!ret && write && *valp) {
+               printk("XFS Clearing pbstats\n");
+-              memset(&pbstats, 0, sizeof(pbstats));
++              for (c = 0; c < NR_CPUS; c++) {
++                      if (!cpu_possible(c)) continue;
++                              memset(&per_cpu(pbstats, c), 0,
++                                     sizeof(struct pbstats));
++              }
+               pb_params.stats_clear.val = 0;
+       }
+@@ -1907,13 +1901,17 @@ pagebuf_readstats(
+       int                     *eof,
+       void                    *data)
+ {
+-      int                     i, len;
++      int                     c, i, len, val;
+       len = 0;
+       len += sprintf(buffer + len, "pagebuf");
+-      for (i = 0; i < sizeof(pbstats) / sizeof(u_int32_t); i++) {
+-              len += sprintf(buffer + len, " %u",
+-                      *(((u_int32_t*)&pbstats) + i));
++      for (i = 0; i < sizeof(struct pbstats) / sizeof(u_int32_t); i++) {
++              val = 0;
++              for (c = 0 ; c < NR_CPUS; c++) {
++                      if (!cpu_possible(c)) continue;
++                      val += *(((u_int32_t*)&per_cpu(pbstats, c) + i));
++              }
++              len += sprintf(buffer + len, " %u", val);
+       }
+       buffer[len++] = '\n';
+--- linux-2.6.0-test6/fs/xfs/pagebuf/page_buf.h        2003-08-22 19:23:42.000000000 -0700
++++ 25/fs/xfs/pagebuf/page_buf.h       2003-10-05 00:33:24.000000000 -0700
+@@ -136,9 +136,6 @@ typedef enum page_buf_flags_e {            /* pb_f
+ #define PBF_NOT_DONE(pb) (((pb)->pb_flags & (PBF_PARTIAL|PBF_NONE)) != 0)
+ #define PBF_DONE(pb) (((pb)->pb_flags & (PBF_PARTIAL|PBF_NONE)) == 0)
+-#define PBR_SECTOR_ONLY       1       /* only use sector size buffer heads */
+-#define PBR_ALIGNED_ONLY 2    /* only use aligned I/O */
+-
+ typedef struct pb_target {
+       dev_t                   pbr_dev;
+       struct block_device     *pbr_bdev;
+@@ -371,7 +368,6 @@ extern int pagebuf_ispin(          /* check if b
+ /* Delayed Write Buffer Routines */
+ #define PBDF_WAIT    0x01
+-#define PBDF_TRYLOCK 0x02
+ extern void pagebuf_delwri_flush(
+               pb_target_t *,
+               unsigned long,
+--- linux-2.6.0-test6/fs/xfs/pagebuf/page_buf_internal.h       2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/xfs/pagebuf/page_buf_internal.h      2003-10-05 00:33:24.000000000 -0700
+@@ -37,6 +37,7 @@
+ #ifndef __PAGE_BUF_PRIVATE_H__
+ #define __PAGE_BUF_PRIVATE_H__
++#include <linux/percpu.h>
+ #include "page_buf.h"
+ #define _PAGE_BUF_INTERNAL_
+@@ -120,9 +121,11 @@ struct pbstats {
+       u_int32_t       pb_get_read;
+ };
+-extern struct pbstats pbstats;
++DECLARE_PER_CPU(struct pbstats, pbstats);
+-#define PB_STATS_INC(count)   ( count ++ )
++/* We don't disable preempt, not too worried about poking the
++ * wrong cpu's stat for now */
++#define PB_STATS_INC(count)   (__get_cpu_var(pbstats).count++)
+ #ifndef STATIC
+ # define STATIC       static
+--- linux-2.6.0-test6/fs/xfs/quota/xfs_dquot.c 2003-06-14 12:18:09.000000000 -0700
++++ 25/fs/xfs/quota/xfs_dquot.c        2003-10-05 00:33:24.000000000 -0700
+@@ -87,9 +87,9 @@
+ STATIC void           xfs_qm_dqflush_done(xfs_buf_t *, xfs_dq_logitem_t *);
+ #ifdef DEBUG
+-dev_t xfs_dqerror_dev = 0;
+-int xfs_do_dqerror = 0;
+-int xfs_dqreq_num = 0;
++xfs_buftarg_t *xfs_dqerror_target;
++int xfs_do_dqerror;
++int xfs_dqreq_num;
+ int xfs_dqerror_mod = 33;
+ #endif
+@@ -911,7 +911,7 @@ xfs_qm_dqget(
+ #ifdef DEBUG
+       if (xfs_do_dqerror) {
+-              if ((xfs_dqerror_dev == mp->m_dev) &&
++              if ((xfs_dqerror_target == mp->m_ddev_targp) &&
+                   (xfs_dqreq_num++ % xfs_dqerror_mod) == 0) {
+                       cmn_err(CE_DEBUG, "Returning error in dqget");
+                       return (EIO);
+--- linux-2.6.0-test6/fs/xfs/quota/xfs_qm.h    2003-06-14 12:18:06.000000000 -0700
++++ 25/fs/xfs/quota/xfs_qm.h   2003-10-05 00:33:24.000000000 -0700
+@@ -165,9 +165,9 @@ typedef struct xfs_dquot_acct {
+  * Users are allowed to have a usage exceeding their softlimit for
+  * a period this long.
+  */
+-#define XFS_QM_BTIMELIMIT     DQ_BTIMELIMIT
+-#define XFS_QM_RTBTIMELIMIT   DQ_BTIMELIMIT
+-#define XFS_QM_ITIMELIMIT     DQ_FTIMELIMIT
++#define XFS_QM_BTIMELIMIT     (7 * 24*60*60)          /* 1 week */
++#define XFS_QM_RTBTIMELIMIT   (7 * 24*60*60)          /* 1 week */
++#define XFS_QM_ITIMELIMIT     (7 * 24*60*60)          /* 1 week */
+ #define XFS_QM_BWARNLIMIT     5
+ #define XFS_QM_IWARNLIMIT     5
+--- linux-2.6.0-test6/fs/xfs/support/move.c    2003-06-14 12:18:22.000000000 -0700
++++ 25/fs/xfs/support/move.c   2003-10-05 00:33:24.000000000 -0700
+@@ -38,57 +38,37 @@
+ #include "debug.h"
+ #include "move.h"
+-/*
+- * Move "n" bytes at byte address "cp"; "rw" indicates the direction
+- * of the move, and the I/O parameters are provided in "uio", which is
+- * update to reflect the data which was moved.  Returns 0 on success or
+- * a non-zero errno on failure.
++/* Read from kernel buffer at src to user/kernel buffer defined
++ * by the uio structure. Advance the pointer in the uio struct
++ * as we go.
+  */
+ int
+-uiomove(void *cp, size_t n, enum uio_rw rw, struct uio *uio)
++uio_read(caddr_t src, size_t len, struct uio *uio)
+ {
+-      register struct iovec *iov;
++      struct iovec *iov;
+       u_int cnt;
+       int error;
+-      while (n > 0 && uio->uio_resid) {
++      if (len > 0 && uio->uio_resid) {
+               iov = uio->uio_iov;
+               cnt = (u_int)iov->iov_len;
+-              if (cnt == 0) {
+-                      uio->uio_iov++;
+-                      uio->uio_iovcnt--;
+-                      continue;
+-              }
+-              if (cnt > n)
+-                      cnt = (u_int)n;
+-              switch (uio->uio_segflg) {
+-              case UIO_USERSPACE:
+-                      if (rw == UIO_READ)
+-                              error = copy_to_user(iov->iov_base, cp, cnt);
+-                      else
+-                              error = copy_from_user(cp, iov->iov_base, cnt);
++              if (cnt == 0)
++                      return 0;
++              if (cnt > len)
++                      cnt = (u_int)len;
++              if (uio->uio_segflg == UIO_USERSPACE) {
++                      error = copy_to_user(iov->iov_base, src, cnt);
+                       if (error)
+                               return EFAULT;
+-                      break;
+-
+-
+-              case UIO_SYSSPACE:
+-                      if (rw == UIO_READ)
+-                              memcpy(iov->iov_base, cp, cnt);
+-                      else
+-                              memcpy(cp, iov->iov_base, cnt);
+-                      break;
+-
+-              default:
++              } else if (uio->uio_segflg == UIO_SYSSPACE) {
++                      memcpy(iov->iov_base, src, cnt);
++              } else {
+                       ASSERT(0);
+-                      break;
+               }
+               iov->iov_base = (void *)((char *)iov->iov_base + cnt);
+               iov->iov_len -= cnt;
+               uio->uio_resid -= cnt;
+               uio->uio_offset += cnt;
+-              cp = (void *)((char *)cp + cnt);
+-              n -= cnt;
+       }
+       return 0;
+ }
+--- linux-2.6.0-test6/fs/xfs/support/move.h    2003-06-14 12:18:20.000000000 -0700
++++ 25/fs/xfs/support/move.h   2003-10-05 00:33:24.000000000 -0700
+@@ -48,11 +48,6 @@ typedef struct uio {
+ } uio_t;
+ /*
+- * I/O direction.
+- */
+-typedef enum uio_rw { UIO_READ, UIO_WRITE } uio_rw_t;
+-
+-/*
+  * Segment flag values.
+  */
+ typedef enum uio_seg {
+@@ -60,7 +55,6 @@ typedef enum uio_seg {
+       UIO_SYSSPACE,           /* uio_iov describes system space */
+ } uio_seg_t;
+-
+-extern int    uiomove (void *, size_t, uio_rw_t, uio_t *);
++extern int    uio_read (caddr_t, size_t, uio_t *);
+ #endif  /* __XFS_SUPPORT_MOVE_H__ */
+--- linux-2.6.0-test6/fs/xfs/xfs_attr_fetch.c  2003-06-14 12:18:25.000000000 -0700
++++ /dev/null  2002-08-30 16:31:37.000000000 -0700
+@@ -1,100 +0,0 @@
+-/*
+- * Copyright (c) 2000, 2002 Silicon Graphics, Inc.  All Rights Reserved.
+- *
+- * This program is free software; you can redistribute it and/or modify it
+- * under the terms of version 2 of the GNU General Public License as
+- * published by the Free Software Foundation.
+- *
+- * This program is distributed in the hope that it would be useful, but
+- * WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+- *
+- * Further, this software is distributed without any warranty that it is
+- * free of the rightful claim of any third person regarding infringement
+- * or the like.  Any license provided herein, whether implied or
+- * otherwise, applies only to this software file.  Patent licenses, if
+- * any, provided herein do not apply to combinations of this program with
+- * other software, or any other product whatsoever.
+- *
+- * You should have received a copy of the GNU General Public License along
+- * with this program; if not, write the Free Software Foundation, Inc., 59
+- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+- *
+- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+- * Mountain View, CA  94043, or:
+- *
+- * http://www.sgi.com
+- *
+- * For further information regarding this notice, see:
+- *
+- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+- */
+-
+-#include "xfs.h"
+-
+-#include "xfs_macros.h"
+-#include "xfs_types.h"
+-#include "xfs_inum.h"
+-#include "xfs_log.h"
+-#include "xfs_trans.h"
+-#include "xfs_sb.h"
+-#include "xfs_ag.h"
+-#include "xfs_dir.h"
+-#include "xfs_dir2.h"
+-#include "xfs_dmapi.h"
+-#include "xfs_mount.h"
+-#include "xfs_alloc_btree.h"
+-#include "xfs_bmap_btree.h"
+-#include "xfs_ialloc_btree.h"
+-#include "xfs_itable.h"
+-#include "xfs_btree.h"
+-#include "xfs_ialloc.h"
+-#include "xfs_alloc.h"
+-#include "xfs_attr_sf.h"
+-#include "xfs_dir_sf.h"
+-#include "xfs_dir2_sf.h"
+-#include "xfs_dinode.h"
+-#include "xfs_inode_item.h"
+-#include "xfs_inode.h"
+-#include "xfs_bmap.h"
+-#include "xfs_da_btree.h"
+-#include "xfs_attr.h"
+-#include "xfs_attr_leaf.h"
+-
+-int
+-xfs_attr_fetch(xfs_inode_t *ip, char *name, char *value, int valuelen)
+-{
+-      xfs_da_args_t args;
+-      int error;
+-
+-      if (XFS_IFORK_Q(ip) == 0)
+-              return ENOATTR;
+-      /*
+-       * Do the argument setup for the xfs_attr routines.
+-       */
+-      memset((char *)&args, 0, sizeof(args));
+-      args.dp = ip;
+-      args.flags = ATTR_ROOT;
+-      args.whichfork = XFS_ATTR_FORK;
+-      args.name = name;
+-      args.namelen = strlen(name);
+-      args.value = value;
+-      args.valuelen = valuelen;
+-      args.hashval = xfs_da_hashname(args.name, args.namelen);
+-      args.oknoent = 1;
+-
+-      /*
+-       * Decide on what work routines to call based on the inode size.
+-       */
+-      if (args.dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL)
+-              error = xfs_attr_shortform_getvalue(&args);
+-      else if (xfs_bmap_one_block(args.dp, XFS_ATTR_FORK))
+-              error = xfs_attr_leaf_get(&args);
+-      else
+-              error = xfs_attr_node_get(&args);
+-
+-      if (error == EEXIST)
+-              error = 0;
+-
+-      return(error);
+-}
+--- linux-2.6.0-test6/fs/xfs/xfs_bmap.c        2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/xfs/xfs_bmap.c       2003-10-05 00:33:24.000000000 -0700
+@@ -5553,7 +5553,7 @@ xfs_getbmap(
+           && DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ)
+           && whichfork == XFS_DATA_FORK) {
+-              error = XFS_SEND_DATA(mp, DM_EVENT_READ, bdp, 0, 0, 0, NULL);
++              error = XFS_SEND_DATA(mp, DM_EVENT_READ, vp, 0, 0, 0, NULL);
+               if (error)
+                       return XFS_ERROR(error);
+       }
+--- linux-2.6.0-test6/fs/xfs/xfs_buf.h 2003-08-22 19:23:42.000000000 -0700
++++ 25/fs/xfs/xfs_buf.h        2003-10-05 00:33:24.000000000 -0700
+@@ -194,7 +194,10 @@ extern inline xfs_caddr_t xfs_buf_offset
+       (bp)->pb_target = (target)
+ #define XFS_BUF_TARGET(bp)    ((bp)->pb_target)
+-#define XFS_BUF_TARGET_DEV(bp)        ((bp)->pb_target->pbr_dev)
++
++#define XFS_BUFTARG_NAME(target) \
++      ({ char __b[BDEVNAME_SIZE]; bdevname((target->pbr_bdev), __b); __b; })
++      
+ #define XFS_BUF_SET_VTYPE_REF(bp, type, ref)
+ #define XFS_BUF_SET_VTYPE(bp, type)
+ #define XFS_BUF_SET_REF(bp, ref)
+--- linux-2.6.0-test6/fs/xfs/xfs_buf_item.c    2003-06-14 12:17:56.000000000 -0700
++++ 25/fs/xfs/xfs_buf_item.c   2003-10-05 00:33:24.000000000 -0700
+@@ -1007,7 +1007,7 @@ xfs_buf_iodone_callbacks(
+ {
+       xfs_log_item_t  *lip;
+       static ulong    lasttime;
+-      static dev_t    lastdev;
++      static xfs_buftarg_t *lasttarg;
+       xfs_mount_t     *mp;
+       ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL);
+@@ -1045,15 +1045,15 @@ xfs_buf_iodone_callbacks(
+                       return;
+               }
+-              if ((XFS_BUF_TARGET_DEV(bp) != lastdev) ||
++              if ((XFS_BUF_TARGET(bp) != lasttarg) ||
+                   (time_after(jiffies, (lasttime + 5*HZ)))) {
+                       lasttime = jiffies;
+                       prdev("XFS write error in file system meta-data "
+                             "block 0x%Lx in %s",
+-                            XFS_BUF_TARGET_DEV(bp),
++                            XFS_BUF_TARGET(bp),
+                             XFS_BUF_ADDR(bp), mp->m_fsname);
+               }
+-              lastdev = XFS_BUF_TARGET_DEV(bp);
++              lasttarg = XFS_BUF_TARGET(bp);
+               if (XFS_BUF_ISASYNC(bp)) {
+                       /*
+--- linux-2.6.0-test6/fs/xfs/xfs_da_btree.c    2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/xfs/xfs_da_btree.c   2003-10-05 00:33:24.000000000 -0700
+@@ -2450,7 +2450,7 @@ xfs_da_buf_make(int nbuf, xfs_buf_t **bp
+       dabuf->dirty = 0;
+ #ifdef XFS_DABUF_DEBUG
+       dabuf->ra = ra;
+-      dabuf->dev = XFS_BUF_TARGET_DEV(bps[0]);
++      dabuf->target = XFS_BUF_TARGET(bps[0]);
+       dabuf->blkno = XFS_BUF_ADDR(bps[0]);
+ #endif
+       if (nbuf == 1) {
+@@ -2480,7 +2480,7 @@ xfs_da_buf_make(int nbuf, xfs_buf_t **bp
+               s = mutex_spinlock(&xfs_dabuf_global_lock);
+               for (p = xfs_dabuf_global_list; p; p = p->next) {
+                       ASSERT(p->blkno != dabuf->blkno ||
+-                             p->dev != dabuf->dev);
++                             p->target != dabuf->target);
+               }
+               dabuf->prev = NULL;
+               if (xfs_dabuf_global_list)
+--- linux-2.6.0-test6/fs/xfs/xfs_da_btree.h    2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/xfs/xfs_da_btree.h   2003-10-05 00:33:24.000000000 -0700
+@@ -212,7 +212,7 @@ typedef struct xfs_dabuf {
+       inst_t          *ra;            /* return address of caller to make */
+       struct xfs_dabuf *next;         /* next in global chain */
+       struct xfs_dabuf *prev;         /* previous in global chain */
+-      dev_t           dev;            /* device for buffer */
++      struct xfs_buftarg *target;     /* device for buffer */
+       xfs_daddr_t     blkno;          /* daddr first in bps[0] */
+ #endif
+       struct xfs_buf  *bps[1];        /* actually nbuf of these */
+--- linux-2.6.0-test6/fs/xfs/xfs_dinode.h      2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/xfs/xfs_dinode.h     2003-10-05 00:33:24.000000000 -0700
+@@ -439,25 +439,21 @@ void xfs_dfork_next_set(xfs_dinode_t *di
+ /*
+  * File types (mode field)
+  */
+-#define       IFMT            0170000         /* type of file */
+-#define       IFIFO           0010000         /* named pipe (fifo) */
+-#define       IFCHR           0020000         /* character special */
+-#define       IFDIR           0040000         /* directory */
+-#define       IFBLK           0060000         /* block special */
+-#define       IFREG           0100000         /* regular */
+-#define       IFLNK           0120000         /* symbolic link */
+-#define       IFSOCK          0140000         /* socket */
+-#define       IFMNT           0160000         /* mount point */
++#define       IFMT            S_IFMT
++#define       IFSOCK          S_IFSOCK
++#define       IFLNK           S_IFLNK
++#define       IFREG           S_IFREG
++#define       IFBLK           S_IFBLK
++#define       IFDIR           S_IFDIR
++#define       IFCHR           S_IFCHR
++#define       IFIFO           S_IFIFO
+-/*
+- * File execution and access modes.
+- */
+-#define       ISUID           04000           /* set user id on execution */
+-#define       ISGID           02000           /* set group id on execution */
+-#define       ISVTX           01000           /* sticky directory */
+-#define       IREAD           0400            /* read, write, execute permissions */
+-#define       IWRITE          0200
+-#define       IEXEC           0100
++#define       ISUID           S_ISUID
++#define       ISGID           S_ISGID
++#define       ISVTX           S_ISVTX
++#define       IREAD           S_IRUSR
++#define       IWRITE          S_IWUSR
++#define       IEXEC           S_IXUSR
+ #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_DINODE)
+ xfs_dinode_t *xfs_buf_to_dinode(struct xfs_buf *bp);
+--- linux-2.6.0-test6/fs/xfs/xfs_dir2.c        2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/xfs/xfs_dir2.c       2003-10-05 00:33:24.000000000 -0700
+@@ -773,7 +773,7 @@ xfs_dir2_put_dirent64_uio(
+       idbp->d_off = pa->cook;
+       idbp->d_name[namelen] = '\0';
+       memcpy(idbp->d_name, pa->name, namelen);
+-      rval = uiomove((caddr_t)idbp, reclen, UIO_READ, uio);
++      rval = uio_read((caddr_t)idbp, reclen, uio);
+       pa->done = (rval == 0);
+       return rval;
+ }
+--- linux-2.6.0-test6/fs/xfs/xfs_dir_leaf.c    2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/xfs/xfs_dir_leaf.c   2003-10-05 00:33:24.000000000 -0700
+@@ -2225,7 +2225,7 @@ xfs_dir_put_dirent64_uio(xfs_dir_put_arg
+       idbp->d_off = pa->cook.o;
+       idbp->d_name[namelen] = '\0';
+       memcpy(idbp->d_name, pa->name, namelen);
+-      retval = uiomove((caddr_t)idbp, reclen, UIO_READ, uio);
++      retval = uio_read((caddr_t)idbp, reclen, uio);
+       pa->done = (retval == 0);
+       return retval;
+ }
+--- linux-2.6.0-test6/fs/xfs/xfs_error.c       2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/xfs/xfs_error.c      2003-10-05 00:33:24.000000000 -0700
+@@ -329,6 +329,7 @@ xfs_corruption_error(
+       int             linenum,
+       inst_t          *ra)
+ {
+-      xfs_hex_dump(p, 16);
++      if (level <= xfs_error_level)
++              xfs_hex_dump(p, 16);
+       xfs_error_report(tag, level, mp, fname, linenum, ra);
+ }
+--- linux-2.6.0-test6/fs/xfs/xfs_error.h       2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/xfs/xfs_error.h      2003-10-05 00:33:24.000000000 -0700
+@@ -32,8 +32,8 @@
+ #ifndef       __XFS_ERROR_H__
+ #define       __XFS_ERROR_H__
+-#define prdev(fmt,dev,args...) \
+-      printk("XFS: device %u:%u- " fmt "\n", MAJOR(dev), MINOR(dev), ## args)
++#define prdev(fmt,targ,args...) \
++      printk("XFS: device %s- " fmt "\n", XFS_BUFTARG_NAME(targ), ## args)
+ #define XFS_ERECOVER  1       /* Failure to recover log */
+ #define XFS_ELOGSTAT  2       /* Failure to stat log in user space */
+--- linux-2.6.0-test6/fs/xfs/xfs_fs.h  2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/xfs/xfs_fs.h 2003-10-05 00:33:24.000000000 -0700
+@@ -392,22 +392,17 @@ typedef struct xfs_fsop_attrmulti_handle
+ } xfs_fsop_attrmulti_handlereq_t;
+ /*
+- * File system identifier. Should be unique (at least per machine).
++ * per machine unique filesystem identifier types.
+  */
+-typedef struct {
+-      __u32 val[2];                   /* file system id type */
+-} xfs_fsid_t;
++typedef struct { __u32 val[2]; } xfs_fsid_t; /* file system id type */
++
+-/*
+- * File identifier.  Should be unique per filesystem on a single machine.
+- * This is typically called by a stateless file server in order to generate
+- * "file handles".
+- */
+ #ifndef HAVE_FID
+ #define MAXFIDSZ      46
++
+ typedef struct fid {
+       __u16           fid_len;                /* length of data in bytes */
+-      unsigned char   fid_data[MAXFIDSZ];     /* data (variable length)  */
++      unsigned char   fid_data[MAXFIDSZ];     /* data (fid_len worth)  */
+ } fid_t;
+ #endif
+--- linux-2.6.0-test6/fs/xfs/xfsidbg.c 2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/xfs/xfsidbg.c        2003-10-05 00:33:24.000000000 -0700
+@@ -3739,9 +3739,9 @@ xfsidbg_xdabuf(xfs_dabuf_t *dabuf)
+               kdb_printf(" %d:0x%p", i, dabuf->bps[i]);
+       kdb_printf("\n");
+ #ifdef XFS_DABUF_DEBUG
+-      kdb_printf(" ra 0x%x prev 0x%x next 0x%x dev %u:%u blkno 0x%x\n",
++      kdb_printf(" ra 0x%x prev 0x%x next 0x%x dev %s blkno 0x%x\n",
+               dabuf->ra, dabuf->prev, dabuf->next,
+-              MAJOR(dabuf->dev), MINOR(dabuf->dev), dabuf->blkno);
++              XFS_BUFTARG_NAME(dabuf->dev), dabuf->blkno);
+ #endif
+ }
+@@ -4269,9 +4269,8 @@ xfsidbg_xlog(xlog_t *log)
+                       xfsidbg_get_cstate(log->l_covered_state));
+       kdb_printf("flags: ");
+       printflags(log->l_flags, t_flags,"log");
+-      kdb_printf("  dev: %u:%u logBBstart: %lld logsize: %d logBBsize: %d\n",
+-              MAJOR(log->l_dev), MINOR(log->l_dev),
+-              (long long) log->l_logBBstart,
++      kdb_printf("  dev: %s logBBstart: %lld logsize: %d logBBsize: %d\n",
++              XFS_BUFTARG_NAME(log->l_targ), (long long) log->l_logBBstart,
+               log->l_logsize,log->l_logBBsize);
+       kdb_printf("curr_cycle: %d  prev_cycle: %d  curr_block: %d  prev_block: %d\n",
+            log->l_curr_cycle, log->l_prev_cycle, log->l_curr_block,
+@@ -4646,14 +4645,14 @@ xfsidbg_xmount(xfs_mount_t *mp)
+               XFS_MTOVFS(mp), mp->m_tid, &mp->m_ail_lock, &mp->m_ail);
+       kdb_printf("ail_gen 0x%x &sb 0x%p\n",
+               mp->m_ail_gen, &mp->m_sb);
+-      kdb_printf("sb_lock 0x%p sb_bp 0x%p dev %u:%u logdev %u:%u rtdev %u:%u\n",
++      kdb_printf("sb_lock 0x%p sb_bp 0x%p dev %s logdev %s rtdev %s\n",
+               &mp->m_sb_lock, mp->m_sb_bp,
+-              mp->m_ddev_targp ? MAJOR(mp->m_ddev_targp->pbr_dev) : 0,
+-              mp->m_ddev_targp ? MINOR(mp->m_ddev_targp->pbr_dev) : 0,
+-              mp->m_logdev_targp ? MAJOR(mp->m_logdev_targp->pbr_dev) : 0,
+-              mp->m_logdev_targp ? MINOR(mp->m_logdev_targp->pbr_dev) : 0,
+-              mp->m_rtdev_targp ? MAJOR(mp->m_rtdev_targp->pbr_dev) : 0,
+-              mp->m_rtdev_targp ? MINOR(mp->m_rtdev_targp->pbr_dev) : 0);
++              mp->m_ddev_targp ?
++                      XFS_BUFTARG_NAME(mp->m_ddev_targp) : "none",
++              mp->m_logdev_targp ?
++                      XFS_BUFTARG_NAME(mp->m_logdev_targp) : "none",
++              mp->m_rtdev_targp ?
++                      XFS_BUFTARG_NAME(mp->m_rtdev_targp) : "none");
+       kdb_printf("bsize %d agfrotor %d agirotor %d ihash 0x%p ihsize %d\n",
+               mp->m_bsize, mp->m_agfrotor, mp->m_agirotor,
+               mp->m_ihash, mp->m_ihsize);
+@@ -4824,9 +4823,8 @@ xfsidbg_xnode(xfs_inode_t *ip)
+               ip->i_mnext,
+               ip->i_mprev,
+               XFS_ITOV_NULL(ip));
+-      kdb_printf("dev %u:%u ino %s\n",
+-              MAJOR(ip->i_mount->m_dev),
+-              MINOR(ip->i_mount->m_dev),
++      kdb_printf("dev %s ino %s\n",
++              XFS_BUFTARG_NAME(ip->i_mount->m_ddev_targp),
+               xfs_fmtino(ip->i_ino, ip->i_mount));
+       kdb_printf("blkno 0x%llx len 0x%x boffset 0x%x\n",
+               (long long) ip->i_blkno,
+--- linux-2.6.0-test6/fs/xfs/xfs_inode.c       2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/xfs/xfs_inode.c      2003-10-05 00:33:24.000000000 -0700
+@@ -408,8 +408,9 @@ xfs_itobp(
+               if (unlikely(XFS_TEST_ERROR(!di_ok, mp, XFS_ERRTAG_ITOBP_INOTOBP,
+                                XFS_RANDOM_ITOBP_INOTOBP))) {
+ #ifdef DEBUG
+-                      prdev("bad inode magic/vsn daddr 0x%llx #%d (magic=%x)",
+-                              mp->m_dev, (unsigned long long)imap.im_blkno, i,
++                      prdev("bad inode magic/vsn daddr %lld #%d (magic=%x)",
++                              mp->m_ddev_targp,
++                              (unsigned long long)imap.im_blkno, i,
+                               INT_GET(dip->di_core.di_magic, ARCH_CONVERT));
+ #endif
+                       XFS_CORRUPTION_ERROR("xfs_itobp", XFS_ERRLEVEL_HIGH,
+--- linux-2.6.0-test6/fs/xfs/xfs_log.c 2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/xfs/xfs_log.c        2003-10-05 00:33:24.000000000 -0700
+@@ -65,7 +65,7 @@ STATIC int    xlog_bdstrat_cb(struct xfs_b
+ STATIC int     xlog_commit_record(xfs_mount_t *mp, xlog_ticket_t *ticket,
+                                   xlog_in_core_t **, xfs_lsn_t *);
+ STATIC xlog_t *  xlog_alloc_log(xfs_mount_t   *mp,
+-                              dev_t           log_dev,
++                              xfs_buftarg_t   *log_target,
+                               xfs_daddr_t     blk_offset,
+                               int             num_bblks);
+ STATIC int     xlog_space_left(xlog_t *log, int cycle, int bytes);
+@@ -155,7 +155,7 @@ int xlog_error_mod = 33;
+  */
+ #if defined(XLOG_NOLOG) || defined(DEBUG)
+ int   xlog_debug = 1;
+-dev_t xlog_devt  = 0;
++xfs_buftarg_t *xlog_target;
+ #endif
+ #if defined(XFS_LOG_TRACE)
+@@ -274,7 +274,7 @@ xfs_log_done(xfs_mount_t   *mp,
+       xfs_lsn_t       lsn     = 0;
+ #if defined(DEBUG) || defined(XLOG_NOLOG)
+-      if (! xlog_debug && xlog_devt == log->l_dev)
++      if (!xlog_debug && xlog_target == log->l_targ)
+               return 0;
+ #endif
+@@ -339,7 +339,7 @@ xfs_log_force(xfs_mount_t *mp,
+       xlog_t *log = mp->m_log;
+ #if defined(DEBUG) || defined(XLOG_NOLOG)
+-      if (! xlog_debug && xlog_devt == log->l_dev)
++      if (!xlog_debug && xlog_target == log->l_targ)
+               return 0;
+ #endif
+@@ -378,7 +378,7 @@ xfs_log_notify(xfs_mount_t   *mp,          /* mo
+       int     abortflg, spl;
+ #if defined(DEBUG) || defined(XLOG_NOLOG)
+-      if (! xlog_debug && xlog_devt == log->l_dev)
++      if (!xlog_debug && xlog_target == log->l_targ)
+               return 0;
+ #endif
+       cb->cb_next = 0;
+@@ -436,7 +436,7 @@ xfs_log_reserve(xfs_mount_t         *mp,
+       int             retval;
+ #if defined(DEBUG) || defined(XLOG_NOLOG)
+-      if (! xlog_debug && xlog_devt == log->l_dev)
++      if (!xlog_debug && xlog_target == log->l_targ)
+               return 0;
+ #endif
+       retval = 0;
+@@ -472,7 +472,7 @@ xfs_log_reserve(xfs_mount_t         *mp,
+  * Mount a log filesystem
+  *
+  * mp         - ubiquitous xfs mount point structure
+- * log_dev    - device number of on-disk log device
++ * log_target - buftarg of on-disk log device
+  * blk_offset - Start block # where block size is 512 bytes (BBSIZE)
+  * num_bblocks        - Number of BBSIZE blocks in on-disk log
+  *
+@@ -480,7 +480,7 @@ xfs_log_reserve(xfs_mount_t         *mp,
+  */
+ int
+ xfs_log_mount(xfs_mount_t     *mp,
+-            dev_t             log_dev,
++            xfs_buftarg_t     *log_target,
+             xfs_daddr_t       blk_offset,
+             int               num_bblks)
+ {
+@@ -493,12 +493,11 @@ xfs_log_mount(xfs_mount_t        *mp,
+               ASSERT(XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY);
+       }
+-      mp->m_log = xlog_alloc_log(mp, log_dev, blk_offset, num_bblks);
++      mp->m_log = xlog_alloc_log(mp, log_target, blk_offset, num_bblks);
+ #if defined(DEBUG) || defined(XLOG_NOLOG)
+-      if (! xlog_debug) {
+-              cmn_err(CE_NOTE, "log dev: %u:%u",
+-                      MAJOR(log_dev), MINOR(log_dev));
++      if (!xlog_debug) {
++              cmn_err(CE_NOTE, "log dev: %s", XFS_BUFTARG_NAME(log_target));
+               return 0;
+       }
+ #endif
+@@ -606,7 +605,7 @@ xfs_log_unmount_write(xfs_mount_t *mp)
+       } magic = { XLOG_UNMOUNT_TYPE, 0, 0 };
+ #if defined(DEBUG) || defined(XLOG_NOLOG)
+-      if (! xlog_debug && xlog_devt == log->l_dev)
++      if (!xlog_debug && xlog_target == log->l_targ)
+               return 0;
+ #endif
+@@ -734,9 +733,9 @@ xfs_log_write(xfs_mount_t *        mp,
+ {
+       int     error;
+       xlog_t *log = mp->m_log;
+-#if defined(DEBUG) || defined(XLOG_NOLOG)
+-      if (! xlog_debug && xlog_devt == log->l_dev) {
++#if defined(DEBUG) || defined(XLOG_NOLOG)
++      if (!xlog_debug && xlog_target == log->l_targ) {
+               *start_lsn = 0;
+               return 0;
+       }
+@@ -761,7 +760,7 @@ xfs_log_move_tail(xfs_mount_t      *mp,
+       SPLDECL(s);
+ #if defined(DEBUG) || defined(XLOG_NOLOG)
+-      if (!xlog_debug && xlog_devt == log->l_dev)
++      if (!xlog_debug && xlog_target == log->l_targ)
+               return;
+ #endif
+       /* XXXsup tmp */
+@@ -1059,14 +1058,14 @@ xlog_get_iclog_buffer_size(xfs_mount_t *
+       /*
+        * When logbufs == 0, someone has disabled the log from the FSTAB
+        * file.  This is not a documented feature.  We need to set xlog_debug
+-       * to zero (this deactivates the log) and set xlog_devt to the
++       * to zero (this deactivates the log) and set xlog_target to the
+        * appropriate dev_t.  Only one filesystem may be affected as such
+        * since this is just a performance hack to test what we might be able
+        * to get if the log were not present.
+        */
+       if (mp->m_logbufs == 0) {
+               xlog_debug = 0;
+-              xlog_devt = log->l_dev;
++              xlog_target = log->l_targ;
+               log->l_iclog_bufs = XLOG_MIN_ICLOGS;
+       } else
+ #endif
+@@ -1089,8 +1088,8 @@ xlog_get_iclog_buffer_size(xfs_mount_t   *
+ #if defined(DEBUG) || defined(XLOG_NOLOG)
+               /* We are reactivating a filesystem after it was active */
+-              if (log->l_dev == xlog_devt) {
+-                      xlog_devt = 1;
++              if (log->l_targ == xlog_target) {
++                      xlog_target = 1; /* XXX(hch): WTF? */
+                       xlog_debug = 1;
+               }
+ #endif
+@@ -1176,7 +1175,7 @@ xlog_get_iclog_buffer_size(xfs_mount_t   *
+  */
+ STATIC xlog_t *
+ xlog_alloc_log(xfs_mount_t    *mp,
+-             dev_t            log_dev,
++             xfs_buftarg_t    *log_target,
+              xfs_daddr_t      blk_offset,
+              int              num_bblks)
+ {
+@@ -1191,7 +1190,7 @@ xlog_alloc_log(xfs_mount_t       *mp,
+       log = (xlog_t *)kmem_zalloc(sizeof(xlog_t), KM_SLEEP);
+       log->l_mp          = mp;
+-      log->l_dev         = log_dev;
++      log->l_targ        = log_target;
+       log->l_logsize     = BBTOB(num_bblks);
+       log->l_logBBstart  = blk_offset;
+       log->l_logBBsize   = num_bblks;
+--- linux-2.6.0-test6/fs/xfs/xfs_log.h 2003-06-14 12:18:52.000000000 -0700
++++ 25/fs/xfs/xfs_log.h        2003-10-05 00:33:24.000000000 -0700
+@@ -153,10 +153,10 @@ xfs_lsn_t xfs_log_done(struct xfs_mount 
+ int     xfs_log_force(struct xfs_mount *mp,
+                       xfs_lsn_t        lsn,
+                       uint             flags);
+-int     xfs_log_mount(struct xfs_mount *mp,
+-                      dev_t            log_dev,
+-                      xfs_daddr_t              start_block,
+-                      int              num_bblocks);
++int     xfs_log_mount(struct xfs_mount        *mp,
++                      struct xfs_buftarg      *log_target,
++                      xfs_daddr_t             start_block,
++                      int                     num_bblocks);
+ int     xfs_log_mount_finish(struct xfs_mount *mp, int);
+ void    xfs_log_move_tail(struct xfs_mount    *mp,
+                           xfs_lsn_t           tail_lsn);
+--- linux-2.6.0-test6/fs/xfs/xfs_log_priv.h    2003-08-08 22:55:13.000000000 -0700
++++ 25/fs/xfs/xfs_log_priv.h   2003-10-05 00:33:24.000000000 -0700
+@@ -504,7 +504,7 @@ typedef struct log {
+       struct xfs_mount        *l_mp;          /* mount point */
+       struct xfs_buf          *l_xbuf;        /* extra buffer for log
+                                                * wrapping */
+-      dev_t                   l_dev;          /* dev_t of log */
++      struct xfs_buftarg      *l_targ;        /* buftarg of log */
+       xfs_daddr_t             l_logBBstart;   /* start block of log */
+       int                     l_logsize;      /* size of log in bytes */
+       int                     l_logBBsize;    /* size of log in BB chunks */
+--- linux-2.6.0-test6/fs/xfs/xfs_log_recover.c 2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/xfs/xfs_log_recover.c        2003-10-05 00:33:24.000000000 -0700
+@@ -2179,8 +2179,8 @@ xlog_recover_do_buffer_trans(
+               break;
+       default:
+               xfs_fs_cmn_err(CE_ALERT, log->l_mp,
+-                      "xfs_log_recover: unknown buffer type 0x%x, dev %u:%u",
+-                      buf_f->blf_type, MAJOR(log->l_dev), MINOR(log->l_dev));
++                      "xfs_log_recover: unknown buffer type 0x%x, dev %s",
++                      buf_f->blf_type, XFS_BUFTARG_NAME(log->l_targ));
+               XFS_ERROR_REPORT("xlog_recover_do_buffer_trans",
+                                XFS_ERRLEVEL_LOW, log->l_mp);
+               return XFS_ERROR(EFSCORRUPTED);
+@@ -3889,9 +3889,8 @@ xlog_recover(
+               }
+               cmn_err(CE_NOTE,
+-                      "Starting XFS recovery on filesystem: %s (dev: %d/%d)",
+-                      log->l_mp->m_fsname, MAJOR(log->l_dev),
+-                      MINOR(log->l_dev));
++                      "Starting XFS recovery on filesystem: %s (dev: %s)",
++                      log->l_mp->m_fsname, XFS_BUFTARG_NAME(log->l_targ));
+               error = xlog_do_recover(log, head_blk, tail_blk);
+               log->l_flags |= XLOG_RECOVERY_NEEDED;
+@@ -3939,10 +3938,8 @@ xlog_recover_finish(
+               xlog_recover_check_summary(log);
+               cmn_err(CE_NOTE,
+-                      "Ending XFS recovery on filesystem: %s (dev: %d/%d)",
+-                      log->l_mp->m_fsname, MAJOR(log->l_dev),
+-                      MINOR(log->l_dev));
+-
++                      "Ending XFS recovery on filesystem: %s (dev: %s)",
++                      log->l_mp->m_fsname, XFS_BUFTARG_NAME(log->l_targ));
+               log->l_flags &= ~XLOG_RECOVERY_NEEDED;
+       } else {
+               cmn_err(CE_DEBUG,
+--- linux-2.6.0-test6/fs/xfs/xfs_mount.c       2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/xfs/xfs_mount.c      2003-10-05 00:33:24.000000000 -0700
+@@ -285,9 +285,9 @@ xfs_mount_validate_sb(
+ #if !XFS_BIG_BLKNOS
+       if (unlikely(
+           (sbp->sb_dblocks << (__uint64_t)(sbp->sb_blocklog - BBSHIFT))
+-              > INT_MAX ||
++              > UINT_MAX ||
+           (sbp->sb_rblocks << (__uint64_t)(sbp->sb_blocklog - BBSHIFT))
+-              > INT_MAX)) {
++              > UINT_MAX)) {
+               cmn_err(CE_WARN,
+       "XFS: File system is too large to be mounted on this system.");
+               return XFS_ERROR(E2BIG);
+@@ -949,7 +949,7 @@ xfs_mountfs(
+        * log's mount-time initialization. Perform 1st part recovery if needed
+        */
+       if (likely(sbp->sb_logblocks > 0)) {    /* check for volume case */
+-              error = xfs_log_mount(mp, mp->m_logdev_targp->pbr_dev,
++              error = xfs_log_mount(mp, mp->m_logdev_targp,
+                                     XFS_FSB_TO_DADDR(mp, sbp->sb_logstart),
+                                     XFS_FSB_TO_BB(mp, sbp->sb_logblocks));
+               if (error) {
+@@ -980,7 +980,7 @@ xfs_mountfs(
+       if (unlikely((rip->i_d.di_mode & IFMT) != IFDIR)) {
+               cmn_err(CE_WARN, "XFS: corrupted root inode");
+               prdev("Root inode %llu is not a directory",
+-                    mp->m_dev, (unsigned long long)rip->i_ino);
++                    mp->m_ddev_targp, (unsigned long long)rip->i_ino);
+               xfs_iunlock(rip, XFS_ILOCK_EXCL);
+               XFS_ERROR_REPORT("xfs_mountfs_int(2)", XFS_ERRLEVEL_LOW,
+                                mp);
+--- linux-2.6.0-test6/fs/xfs/xfs_mount.h       2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/xfs/xfs_mount.h      2003-10-05 00:33:24.000000000 -0700
+@@ -91,10 +91,10 @@ struct xfs_bmap_free;
+  * Prototypes and functions for the Data Migration subsystem.
+  */
+-typedef int   (*xfs_send_data_t)(int, struct bhv_desc *,
++typedef int   (*xfs_send_data_t)(int, struct vnode *,
+                       xfs_off_t, size_t, int, vrwlock_t *);
+ typedef int   (*xfs_send_mmap_t)(struct vm_area_struct *, uint);
+-typedef int   (*xfs_send_destroy_t)(struct bhv_desc *, dm_right_t);
++typedef int   (*xfs_send_destroy_t)(struct vnode *, dm_right_t);
+ typedef int   (*xfs_send_namesp_t)(dm_eventtype_t, struct vnode *,
+                       dm_right_t, struct vnode *, dm_right_t,
+                       char *, char *, mode_t, int, int);
+@@ -109,12 +109,12 @@ typedef struct xfs_dmops {
+       xfs_send_unmount_t      xfs_send_unmount;
+ } xfs_dmops_t;
+-#define XFS_SEND_DATA(mp, ev,bdp,off,len,fl,lock) \
+-      (*(mp)->m_dm_ops.xfs_send_data)(ev,bdp,off,len,fl,lock)
++#define XFS_SEND_DATA(mp, ev,vp,off,len,fl,lock) \
++      (*(mp)->m_dm_ops.xfs_send_data)(ev,vp,off,len,fl,lock)
+ #define XFS_SEND_MMAP(mp, vma,fl) \
+       (*(mp)->m_dm_ops.xfs_send_mmap)(vma,fl)
+-#define XFS_SEND_DESTROY(mp, bdp,right) \
+-      (*(mp)->m_dm_ops.xfs_send_destroy)(bdp,right)
++#define XFS_SEND_DESTROY(mp, vp,right) \
++      (*(mp)->m_dm_ops.xfs_send_destroy)(vp,right)
+ #define XFS_SEND_NAMESP(mp, ev,b1,r1,b2,r2,n1,n2,mode,rval,fl) \
+       (*(mp)->m_dm_ops.xfs_send_namesp)(ev,b1,r1,b2,r2,n1,n2,mode,rval,fl)
+ #define XFS_SEND_UNMOUNT(mp, vfsp,vp,right,mode,rval,fl) \
+--- linux-2.6.0-test6/fs/xfs/xfs_rw.c  2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/xfs/xfs_rw.c 2003-10-05 00:33:24.000000000 -0700
+@@ -260,11 +260,10 @@ xfs_ioerror_alert(
+       xfs_daddr_t             blkno)
+ {
+       cmn_err(CE_ALERT,
+- "I/O error in filesystem (\"%s\") meta-data dev %u:%u block 0x%llx"
++ "I/O error in filesystem (\"%s\") meta-data dev %s block 0x%llx"
+  "       (\"%s\") error %d buf count %u",
+               (!mp || !mp->m_fsname) ? "(fs name not set)" : mp->m_fsname,
+-              MAJOR(XFS_BUF_TARGET_DEV(bp)),
+-              MINOR(XFS_BUF_TARGET_DEV(bp)),
++              XFS_BUFTARG_NAME(bp->pb_target),
+               (__uint64_t)blkno,
+               func,
+               XFS_BUF_GETERROR(bp),
+--- linux-2.6.0-test6/fs/xfs/xfs_trans_buf.c   2003-06-14 12:17:57.000000000 -0700
++++ 25/fs/xfs/xfs_trans_buf.c  2003-10-05 00:33:24.000000000 -0700
+@@ -264,7 +264,7 @@ xfs_trans_getsb(xfs_trans_t        *tp,
+ }
+ #ifdef DEBUG
+-dev_t xfs_error_dev = 0;
++xfs_buftarg_t *xfs_error_target;
+ int   xfs_do_error;
+ int   xfs_req_num;
+ int   xfs_error_mod = 33;
+@@ -322,7 +322,7 @@ xfs_trans_read_buf(
+               }
+ #ifdef DEBUG
+               if (xfs_do_error && (bp != NULL)) {
+-                      if (xfs_error_dev == target->pbr_dev) {
++                      if (xfs_error_target == target) {
+                               if (((xfs_req_num++) % xfs_error_mod) == 0) {
+                                       xfs_buf_relse(bp);
+                                       printk("Returning error!\n");
+@@ -425,7 +425,7 @@ xfs_trans_read_buf(
+       }
+ #ifdef DEBUG
+       if (xfs_do_error && !(tp->t_flags & XFS_TRANS_DIRTY)) {
+-              if (xfs_error_dev == target->pbr_dev) {
++              if (xfs_error_target == target) {
+                       if (((xfs_req_num++) % xfs_error_mod) == 0) {
+                               xfs_force_shutdown(tp->t_mountp,
+                                                  XFS_METADATA_IO_ERROR);
+--- linux-2.6.0-test6/fs/xfs/xfs_trans.h       2003-08-08 22:55:13.000000000 -0700
++++ 25/fs/xfs/xfs_trans.h      2003-10-05 00:33:24.000000000 -0700
+@@ -995,7 +995,6 @@ void               xfs_trans_dquot_buf(xfs_trans_t *,
+ void          xfs_trans_inode_alloc_buf(xfs_trans_t *, struct xfs_buf *);
+ int           xfs_trans_iget(struct xfs_mount *, xfs_trans_t *,
+                              xfs_ino_t , uint, struct xfs_inode **);
+-void          xfs_trans_iput(xfs_trans_t *, struct xfs_inode *, uint);
+ void          xfs_trans_ijoin(xfs_trans_t *, struct xfs_inode *, uint);
+ void          xfs_trans_ihold(xfs_trans_t *, struct xfs_inode *);
+ void          xfs_trans_ihold_release(xfs_trans_t *, struct xfs_inode *);
+--- linux-2.6.0-test6/fs/xfs/xfs_trans_inode.c 2003-06-14 12:17:56.000000000 -0700
++++ 25/fs/xfs/xfs_trans_inode.c        2003-10-05 00:33:24.000000000 -0700
+@@ -188,106 +188,6 @@ xfs_trans_iget(
+ /*
+- * Release the inode ip which was previously acquired with xfs_trans_iget()
+- * or added with xfs_trans_ijoin(). This will decrement the lock
+- * recursion count of the inode item.  If the count goes to less than 0,
+- * the inode will be unlocked and disassociated from the transaction.
+- *
+- * If the inode has been modified within the transaction, it will not be
+- * unlocked until the transaction commits.
+- */
+-void
+-xfs_trans_iput(
+-      xfs_trans_t     *tp,
+-      xfs_inode_t     *ip,
+-      uint            lock_flags)
+-{
+-      xfs_inode_log_item_t    *iip;
+-      xfs_log_item_desc_t     *lidp;
+-
+-      /*
+-       * If the transaction pointer is NULL, just call xfs_iput().
+-       */
+-      if (tp == NULL) {
+-              xfs_iput(ip, lock_flags);
+-      }
+-
+-      ASSERT(ip->i_transp == tp);
+-      iip = ip->i_itemp;
+-      ASSERT(iip != NULL);
+-
+-      /*
+-       * Find the item descriptor pointing to this inode's
+-       * log item.  It must be there.
+-       */
+-      lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)iip);
+-      ASSERT(lidp != NULL);
+-      ASSERT(lidp->lid_item == (xfs_log_item_t*)iip);
+-
+-      /*
+-       * Be consistent about the bookkeeping for the inode's
+-       * io lock, but it doesn't mean much really.
+-       */
+-      ASSERT((iip->ili_flags & XFS_ILI_IOLOCKED_ANY) != XFS_ILI_IOLOCKED_ANY);
+-      if (lock_flags & (XFS_IOLOCK_EXCL | XFS_IOLOCK_SHARED)) {
+-              ASSERT(iip->ili_flags & XFS_ILI_IOLOCKED_ANY);
+-              ASSERT((!(lock_flags & XFS_IOLOCK_EXCL)) ||
+-                     (iip->ili_flags & XFS_ILI_IOLOCKED_EXCL));
+-              ASSERT((!(lock_flags & XFS_IOLOCK_SHARED)) ||
+-                     (iip->ili_flags &
+-                      (XFS_ILI_IOLOCKED_EXCL | XFS_ILI_IOLOCKED_SHARED)));
+-              if (iip->ili_iolock_recur > 0) {
+-                      iip->ili_iolock_recur--;
+-              }
+-      }
+-
+-      /*
+-       * If the release is just for a recursive lock on the inode lock,
+-       * then decrement the count and return.  We can assert that
+-       * the caller is dropping an EXCL lock on the inode, because
+-       * inode must be locked EXCL within transactions.
+-       */
+-      ASSERT(lock_flags & XFS_ILOCK_EXCL);
+-      if (iip->ili_ilock_recur > 0) {
+-              iip->ili_ilock_recur--;
+-              return;
+-      }
+-      ASSERT(iip->ili_iolock_recur == 0);
+-
+-      /*
+-       * If the inode was dirtied within this transaction, it cannot
+-       * be released until the transaction commits.
+-       */
+-      if (lidp->lid_flags & XFS_LID_DIRTY) {
+-              return;
+-      }
+-
+-      xfs_trans_free_item(tp, lidp);
+-
+-      /*
+-       * Clear the hold and iolocked flags in the inode log item.
+-       * We wouldn't want the next user of the inode to
+-       * get confused.  Assert that if the iolocked flag is set
+-       * in the item then we are unlocking it in the call to xfs_iput()
+-       * below.
+-       */
+-      ASSERT((!(iip->ili_flags & XFS_ILI_IOLOCKED_ANY)) ||
+-             (lock_flags & (XFS_IOLOCK_EXCL | XFS_IOLOCK_SHARED)));
+-      if (iip->ili_flags & (XFS_ILI_HOLD | XFS_ILI_IOLOCKED_ANY)) {
+-              iip->ili_flags &= ~(XFS_ILI_HOLD | XFS_ILI_IOLOCKED_ANY);
+-      }
+-
+-      /*
+-       * Unlike xfs_brelse() the inode log item cannot be
+-       * freed, because it is embedded within the inode.
+-       * All we have to do is release the inode.
+-       */
+-      xfs_iput(ip, lock_flags);
+-      return;
+-}
+-
+-
+-/*
+  * Add the locked inode to the transaction.
+  * The inode must be locked, and it cannot be associated with any
+  * transaction.  The caller must specify the locks already held
+--- linux-2.6.0-test6/fs/xfs/xfs_types.h       2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/xfs/xfs_types.h      2003-10-05 00:33:24.000000000 -0700
+@@ -83,7 +83,7 @@ typedef __uint64_t __psunsigned_t;
+  * XFS_BIG_INUMS needs the VFS inode number to be 64 bits, as well
+  * as requiring XFS_BIG_BLKNOS to be set.
+  */
+-#if defined(CONFIG_LBD) || (defined(HAVE_SECTOR_T) && (BITS_PER_LONG == 64))
++#if defined(CONFIG_LBD) || (BITS_PER_LONG == 64)
+ # define XFS_BIG_BLKNOS       1
+ # if BITS_PER_LONG == 64
+ #  define XFS_BIG_INUMS       1
+--- linux-2.6.0-test6/fs/xfs/xfs_vfsops.c      2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/xfs/xfs_vfsops.c     2003-10-05 00:33:24.000000000 -0700
+@@ -1776,7 +1776,6 @@ xfs_showargs(
+       };
+       struct proc_xfs_info    *xfs_infop;
+       struct xfs_mount        *mp = XFS_BHVTOM(bhv);
+-      char                    b[BDEVNAME_SIZE];
+       for (xfs_infop = xfs_info; xfs_infop->flag; xfs_infop++) {
+               if (mp->m_flags & xfs_infop->flag)
+@@ -1792,14 +1791,13 @@ xfs_showargs(
+       if (mp->m_logbsize > 0)
+               seq_printf(m, "," MNTOPT_LOGBSIZE "=%d", mp->m_logbsize);
+-      if (mp->m_ddev_targp->pbr_dev != mp->m_logdev_targp->pbr_dev)
++      if (mp->m_ddev_targp != mp->m_logdev_targp)
+               seq_printf(m, "," MNTOPT_LOGDEV "=%s",
+-                              bdevname(mp->m_logdev_targp->pbr_bdev, b));
++                              XFS_BUFTARG_NAME(mp->m_logdev_targp));
+-      if (mp->m_rtdev_targp &&
+-          mp->m_ddev_targp->pbr_dev != mp->m_rtdev_targp->pbr_dev)
++      if (mp->m_rtdev_targp && mp->m_ddev_targp != mp->m_rtdev_targp)
+               seq_printf(m, "," MNTOPT_RTDEV "=%s",
+-                              bdevname(mp->m_rtdev_targp->pbr_bdev, b));
++                              XFS_BUFTARG_NAME(mp->m_rtdev_targp));
+       if (mp->m_dalign > 0)
+               seq_printf(m, "," MNTOPT_SUNIT "=%d",
+--- linux-2.6.0-test6/fs/xfs/xfs_vnodeops.c    2003-09-27 18:57:46.000000000 -0700
++++ 25/fs/xfs/xfs_vnodeops.c   2003-10-05 00:33:24.000000000 -0700
+@@ -144,14 +144,11 @@ xfs_getattr(
+               xfs_ilock(ip, XFS_ILOCK_SHARED);
+       vap->va_size = ip->i_d.di_size;
+-      if (vap->va_mask == XFS_AT_SIZE) {
+-              if (!(flags & ATTR_LAZY))
+-                      xfs_iunlock(ip, XFS_ILOCK_SHARED);
+-              return 0;
+-      }
++      if (vap->va_mask == XFS_AT_SIZE)
++              goto all_done;
++
+       vap->va_nblocks =
+               XFS_FSB_TO_BB(mp, ip->i_d.di_nblocks + ip->i_delayed_blks);
+-      vap->va_fsid = mp->m_dev;
+       vap->va_nodeid = ip->i_ino;
+ #if XFS_BIG_INUMS
+       vap->va_nodeid += mp->m_inoadd;
+@@ -163,11 +160,8 @@ xfs_getattr(
+        */
+       if ((vap->va_mask &
+           ~(XFS_AT_SIZE|XFS_AT_FSID|XFS_AT_NODEID|
+-            XFS_AT_NLINK|XFS_AT_BLKSIZE)) == 0) {
+-              if (!(flags & ATTR_LAZY))
+-                      xfs_iunlock(ip, XFS_ILOCK_SHARED);
+-              return 0;
+-      }
++            XFS_AT_NLINK|XFS_AT_BLKSIZE)) == 0)
++              goto all_done;
+       /*
+        * Copy from in-core inode.
+@@ -194,7 +188,7 @@ xfs_getattr(
+                        * stripe size through is not a good
+                        * idea for now.
+                        */
+-                      vap->va_blksize = mp->m_swidth ?
++                      vap->va_blocksize = mp->m_swidth ?
+                               /*
+                                * If the underlying volume is a stripe, then
+                                * return the stripe width in bytes as the
+@@ -211,7 +205,7 @@ xfs_getattr(
+                                              mp->m_writeio_log));
+ #else
+-                      vap->va_blksize =
++                      vap->va_blocksize =
+                               /*
+                                * Return the largest of the preferred buffer
+                                * sizes since doing small I/Os into larger
+@@ -229,13 +223,13 @@ xfs_getattr(
+                        * realtime extent size or the realtime volume's
+                        * extent size.
+                        */
+-                      vap->va_blksize = ip->i_d.di_extsize ?
++                      vap->va_blocksize = ip->i_d.di_extsize ?
+                               (ip->i_d.di_extsize << mp->m_sb.sb_blocklog) :
+                               (mp->m_sb.sb_rextsize << mp->m_sb.sb_blocklog);
+               }
+       } else {
+               vap->va_rdev = ip->i_df.if_u2.if_rdev;
+-              vap->va_blksize = BLKDEV_IOSIZE;
++              vap->va_blocksize = BLKDEV_IOSIZE;
+       }
+       vap->va_atime.tv_sec = ip->i_d.di_atime.t_sec;
+@@ -251,46 +245,53 @@ xfs_getattr(
+        */
+       if ((vap->va_mask &
+            (XFS_AT_XFLAGS|XFS_AT_EXTSIZE|XFS_AT_NEXTENTS|XFS_AT_ANEXTENTS|
+-            XFS_AT_GENCOUNT|XFS_AT_VCODE)) == 0) {
+-              if (!(flags & ATTR_LAZY))
+-                      xfs_iunlock(ip, XFS_ILOCK_SHARED);
+-              return 0;
+-      }
++            XFS_AT_GENCOUNT|XFS_AT_VCODE)) == 0)
++              goto all_done;
++
+       /*
+        * convert di_flags to xflags
+        */
+-      vap->va_xflags =
+-              ((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) ?
+-                      XFS_XFLAG_REALTIME : 0) |
+-              ((ip->i_d.di_flags & XFS_DIFLAG_PREALLOC) ?
+-                      XFS_XFLAG_PREALLOC : 0) |
+-              ((ip->i_d.di_flags & XFS_DIFLAG_IMMUTABLE) ?
+-                      XFS_XFLAG_IMMUTABLE : 0) |
+-              ((ip->i_d.di_flags & XFS_DIFLAG_APPEND) ?
+-                      XFS_XFLAG_APPEND : 0) |
+-              ((ip->i_d.di_flags & XFS_DIFLAG_SYNC) ?
+-                      XFS_XFLAG_SYNC : 0) |
+-              ((ip->i_d.di_flags & XFS_DIFLAG_NOATIME) ?
+-                      XFS_XFLAG_NOATIME : 0) |
+-              ((ip->i_d.di_flags & XFS_DIFLAG_NODUMP) ?
+-                      XFS_XFLAG_NODUMP: 0) |
+-              (XFS_IFORK_Q(ip) ?
+-                      XFS_XFLAG_HASATTR : 0);
++      vap->va_xflags = 0;
++      if (ip->i_d.di_flags & XFS_DIFLAG_REALTIME)
++              vap->va_xflags |= XFS_XFLAG_REALTIME;
++      if (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC)
++              vap->va_xflags |= XFS_XFLAG_PREALLOC;
++      if (ip->i_d.di_flags & XFS_DIFLAG_IMMUTABLE)
++              vap->va_xflags |= XFS_XFLAG_IMMUTABLE;
++      if (ip->i_d.di_flags & XFS_DIFLAG_APPEND)
++              vap->va_xflags |= XFS_XFLAG_APPEND;
++      if (ip->i_d.di_flags & XFS_DIFLAG_SYNC)
++              vap->va_xflags |= XFS_XFLAG_SYNC;
++      if (ip->i_d.di_flags & XFS_DIFLAG_NOATIME)
++              vap->va_xflags |= XFS_XFLAG_NOATIME;
++      if (ip->i_d.di_flags & XFS_DIFLAG_NODUMP)
++              vap->va_xflags |= XFS_XFLAG_NODUMP;
++      if (XFS_IFORK_Q(ip))
++              vap->va_xflags |= XFS_XFLAG_HASATTR;
++      /*
++       * Exit for inode revalidate.  See if any of the rest of
++       * the fields to be filled in are needed.
++       */
++      if ((vap->va_mask &
++           (XFS_AT_EXTSIZE|XFS_AT_NEXTENTS|XFS_AT_ANEXTENTS|
++            XFS_AT_GENCOUNT|XFS_AT_VCODE)) == 0)
++              goto all_done;
++
+       vap->va_extsize = ip->i_d.di_extsize << mp->m_sb.sb_blocklog;
+       vap->va_nextents =
+               (ip->i_df.if_flags & XFS_IFEXTENTS) ?
+                       ip->i_df.if_bytes / sizeof(xfs_bmbt_rec_t) :
+                       ip->i_d.di_nextents;
+-      if (ip->i_afp != NULL)
++      if (ip->i_afp)
+               vap->va_anextents =
+                       (ip->i_afp->if_flags & XFS_IFEXTENTS) ?
+                               ip->i_afp->if_bytes / sizeof(xfs_bmbt_rec_t) :
+                                ip->i_d.di_anextents;
+       else
+               vap->va_anextents = 0;
+-      vap->va_gencount = ip->i_d.di_gen;
+-      vap->va_vcode = 0L;
++      vap->va_gen = ip->i_d.di_gen;
++ all_done:
+       if (!(flags & ATTR_LAZY))
+               xfs_iunlock(ip, XFS_ILOCK_SHARED);
+       return 0;
+@@ -415,7 +416,7 @@ xfs_setattr(
+       } else {
+               if (DM_EVENT_ENABLED (vp->v_vfsp, ip, DM_EVENT_TRUNCATE) &&
+                   !(flags & ATTR_DMI)) {
+-                      code = XFS_SEND_DATA(mp, DM_EVENT_TRUNCATE, bdp,
++                      code = XFS_SEND_DATA(mp, DM_EVENT_TRUNCATE, vp,
+                               vap->va_size, 0, AT_DELAY_FLAG(flags), NULL);
+                       if (code) {
+                               lock_flags = 0;
+@@ -1042,7 +1043,7 @@ xfs_readlink(
+       pathlen = (int)ip->i_d.di_size;
+       if (ip->i_df.if_flags & XFS_IFINLINE) {
+-              error = uiomove(ip->i_df.if_u1.if_data, pathlen, UIO_READ, uiop);
++              error = uio_read(ip->i_df.if_u1.if_data, pathlen, uiop);
+       }
+       else {
+               /*
+@@ -1073,8 +1074,7 @@ xfs_readlink(
+                               byte_cnt = pathlen;
+                       pathlen -= byte_cnt;
+-                      error = uiomove(XFS_BUF_PTR(bp), byte_cnt,
+-                                       UIO_READ, uiop);
++                      error = uio_read(XFS_BUF_PTR(bp), byte_cnt, uiop);
+                       xfs_buf_relse (bp);
+               }
+@@ -1729,7 +1729,7 @@ xfs_inactive(
+       if (ip->i_d.di_nlink == 0 &&
+           DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_DESTROY)) {
+-              (void) XFS_SEND_DESTROY(mp, bdp, DM_RIGHT_NULL);
++              (void) XFS_SEND_DESTROY(mp, vp, DM_RIGHT_NULL);
+       }
+       error = 0;
+@@ -4163,7 +4163,7 @@ xfs_alloc_file_space(
+               end_dmi_offset = offset+len;
+               if (end_dmi_offset > ip->i_d.di_size)
+                       end_dmi_offset = ip->i_d.di_size;
+-              error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, XFS_ITOBHV(ip),
++              error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, XFS_ITOV(ip),
+                       offset, end_dmi_offset - offset,
+                       0, NULL);
+               if (error)
+@@ -4410,7 +4410,7 @@ xfs_free_file_space(
+           DM_EVENT_ENABLED(XFS_MTOVFS(mp), ip, DM_EVENT_WRITE)) {
+               if (end_dmi_offset > ip->i_d.di_size)
+                       end_dmi_offset = ip->i_d.di_size;
+-              error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, XFS_ITOBHV(ip),
++              error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, XFS_ITOV(ip),
+                               offset, end_dmi_offset - offset,
+                               AT_DELAY_FLAG(attr_flags), NULL);
+               if (error)
+--- linux-2.6.0-test6/include/acpi/acconfig.h  2003-08-22 19:23:42.000000000 -0700
++++ 25/include/acpi/acconfig.h 2003-10-05 00:33:24.000000000 -0700
+@@ -64,7 +64,7 @@
+ /* Version string */
+-#define ACPI_CA_VERSION                 0x20030813
++#define ACPI_CA_VERSION                 0x20030918
+ /* Maximum objects in the various object caches */
+--- linux-2.6.0-test6/include/acpi/acdisasm.h  2003-06-14 12:18:22.000000000 -0700
++++ 25/include/acpi/acdisasm.h 2003-10-05 00:33:24.000000000 -0700
+@@ -152,10 +152,6 @@ void
+ acpi_dm_decode_internal_object (
+       union acpi_operand_object       *obj_desc);
+-void
+-acpi_dm_decode_node (
+-      struct acpi_namespace_node      *node);
+-
+ u32
+ acpi_dm_block_type (
+       union acpi_parse_object         *op);
+--- linux-2.6.0-test6/include/acpi/acstruct.h  2003-06-14 12:17:57.000000000 -0700
++++ 25/include/acpi/acstruct.h 2003-10-05 00:33:24.000000000 -0700
+@@ -91,11 +91,12 @@ struct acpi_walk_state
+       struct acpi_namespace_node          arguments[ACPI_METHOD_NUM_ARGS];    /* Control method arguments */
+       union acpi_operand_object           **caller_return_desc;
+       union acpi_generic_state            *control_state;                     /* List of control states (nested IFs) */
++      struct acpi_namespace_node          *deferred_node;                      /* Used when executing deferred opcodes */
+       struct acpi_namespace_node          local_variables[ACPI_METHOD_NUM_LOCALS];    /* Control method locals */
+       struct acpi_namespace_node          *method_call_node;                  /* Called method Node*/
+       union acpi_parse_object             *method_call_op;                    /* method_call Op if running a method */
+       union acpi_operand_object           *method_desc;                       /* Method descriptor if running a method */
+-      struct acpi_namespace_node          *method_node;                       /* Method Node if running a method */
++      struct acpi_namespace_node          *method_node;                       /* Method node if running a method. */
+       union acpi_parse_object             *op;                                /* Current parser op */
+       union acpi_operand_object           *operands[ACPI_OBJ_NUM_OPERANDS+1]; /* Operands passed to the interpreter (+1 for NULL terminator) */
+       const struct acpi_opcode_info       *op_info;                           /* Info on current opcode */
+--- linux-2.6.0-test6/include/asm-alpha/cacheflush.h   2003-06-14 12:18:25.000000000 -0700
++++ 25/include/asm-alpha/cacheflush.h  2003-10-05 00:33:24.000000000 -0700
+@@ -10,6 +10,8 @@
+ #define flush_cache_range(vma, start, end)    do { } while (0)
+ #define flush_cache_page(vma, vmaddr)         do { } while (0)
+ #define flush_dcache_page(page)                       do { } while (0)
++#define flush_cache_vmap(start, end)          do { } while (0)
++#define flush_cache_vunmap(start, end)                do { } while (0)
+ /* Note that the following two definitions are _highly_ dependent
+    on the contexts in which they are used in the kernel.  I personally
+@@ -60,4 +62,11 @@ extern void flush_icache_user_range(stru
+ #define flush_icache_page(vma, page) \
+   flush_icache_user_range((vma), (page), 0, 0)
++#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
++do { memcpy(dst, src, len); \
++     flush_icache_user_range(vma, page, vaddr, len); \
++} while (0)
++#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
++      memcpy(dst, src, len)
++
+ #endif /* _ALPHA_CACHEFLUSH_H */
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/include/asm-alpha/lockmeter.h   2003-10-05 00:36:40.000000000 -0700
+@@ -0,0 +1,90 @@
++/*
++ *  Written by John Hawkes (hawkes@sgi.com)
++ *  Based on klstat.h by Jack Steiner (steiner@sgi.com)
++ *
++ *  Modified by Peter Rival (frival@zk3.dec.com)
++ */
++
++#ifndef _ALPHA_LOCKMETER_H
++#define _ALPHA_LOCKMETER_H
++
++#include <asm/hwrpb.h>
++#define CPU_CYCLE_FREQUENCY   hwrpb->cycle_freq
++
++#define get_cycles64()                get_cycles()
++
++#define THIS_CPU_NUMBER               smp_processor_id()
++
++#include <linux/version.h>
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
++#define local_irq_save(x) \
++      __save_and_cli(x)
++#define local_irq_restore(x) \
++      __restore_flags(x)
++#endif        /* Linux version 2.2.x */
++
++#define SPINLOCK_MAGIC_INIT /**/
++
++/*
++ * Macros to cache and retrieve an index value inside of a lock
++ * these macros assume that there are less than 65536 simultaneous
++ * (read mode) holders of a rwlock.
++ * We also assume that the hash table has less than 32767 entries.
++ * the high order bit is used for write locking a rw_lock
++ * Note: although these defines and macros are the same as what is being used
++ *       in include/asm-i386/lockmeter.h, they are present here to easily
++ *     allow an alternate Alpha implementation.
++ */
++/*
++ * instrumented spinlock structure -- never used to allocate storage
++ * only used in macros below to overlay a spinlock_t
++ */
++typedef struct inst_spinlock_s {
++      /* remember, Alpha is little endian */
++      unsigned short lock;
++      unsigned short index;
++} inst_spinlock_t;
++#define PUT_INDEX(lock_ptr,indexv)    ((inst_spinlock_t *)(lock_ptr))->index = indexv
++#define GET_INDEX(lock_ptr)           ((inst_spinlock_t *)(lock_ptr))->index
++
++/*
++ * macros to cache and retrieve an index value in a read/write lock
++ * as well as the cpu where a reader busy period started
++ * we use the 2nd word (the debug word) for this, so require the
++ * debug word to be present
++ */
++/*
++ * instrumented rwlock structure -- never used to allocate storage
++ * only used in macros below to overlay a rwlock_t
++ */
++typedef struct inst_rwlock_s {
++      volatile int lock;
++      unsigned short index;
++      unsigned short cpu;
++} inst_rwlock_t;
++#define PUT_RWINDEX(rwlock_ptr,indexv)        ((inst_rwlock_t *)(rwlock_ptr))->index = indexv
++#define GET_RWINDEX(rwlock_ptr)               ((inst_rwlock_t *)(rwlock_ptr))->index
++#define PUT_RW_CPU(rwlock_ptr,cpuv)   ((inst_rwlock_t *)(rwlock_ptr))->cpu = cpuv
++#define GET_RW_CPU(rwlock_ptr)                ((inst_rwlock_t *)(rwlock_ptr))->cpu
++
++/*
++ * return true if rwlock is write locked
++ * (note that other lock attempts can cause the lock value to be negative)
++ */
++#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) (((inst_rwlock_t *)rwlock_ptr)->lock & 1)
++#define IABS(x) ((x) > 0 ? (x) : -(x))
++
++#define RWLOCK_READERS(rwlock_ptr)    rwlock_readers(rwlock_ptr)
++extern inline int rwlock_readers(rwlock_t *rwlock_ptr)
++{
++      int tmp = (int) ((inst_rwlock_t *)rwlock_ptr)->lock;
++      /* readers subtract 2, so we have to:           */
++      /*      - andnot off a possible writer (bit 0)  */
++      /*      - get the absolute value                */
++      /*      - divide by 2 (right shift by one)      */
++      /* to find the number of readers                */
++      if (tmp == 0) return(0);
++      else return(IABS(tmp & ~1)>>1);
++}
++
++#endif /* _ALPHA_LOCKMETER_H */
+--- linux-2.6.0-test6/include/asm-alpha/numnodes.h     2003-06-14 12:17:58.000000000 -0700
++++ 25/include/asm-alpha/numnodes.h    2003-10-05 00:34:38.000000000 -0700
+@@ -1,6 +1,7 @@
+ #ifndef _ASM_MAX_NUMNODES_H
+ #define _ASM_MAX_NUMNODES_H
+-#define MAX_NUMNODES          128 /* Marvel */
++/* Max 128 Nodes - Marvel */
++#define NODES_SHIFT   7
+ #endif /* _ASM_MAX_NUMNODES_H */
+--- linux-2.6.0-test6/include/asm-alpha/pgtable.h      2003-06-14 12:18:06.000000000 -0700
++++ 25/include/asm-alpha/pgtable.h     2003-10-05 00:33:24.000000000 -0700
+@@ -49,7 +49,6 @@
+ #else
+ #define VMALLOC_START         (-2*PGDIR_SIZE)
+ #endif
+-#define VMALLOC_VMADDR(x)     ((unsigned long)(x))
+ #define VMALLOC_END           (-PGDIR_SIZE)
+ /*
+--- linux-2.6.0-test6/include/asm-alpha/spinlock.h     2003-06-26 22:07:25.000000000 -0700
++++ 25/include/asm-alpha/spinlock.h    2003-10-05 00:36:40.000000000 -0700
+@@ -6,6 +6,10 @@
+ #include <linux/kernel.h>
+ #include <asm/current.h>
++#ifdef CONFIG_LOCKMETER
++#undef DEBUG_SPINLOCK
++#undef DEBUG_RWLOCK
++#endif
+ /*
+  * Simple spin lock operations.  There are two variants, one clears IRQ's
+@@ -95,9 +99,18 @@ static inline int _raw_spin_trylock(spin
+ typedef struct {
+       volatile int write_lock:1, read_counter:31;
++#ifdef CONFIG_LOCKMETER
++      /* required for LOCKMETER since all bits in lock are used */
++      /* need this storage for CPU and lock INDEX ............. */
++      unsigned magic;
++#endif
+ } /*__attribute__((aligned(32)))*/ rwlock_t;
++#ifdef CONFIG_LOCKMETER
++#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0, 0 }
++#else
+ #define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 }
++#endif
+ #define rwlock_init(x)        do { *(x) = RW_LOCK_UNLOCKED; } while(0)
+ #define rwlock_is_locked(x)   (*(volatile int *)(x) != 0)
+@@ -169,4 +182,41 @@ static inline void _raw_read_unlock(rwlo
+       : "m" (*lock) : "memory");
+ }
++#ifdef CONFIG_LOCKMETER
++static inline int _raw_write_trylock(rwlock_t *lock)
++{
++      long temp,result;
++
++      __asm__ __volatile__(
++      "       ldl_l %1,%0\n"
++      "       mov $31,%2\n"
++      "       bne %1,1f\n"
++      "       or $31,1,%2\n"
++      "       stl_c %2,%0\n"
++      "1:     mb\n"
++      : "=m" (*(volatile int *)lock), "=&r" (temp), "=&r" (result)
++      : "m" (*(volatile int *)lock)
++      );
++
++      return (result);
++}
++
++static inline int _raw_read_trylock(rwlock_t *lock)
++{
++      unsigned long temp,result;
++
++      __asm__ __volatile__(
++      "       ldl_l %1,%0\n"
++      "       mov $31,%2\n"
++      "       blbs %1,1f\n"
++      "       subl %1,2,%2\n"
++      "       stl_c %2,%0\n"
++      "1:     mb\n"
++      : "=m" (*(volatile int *)lock), "=&r" (temp), "=&r" (result)
++      : "m" (*(volatile int *)lock)
++      );
++      return (result);
++}
++#endif /* CONFIG_LOCKMETER */
++
+ #endif /* _ALPHA_SPINLOCK_H */
+--- linux-2.6.0-test6/include/asm-arm26/cacheflush.h   2003-06-14 12:18:29.000000000 -0700
++++ 25/include/asm-arm26/cacheflush.h  2003-10-05 00:33:24.000000000 -0700
+@@ -25,6 +25,8 @@
+ #define flush_cache_range(vma,start,end)        do { } while (0)
+ #define flush_cache_page(vma,vmaddr)            do { } while (0)
+ #define flush_page_to_ram(page)                 do { } while (0)
++#define flush_cache_vmap(start, end)          do { } while (0)
++#define flush_cache_vunmap(start, end)                do { } while (0)
+ #define invalidate_dcache_range(start,end)      do { } while (0)
+ #define clean_dcache_range(start,end)           do { } while (0)
+@@ -37,6 +39,11 @@
+ #define flush_icache_range(start,end)           do { } while (0)
+ #define flush_icache_page(vma,page)             do { } while (0)
++#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
++      memcpy(dst, src, len)
++#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
++      memcpy(dst, src, len)
++
+ /* DAG: ARM3 will flush cache on MEMC updates anyway? so don't bother */
+ /* IM : Yes, it will, but only if setup to do so (we do this). */
+ #define clean_cache_area(_start,_size)          do { } while (0)
+--- linux-2.6.0-test6/include/asm-arm26/pgtable.h      2003-07-10 18:50:32.000000000 -0700
++++ 25/include/asm-arm26/pgtable.h     2003-10-05 00:33:24.000000000 -0700
+@@ -173,7 +173,6 @@ extern struct page *empty_zero_page;
+  * area for the same reason. ;) FIXME: surely 1 page not 4k ?
+  */
+ #define VMALLOC_START     0x01a00000
+-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+ #define VMALLOC_END       0x01c00000
+ /* Is pmd_page supposed to return a pointer to a page in some arches? ours seems to
+--- linux-2.6.0-test6/include/asm-arm/arch-adifcc/vmalloc.h    2003-06-14 12:17:58.000000000 -0700
++++ 25/include/asm-arm/arch-adifcc/vmalloc.h   2003-10-05 00:33:24.000000000 -0700
+@@ -12,7 +12,6 @@
+  */
+ #define VMALLOC_OFFSET          (8*1024*1024)
+ #define VMALLOC_START   (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+ #define VMALLOC_END       (0xe8000000)
+ #define MODULE_START  (PAGE_OFFSET - 16*1048576)
+--- linux-2.6.0-test6/include/asm-arm/arch-anakin/vmalloc.h    2003-06-14 12:18:04.000000000 -0700
++++ 25/include/asm-arm/arch-anakin/vmalloc.h   2003-10-05 00:33:24.000000000 -0700
+@@ -19,8 +19,7 @@
+  * linux/arch/arm/kernel/traps.c)
+  */
+ #define VMALLOC_ARCH_OFFSET   (8 * 1024 * 1024)
+-#define VMALLOC_VMADDR(a)     ((unsigned int) (a))
+-#define VMALLOC_START         ((VMALLOC_VMADDR(high_memory) + VMALLOC_ARCH_OFFSET) & ~(VMALLOC_ARCH_OFFSET - 1))
++#define VMALLOC_START         (((unsigned long) (high_memory) + VMALLOC_ARCH_OFFSET) & ~(VMALLOC_ARCH_OFFSET - 1))
+ #define VMALLOC_END           (PAGE_OFFSET + 0x10000000)
+ #define MODULE_START  (PAGE_OFFSET - 16*1048576)
+--- linux-2.6.0-test6/include/asm-arm/arch-cl7500/vmalloc.h    2003-06-14 12:18:32.000000000 -0700
++++ 25/include/asm-arm/arch-cl7500/vmalloc.h   2003-10-05 00:33:24.000000000 -0700
+@@ -12,7 +12,6 @@
+  */
+ #define VMALLOC_OFFSET          (8*1024*1024)
+ #define VMALLOC_START   (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+ #define VMALLOC_END       (PAGE_OFFSET + 0x1c000000)
+ #define MODULE_START  (PAGE_OFFSET - 16*1048576)
+--- linux-2.6.0-test6/include/asm-arm/arch-clps711x/memory.h   2003-06-14 12:17:56.000000000 -0700
++++ 25/include/asm-arm/arch-clps711x/memory.h  2003-10-05 00:34:40.000000000 -0700
+@@ -109,8 +109,6 @@
+  *    node 3:  0xd8000000 - 0xdfffffff
+  */
+-#define NR_NODES      4
+-
+ /*
+  * Given a kernel address, find the home node of the underlying memory.
+  */
+--- linux-2.6.0-test6/include/asm-arm/arch-clps711x/vmalloc.h  2003-06-14 12:17:56.000000000 -0700
++++ 25/include/asm-arm/arch-clps711x/vmalloc.h 2003-10-05 00:33:24.000000000 -0700
+@@ -28,7 +28,6 @@
+  */
+ #define VMALLOC_OFFSET          (8*1024*1024)
+ #define VMALLOC_START   (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+ #define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
+ #define MODULE_START  (PAGE_OFFSET - 16*1048576)
+--- linux-2.6.0-test6/include/asm-arm/arch-ebsa110/vmalloc.h   2003-06-14 12:18:07.000000000 -0700
++++ 25/include/asm-arm/arch-ebsa110/vmalloc.h  2003-10-05 00:33:24.000000000 -0700
+@@ -18,7 +18,6 @@
+  */
+ #define VMALLOC_OFFSET          (8*1024*1024)
+ #define VMALLOC_START   (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+ #define VMALLOC_END       (PAGE_OFFSET + 0x1f000000)
+ #define MODULE_START  (PAGE_OFFSET - 16*1048576)
+--- linux-2.6.0-test6/include/asm-arm/arch-ebsa285/vmalloc.h   2003-06-14 12:18:08.000000000 -0700
++++ 25/include/asm-arm/arch-ebsa285/vmalloc.h  2003-10-05 00:33:24.000000000 -0700
+@@ -18,7 +18,6 @@
+  */
+ #define VMALLOC_OFFSET          (8*1024*1024)
+ #define VMALLOC_START   (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+ #ifdef CONFIG_ARCH_FOOTBRIDGE
+ #define VMALLOC_END       (PAGE_OFFSET + 0x30000000)
+--- linux-2.6.0-test6/include/asm-arm/arch-epxa10db/vmalloc.h  2003-06-14 12:17:58.000000000 -0700
++++ 25/include/asm-arm/arch-epxa10db/vmalloc.h 2003-10-05 00:33:24.000000000 -0700
+@@ -28,7 +28,6 @@
+  */
+ #define VMALLOC_OFFSET          (8*1024*1024)
+ #define VMALLOC_START   (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+ #define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
+ #define MODULE_START  (PAGE_OFFSET - 16*1048576)
+--- linux-2.6.0-test6/include/asm-arm/arch-integrator/irqs.h   2003-06-14 12:17:57.000000000 -0700
++++ 25/include/asm-arm/arch-integrator/irqs.h  2003-10-05 00:33:24.000000000 -0700
+@@ -19,116 +19,39 @@
+  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+  */
+-/* Use the integrator definitions */
+-#include <asm/arch/platform.h>
+-
+-/* 
+- *  IRQ interrupts definitions are the same the INT definitions
+- *  held within platform.h
+- */
+-#define IRQ_SOFTINT                     INT_SOFTINT
+-#define IRQ_UARTINT0                    INT_UARTINT0
+-#define IRQ_UARTINT1                    INT_UARTINT1
+-#define IRQ_KMIINT0                     INT_KMIINT0
+-#define IRQ_KMIINT1                     INT_KMIINT1
+-#define IRQ_TIMERINT0                   INT_TIMERINT0
+-#define IRQ_TIMERINT1                   INT_TIMERINT1
+-#define IRQ_TIMERINT2                   INT_TIMERINT2
+-#define IRQ_RTCINT                      INT_RTCINT
+-#define IRQ_EXPINT0                     INT_EXPINT0
+-#define IRQ_EXPINT1                     INT_EXPINT1
+-#define IRQ_EXPINT2                     INT_EXPINT2
+-#define IRQ_EXPINT3                     INT_EXPINT3
+-#define IRQ_PCIINT0                     INT_PCIINT0
+-#define IRQ_PCIINT1                     INT_PCIINT1
+-#define IRQ_PCIINT2                     INT_PCIINT2
+-#define IRQ_PCIINT3                     INT_PCIINT3
+-#define IRQ_V3INT                       INT_V3INT
+-#define IRQ_CPINT0                      INT_CPINT0
+-#define IRQ_CPINT1                      INT_CPINT1
+-#define IRQ_LBUSTIMEOUT                 INT_LBUSTIMEOUT
+-#define IRQ_APCINT                      INT_APCINT
+-
+-#define IRQMASK_SOFTINT                 INTMASK_SOFTINT
+-#define IRQMASK_UARTINT0                INTMASK_UARTINT0
+-#define IRQMASK_UARTINT1                INTMASK_UARTINT1
+-#define IRQMASK_KMIINT0                 INTMASK_KMIINT0
+-#define IRQMASK_KMIINT1                 INTMASK_KMIINT1
+-#define IRQMASK_TIMERINT0               INTMASK_TIMERINT0
+-#define IRQMASK_TIMERINT1               INTMASK_TIMERINT1
+-#define IRQMASK_TIMERINT2               INTMASK_TIMERINT2
+-#define IRQMASK_RTCINT                  INTMASK_RTCINT
+-#define IRQMASK_EXPINT0                 INTMASK_EXPINT0
+-#define IRQMASK_EXPINT1                 INTMASK_EXPINT1
+-#define IRQMASK_EXPINT2                 INTMASK_EXPINT2
+-#define IRQMASK_EXPINT3                 INTMASK_EXPINT3
+-#define IRQMASK_PCIINT0                 INTMASK_PCIINT0
+-#define IRQMASK_PCIINT1                 INTMASK_PCIINT1
+-#define IRQMASK_PCIINT2                 INTMASK_PCIINT2
+-#define IRQMASK_PCIINT3                 INTMASK_PCIINT3
+-#define IRQMASK_V3INT                   INTMASK_V3INT
+-#define IRQMASK_CPINT0                  INTMASK_CPINT0
+-#define IRQMASK_CPINT1                  INTMASK_CPINT1
+-#define IRQMASK_LBUSTIMEOUT             INTMASK_LBUSTIMEOUT
+-#define IRQMASK_APCINT                  INTMASK_APCINT
+-
+ /* 
+- *  FIQ interrupts definitions are the same the INT definitions.
++ *  Interrupt numbers
+  */
+-#define FIQ_SOFTINT                     INT_SOFTINT
+-#define FIQ_UARTINT0                    INT_UARTINT0
+-#define FIQ_UARTINT1                    INT_UARTINT1
+-#define FIQ_KMIINT0                     INT_KMIINT0
+-#define FIQ_KMIINT1                     INT_KMIINT1
+-#define FIQ_TIMERINT0                   INT_TIMERINT0
+-#define FIQ_TIMERINT1                   INT_TIMERINT1
+-#define FIQ_TIMERINT2                   INT_TIMERINT2
+-#define FIQ_RTCINT                      INT_RTCINT
+-#define FIQ_EXPINT0                     INT_EXPINT0
+-#define FIQ_EXPINT1                     INT_EXPINT1
+-#define FIQ_EXPINT2                     INT_EXPINT2
+-#define FIQ_EXPINT3                     INT_EXPINT3
+-#define FIQ_PCIINT0                     INT_PCIINT0
+-#define FIQ_PCIINT1                     INT_PCIINT1
+-#define FIQ_PCIINT2                     INT_PCIINT2
+-#define FIQ_PCIINT3                     INT_PCIINT3
+-#define FIQ_V3INT                       INT_V3INT
+-#define FIQ_CPINT0                      INT_CPINT0
+-#define FIQ_CPINT1                      INT_CPINT1
+-#define FIQ_LBUSTIMEOUT                 INT_LBUSTIMEOUT
+-#define FIQ_APCINT                      INT_APCINT
+-
+-#define FIQMASK_SOFTINT                 INTMASK_SOFTINT
+-#define FIQMASK_UARTINT0                INTMASK_UARTINT0
+-#define FIQMASK_UARTINT1                INTMASK_UARTINT1
+-#define FIQMASK_KMIINT0                 INTMASK_KMIINT0
+-#define FIQMASK_KMIINT1                 INTMASK_KMIINT1
+-#define FIQMASK_TIMERINT0               INTMASK_TIMERINT0
+-#define FIQMASK_TIMERINT1               INTMASK_TIMERINT1
+-#define FIQMASK_TIMERINT2               INTMASK_TIMERINT2
+-#define FIQMASK_RTCINT                  INTMASK_RTCINT
+-#define FIQMASK_EXPINT0                 INTMASK_EXPINT0
+-#define FIQMASK_EXPINT1                 INTMASK_EXPINT1
+-#define FIQMASK_EXPINT2                 INTMASK_EXPINT2
+-#define FIQMASK_EXPINT3                 INTMASK_EXPINT3
+-#define FIQMASK_PCIINT0                 INTMASK_PCIINT0
+-#define FIQMASK_PCIINT1                 INTMASK_PCIINT1
+-#define FIQMASK_PCIINT2                 INTMASK_PCIINT2
+-#define FIQMASK_PCIINT3                 INTMASK_PCIINT3
+-#define FIQMASK_V3INT                   INTMASK_V3INT
+-#define FIQMASK_CPINT0                  INTMASK_CPINT0
+-#define FIQMASK_CPINT1                  INTMASK_CPINT1
+-#define FIQMASK_LBUSTIMEOUT             INTMASK_LBUSTIMEOUT
+-#define FIQMASK_APCINT                  INTMASK_APCINT
+-
+-/* 
+- *  Misc. interrupt definitions
+- */
+-#define IRQ_KEYBDINT                    INT_KMIINT0
+-#define IRQ_MOUSEINT                    INT_KMIINT1
+-
+-#define IRQMASK_KEYBDINT                INTMASK_KMIINT0
+-#define IRQMASK_MOUSEINT                INTMASK_KMIINT1
++#define IRQ_PIC_START                 0
++#define IRQ_SOFTINT                   0
++#define IRQ_UARTINT0                  1
++#define IRQ_UARTINT1                  2
++#define IRQ_KMIINT0                   3
++#define IRQ_KMIINT1                   4
++#define IRQ_TIMERINT0                 5
++#define IRQ_TIMERINT1                 6
++#define IRQ_TIMERINT2                 7
++#define IRQ_RTCINT                    8
++#define IRQ_AP_EXPINT0                        9
++#define IRQ_AP_EXPINT1                        10
++#define IRQ_AP_EXPINT2                        11
++#define IRQ_AP_EXPINT3                        12
++#define IRQ_AP_PCIINT0                        13
++#define IRQ_AP_PCIINT1                        14
++#define IRQ_AP_PCIINT2                        15
++#define IRQ_AP_PCIINT3                        16
++#define IRQ_AP_V3INT                  17
++#define IRQ_AP_CPINT0                 18
++#define IRQ_AP_CPINT1                 19
++#define IRQ_AP_LBUSTIMEOUT            20
++#define IRQ_AP_APCINT                 21
++#define IRQ_PIC_END                   31
++
++#define IRQ_CIC_START                 32
++#define IRQ_CM_SOFTINT                        32
++#define IRQ_CM_COMMRX                 33
++#define IRQ_CM_COMMTX                 34
++#define IRQ_CIC_END                   34
+-#define NR_IRQS                         (MAXIRQNUM + 1)
++#define NR_IRQS                         47
+--- linux-2.6.0-test6/include/asm-arm/arch-integrator/platform.h       2003-06-14 12:18:22.000000000 -0700
++++ 25/include/asm-arm/arch-integrator/platform.h      2003-10-05 00:33:24.000000000 -0700
+@@ -386,85 +386,6 @@
+  * 
+  */
+-/* 
+- *  As the interrupt bit definitions for FIQ/IRQ there is a common
+- *  set of definitions prefixed INT/INTMASK.  The FIQ/IRQ definitions
+- *  have been left to maintain backwards compatible.
+- * 
+- */
+-
+-/* 
+- *  Interrupt numbers
+- * 
+- */
+-#define INT_SOFTINT                     0
+-#define INT_UARTINT0                    1
+-#define INT_UARTINT1                    2
+-#define INT_KMIINT0                     3
+-#define INT_KMIINT1                     4
+-#define INT_TIMERINT0                   5
+-#define INT_TIMERINT1                   6
+-#define INT_TIMERINT2                   7
+-#define INT_RTCINT                      8
+-#define INT_EXPINT0                     9
+-#define INT_EXPINT1                     10
+-#define INT_EXPINT2                     11
+-#define INT_EXPINT3                     12
+-#define INT_PCIINT0                     13
+-#define INT_PCIINT1                     14
+-#define INT_PCIINT2                     15
+-#define INT_PCIINT3                     16
+-#define INT_V3INT                       17
+-#define INT_CPINT0                      18
+-#define INT_CPINT1                      19
+-#define INT_LBUSTIMEOUT                 20
+-#define INT_APCINT                      21
+-#define INT_CM_SOFTINT                  24
+-#define INT_CM_COMMRX                   25
+-#define INT_CM_COMMTX                   26
+-
+-/* 
+- *  Interrupt bit positions
+- * 
+- */
+-#define INTMASK_SOFTINT                 (1 << INT_SOFTINT)
+-#define INTMASK_UARTINT0                (1 << INT_UARTINT0)
+-#define INTMASK_UARTINT1                (1 << INT_UARTINT1)
+-#define INTMASK_KMIINT0                 (1 << INT_KMIINT0)
+-#define INTMASK_KMIINT1                 (1 << INT_KMIINT1)
+-#define INTMASK_TIMERINT0               (1 << INT_TIMERINT0)
+-#define INTMASK_TIMERINT1               (1 << INT_TIMERINT1)
+-#define INTMASK_TIMERINT2               (1 << INT_TIMERINT2)
+-#define INTMASK_RTCINT                  (1 << INT_RTCINT)
+-#define INTMASK_EXPINT0                 (1 << INT_EXPINT0)
+-#define INTMASK_EXPINT1                 (1 << INT_EXPINT1)
+-#define INTMASK_EXPINT2                 (1 << INT_EXPINT2)
+-#define INTMASK_EXPINT3                 (1 << INT_EXPINT3)
+-#define INTMASK_PCIINT0                 (1 << INT_PCIINT0)
+-#define INTMASK_PCIINT1                 (1 << INT_PCIINT1)
+-#define INTMASK_PCIINT2                 (1 << INT_PCIINT2)
+-#define INTMASK_PCIINT3                 (1 << INT_PCIINT3)
+-#define INTMASK_V3INT                   (1 << INT_V3INT)
+-#define INTMASK_CPINT0                  (1 << INT_CPINT0)
+-#define INTMASK_CPINT1                  (1 << INT_CPINT1)
+-#define INTMASK_LBUSTIMEOUT             (1 << INT_LBUSTIMEOUT)
+-#define INTMASK_APCINT                  (1 << INT_APCINT)
+-#define INTMASK_CM_SOFTINT              (1 << INT_CM_SOFTINT)
+-#define INTMASK_CM_COMMRX               (1 << INT_CM_COMMRX)
+-#define INTMASK_CM_COMMTX               (1 << INT_CM_COMMTX)
+-
+-/* 
+- *  INTEGRATOR_CM_INT0      - Interrupt number of first CM interrupt
+- *  INTEGRATOR_SC_VALID_INT - Mask of valid system controller interrupts
+- * 
+- */
+-#define INTEGRATOR_CM_INT0              INT_CM_SOFTINT
+-#define INTEGRATOR_SC_VALID_INT         0x003FFFFF
+-
+-#define MAXIRQNUM                       31
+-#define MAXFIQNUM                       31
+-#define MAXSWINUM                       31
+- 
+ /* ------------------------------------------------------------------------
+  *  LED's - The header LED is not accessible via the uHAL API
+  * ------------------------------------------------------------------------
+--- linux-2.6.0-test6/include/asm-arm/arch-integrator/time.h   2003-06-14 12:18:29.000000000 -0700
++++ 25/include/asm-arm/arch-integrator/time.h  2003-10-05 00:33:24.000000000 -0700
+@@ -86,7 +86,7 @@ static unsigned long integrator_gettimeo
+       /*
+        * Interrupt pending?  If so, we've reloaded once already.
+        */
+-      if (status & IRQMASK_TIMERINT1)
++      if (status & (1 << IRQ_TIMERINT1))
+               ticks1 += TIMER_RELOAD;
+       /*
+--- linux-2.6.0-test6/include/asm-arm/arch-integrator/vmalloc.h        2003-06-14 12:17:57.000000000 -0700
++++ 25/include/asm-arm/arch-integrator/vmalloc.h       2003-10-05 00:33:24.000000000 -0700
+@@ -28,7 +28,6 @@
+  */
+ #define VMALLOC_OFFSET          (8*1024*1024)
+ #define VMALLOC_START   (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+ #define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
+ #define MODULE_START  (PAGE_OFFSET - 16*1048576)
+--- linux-2.6.0-test6/include/asm-arm/arch-iop3xx/vmalloc.h    2003-06-14 12:18:25.000000000 -0700
++++ 25/include/asm-arm/arch-iop3xx/vmalloc.h   2003-10-05 00:33:24.000000000 -0700
+@@ -12,7 +12,6 @@
+  */
+ #define VMALLOC_OFFSET          (8*1024*1024)
+ #define VMALLOC_START   (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+ #define VMALLOC_END       (0xe8000000)
+ #define MODULE_START  (PAGE_OFFSET - 16*1048576)
+--- linux-2.6.0-test6/include/asm-arm/arch-l7200/vmalloc.h     2003-06-14 12:17:59.000000000 -0700
++++ 25/include/asm-arm/arch-l7200/vmalloc.h    2003-10-05 00:33:24.000000000 -0700
+@@ -12,7 +12,6 @@
+  */
+ #define VMALLOC_OFFSET          (8*1024*1024)
+ #define VMALLOC_START   (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+ #define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
+ #define MODULE_START  (PAGE_OFFSET - 16*1048576)
+--- linux-2.6.0-test6/include/asm-arm/arch-nexuspci/vmalloc.h  2003-06-14 12:18:21.000000000 -0700
++++ 25/include/asm-arm/arch-nexuspci/vmalloc.h 2003-10-05 00:33:24.000000000 -0700
+@@ -12,7 +12,6 @@
+  */
+ #define VMALLOC_OFFSET          (8*1024*1024)
+ #define VMALLOC_START   (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+ #define VMALLOC_END       (PAGE_OFFSET + 0x20000000)
+ #define MODULE_START  (PAGE_OFFSET - 16*1048576)
+--- linux-2.6.0-test6/include/asm-arm/arch-pxa/irqs.h  2003-09-27 18:57:46.000000000 -0700
++++ 25/include/asm-arm/arch-pxa/irqs.h 2003-10-05 00:33:24.000000000 -0700
+@@ -13,7 +13,7 @@
+ #include <linux/config.h>
+ #define PXA_IRQ_SKIP  7       /* The first 7 IRQs are not yet used */
+-#define PXA_IRQ(x)            ((x) - PXA_IRQ_SKIP)
++#define PXA_IRQ(x)    ((x) - PXA_IRQ_SKIP)
+ #define IRQ_HWUART    PXA_IRQ(7)      /* HWUART Transmit/Receive/Error */
+ #define       IRQ_GPIO0       PXA_IRQ(8)      /* GPIO0 Edge Detect */
+@@ -47,7 +47,7 @@
+ #define IRQ_TO_GPIO_2_80(i)   \
+                       ((i) - PXA_IRQ(32) + 2)
+-#define IRQ_TO_GPIO(i)        ((i) - (((i) > IRQ_GPIO1) ? IRQ_GPIO(2) : IRQ_GPIO(0)))
++#define IRQ_TO_GPIO(i)        ((i) - (((i) > IRQ_GPIO1) ? IRQ_GPIO(2) - 2 : IRQ_GPIO(0)))
+ /*
+  * The next 16 interrupts are for board specific purposes.  Since
+@@ -131,8 +131,10 @@
+ #define LUBBOCK_IRQ(x)                (IRQ_BOARD_START + (x))
+ #define LUBBOCK_SD_IRQ                LUBBOCK_IRQ(0)
+ #define LUBBOCK_SA1111_IRQ    LUBBOCK_IRQ(1)
+-#define LUBBOCK_USB_IRQ               LUBBOCK_IRQ(2)
++#define LUBBOCK_USB_IRQ               LUBBOCK_IRQ(2)  /* usb connect */
+ #define LUBBOCK_ETH_IRQ               LUBBOCK_IRQ(3)
+ #define LUBBOCK_UCB1400_IRQ   LUBBOCK_IRQ(4)
+ #define LUBBOCK_BB_IRQ                LUBBOCK_IRQ(5)
++#define LUBBOCK_USB_DISC_IRQ  LUBBOCK_IRQ(6)  /* usb disconnect */
++#define LUBBOCK_LAST_IRQ      LUBBOCK_IRQ(6)
+--- linux-2.6.0-test6/include/asm-arm/arch-pxa/lubbock.h       2003-06-14 12:17:59.000000000 -0700
++++ 25/include/asm-arm/arch-pxa/lubbock.h      2003-10-05 00:33:24.000000000 -0700
+@@ -12,7 +12,8 @@
+ #define LUBBOCK_FPGA_PHYS     PXA_CS2_PHYS
+ #define LUBBOCK_FPGA_VIRT     (0xf0000000)    /* phys 0x08000000 */
+-#define LUBBOCK_ETH_BASE      (0xf1000000)    /* phys 0x0c000000 */
++#define LUBBOCK_ETH_PHYS      PXA_CS3_PHYS
++#define LUBBOCK_ETH_VIRT      (0xf1000000)
+ #define LUB_P2V(x)            ((x) - LUBBOCK_FPGA_PHYS + LUBBOCK_FPGA_VIRT)
+ #define LUB_V2P(x)            ((x) - LUBBOCK_FPGA_VIRT + LUBBOCK_FPGA_PHYS)
+--- linux-2.6.0-test6/include/asm-arm/arch-pxa/vmalloc.h       2003-06-14 12:18:21.000000000 -0700
++++ 25/include/asm-arm/arch-pxa/vmalloc.h      2003-10-05 00:33:24.000000000 -0700
+@@ -19,7 +19,6 @@
+  */
+ #define VMALLOC_OFFSET          (8*1024*1024)
+ #define VMALLOC_START   (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+ #define VMALLOC_END       (0xe8000000)
+ #define MODULE_START  (PAGE_OFFSET - 16*1048576)
+--- linux-2.6.0-test6/include/asm-arm/arch-rpc/vmalloc.h       2003-06-14 12:18:25.000000000 -0700
++++ 25/include/asm-arm/arch-rpc/vmalloc.h      2003-10-05 00:33:24.000000000 -0700
+@@ -18,7 +18,6 @@
+  */
+ #define VMALLOC_OFFSET          (8*1024*1024)
+ #define VMALLOC_START   (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+ #define VMALLOC_END       (PAGE_OFFSET + 0x1c000000)
+ #define MODULE_START  (PAGE_OFFSET - 16*1048576)
+--- linux-2.6.0-test6/include/asm-arm/arch-sa1100/memory.h     2003-06-14 12:17:56.000000000 -0700
++++ 25/include/asm-arm/arch-sa1100/memory.h    2003-10-05 00:34:40.000000000 -0700
+@@ -74,8 +74,6 @@
+  *    node 3:  0xd8000000 - 0xdfffffff
+  */
+-#define NR_NODES      4
+-
+ /*
+  * Given a kernel address, find the home node of the underlying memory.
+  */
+--- linux-2.6.0-test6/include/asm-arm/arch-sa1100/vmalloc.h    2003-06-14 12:18:51.000000000 -0700
++++ 25/include/asm-arm/arch-sa1100/vmalloc.h   2003-10-05 00:33:24.000000000 -0700
+@@ -12,7 +12,6 @@
+  */
+ #define VMALLOC_OFFSET          (8*1024*1024)
+ #define VMALLOC_START   (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+ #define VMALLOC_END       (0xe8000000)
+ #define MODULE_START  (PAGE_OFFSET - 16*1048576)
+--- linux-2.6.0-test6/include/asm-arm/arch-shark/vmalloc.h     2003-06-14 12:17:59.000000000 -0700
++++ 25/include/asm-arm/arch-shark/vmalloc.h    2003-10-05 00:33:24.000000000 -0700
+@@ -12,7 +12,6 @@
+  */
+ #define VMALLOC_OFFSET          (8*1024*1024)
+ #define VMALLOC_START   (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+ #define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
+ #define MODULE_START  (PAGE_OFFSET - 16*1048576)
+--- linux-2.6.0-test6/include/asm-arm/arch-tbox/vmalloc.h      2003-06-14 12:17:56.000000000 -0700
++++ 25/include/asm-arm/arch-tbox/vmalloc.h     2003-10-05 00:33:24.000000000 -0700
+@@ -12,7 +12,6 @@
+  */
+ #define VMALLOC_OFFSET          (8*1024*1024)
+ #define VMALLOC_START   (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+ #define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
+ #define MODULE_START  (PAGE_OFFSET - 16*1048576)
+--- linux-2.6.0-test6/include/asm-arm/cacheflush.h     2003-09-27 18:57:46.000000000 -0700
++++ 25/include/asm-arm/cacheflush.h    2003-10-05 00:33:24.000000000 -0700
+@@ -207,6 +207,15 @@ extern void dmac_inv_range(unsigned long
+ extern void dmac_clean_range(unsigned long, unsigned long);
+ extern void dmac_flush_range(unsigned long, unsigned long);
++#define flush_cache_vmap(start, end)          flush_cache_all()
++#define flush_cache_vunmap(start, end)                flush_cache_all()
++#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
++do { memcpy(dst, src, len); \
++     flush_icache_user_range(vma, page, vaddr, len); \
++} while (0)
++#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
++      memcpy(dst, src, len)
++
+ #endif
+ /*
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/include/asm-arm/mach/flash.h    2003-10-05 00:33:24.000000000 -0700
+@@ -0,0 +1,19 @@
++/*
++ *  linux/include/asm-arm/mach/flash.h
++ *
++ *  Copyright (C) 2003 Russell King, All Rights Reserved.
++ */
++#ifndef ASMARM_MACH_FLASH_H
++#define ASMAMR_MACH_FLASH_H
++
++struct mtd_partition;
++
++struct flash_platform_data {
++      const char      *map_name;
++      int             width;
++      int             (*init)(void);
++      void            (*exit)(void);
++      void            (*set_vpp)(int on);
++};
++
++#endif
+--- linux-2.6.0-test6/include/asm-arm/memory.h 2003-09-08 13:58:59.000000000 -0700
++++ 25/include/asm-arm/memory.h        2003-10-05 00:34:41.000000000 -0700
+@@ -84,24 +84,24 @@ static inline void *phys_to_virt(unsigne
+ #define PHYS_TO_NID(addr)     (0)
+-#else
++#else /* CONFIG_DISCONTIGMEM */
++
+ /*
+  * This is more complex.  We have a set of mem_map arrays spread
+  * around in memory.
+  */
++#include <linux/numa.h>
++
+ #define page_to_pfn(page)                                     \
+       (( (page) - page_zone(page)->zone_mem_map)              \
+         + page_zone(page)->zone_start_pfn)
+-
+ #define pfn_to_page(pfn)                                      \
+       (PFN_TO_MAPBASE(pfn) + LOCAL_MAP_NR((pfn) << PAGE_SHIFT))
+-
+-#define pfn_valid(pfn)                (PFN_TO_NID(pfn) < NR_NODES)
++#define pfn_valid(pfn)                (PFN_TO_NID(pfn) < MAX_NUMNODES)
+ #define virt_to_page(kaddr)                                   \
+       (ADDR_TO_MAPBASE(kaddr) + LOCAL_MAP_NR(kaddr))
+-
+-#define virt_addr_valid(kaddr)        (KVADDR_TO_NID(kaddr) < NR_NODES)
++#define virt_addr_valid(kaddr)        (KVADDR_TO_NID(kaddr) < MAX_NUMNODES)
+ /*
+  * Common discontigmem stuff.
+@@ -109,7 +109,7 @@ static inline void *phys_to_virt(unsigne
+  */
+ #define PHYS_TO_NID(addr)     PFN_TO_NID((addr) >> PAGE_SHIFT)
+-#endif
++#endif /* !CONFIG_DISCONTIGMEM */
+ /*
+  * For BIO.  "will die".  Kill me when bio_to_phys() and bvec_to_phys() die.
+--- linux-2.6.0-test6/include/asm-arm/numnodes.h       2003-06-14 12:18:07.000000000 -0700
++++ 25/include/asm-arm/numnodes.h      2003-10-05 00:34:40.000000000 -0700
+@@ -10,8 +10,7 @@
+ #ifndef __ASM_ARM_NUMNODES_H
+ #define __ASM_ARM_NUMNODES_H
+-#include <asm/memory.h>
+-
+-#define MAX_NUMNODES  NR_NODES
++/* Max 4 Nodes */
++#define NODES_SHIFT   2
+ #endif
+--- linux-2.6.0-test6/include/asm-arm/unistd.h 2003-09-08 13:58:59.000000000 -0700
++++ 25/include/asm-arm/unistd.h        2003-10-05 00:33:24.000000000 -0700
+@@ -32,7 +32,7 @@
+ #define __NR_write                    (__NR_SYSCALL_BASE+  4)
+ #define __NR_open                     (__NR_SYSCALL_BASE+  5)
+ #define __NR_close                    (__NR_SYSCALL_BASE+  6)
+-#define __NR_waitpid                  (__NR_SYSCALL_BASE+  7) /* removed */
++                                      /* 7 was sys_waitpid */
+ #define __NR_creat                    (__NR_SYSCALL_BASE+  8)
+ #define __NR_link                     (__NR_SYSCALL_BASE+  9)
+ #define __NR_unlink                   (__NR_SYSCALL_BASE+ 10)
+@@ -42,7 +42,7 @@
+ #define __NR_mknod                    (__NR_SYSCALL_BASE+ 14)
+ #define __NR_chmod                    (__NR_SYSCALL_BASE+ 15)
+ #define __NR_lchown                   (__NR_SYSCALL_BASE+ 16)
+-#define __NR_break                    (__NR_SYSCALL_BASE+ 17) /* removed */
++                                      /* 17 was sys_break */
+                                       /* 18 was sys_stat */
+ #define __NR_lseek                    (__NR_SYSCALL_BASE+ 19)
+ #define __NR_getpid                   (__NR_SYSCALL_BASE+ 20)
+@@ -53,14 +53,14 @@
+ #define __NR_stime                    (__NR_SYSCALL_BASE+ 25)
+ #define __NR_ptrace                   (__NR_SYSCALL_BASE+ 26)
+ #define __NR_alarm                    (__NR_SYSCALL_BASE+ 27)
+-
++                                      /* 28 was sys_fstat */
+ #define __NR_pause                    (__NR_SYSCALL_BASE+ 29)
+ #define __NR_utime                    (__NR_SYSCALL_BASE+ 30)
+-#define __NR_stty                     (__NR_SYSCALL_BASE+ 31) /* removed */
+-#define __NR_gtty                     (__NR_SYSCALL_BASE+ 32) /* removed */
++                                      /* 31 was sys_stty */
++                                      /* 32 was sys_gtty */
+ #define __NR_access                   (__NR_SYSCALL_BASE+ 33)
+ #define __NR_nice                     (__NR_SYSCALL_BASE+ 34)
+-#define __NR_ftime                    (__NR_SYSCALL_BASE+ 35) /* removed */
++                                      /* 35 was sys_ftime */
+ #define __NR_sync                     (__NR_SYSCALL_BASE+ 36)
+ #define __NR_kill                     (__NR_SYSCALL_BASE+ 37)
+ #define __NR_rename                   (__NR_SYSCALL_BASE+ 38)
+@@ -69,21 +69,21 @@
+ #define __NR_dup                      (__NR_SYSCALL_BASE+ 41)
+ #define __NR_pipe                     (__NR_SYSCALL_BASE+ 42)
+ #define __NR_times                    (__NR_SYSCALL_BASE+ 43)
+-#define __NR_prof                     (__NR_SYSCALL_BASE+ 44) /* removed */
++                                      /* 44 was sys_prof */
+ #define __NR_brk                      (__NR_SYSCALL_BASE+ 45)
+ #define __NR_setgid                   (__NR_SYSCALL_BASE+ 46)
+ #define __NR_getgid                   (__NR_SYSCALL_BASE+ 47)
+-#define __NR_signal                   (__NR_SYSCALL_BASE+ 48) /* removed */
++                                      /* 48 was sys_signal */
+ #define __NR_geteuid                  (__NR_SYSCALL_BASE+ 49)
+ #define __NR_getegid                  (__NR_SYSCALL_BASE+ 50)
+ #define __NR_acct                     (__NR_SYSCALL_BASE+ 51)
+ #define __NR_umount2                  (__NR_SYSCALL_BASE+ 52)
+-#define __NR_lock                     (__NR_SYSCALL_BASE+ 53) /* removed */
++                                      /* 53 was sys_lock */
+ #define __NR_ioctl                    (__NR_SYSCALL_BASE+ 54)
+ #define __NR_fcntl                    (__NR_SYSCALL_BASE+ 55)
+-#define __NR_mpx                      (__NR_SYSCALL_BASE+ 56) /* removed */
++                                      /* 56 was sys_mpx */
+ #define __NR_setpgid                  (__NR_SYSCALL_BASE+ 57)
+-#define __NR_ulimit                   (__NR_SYSCALL_BASE+ 58) /* removed */
++                                      /* 58 was sys_ulimit */
+                                       /* 59 was sys_olduname */
+ #define __NR_umask                    (__NR_SYSCALL_BASE+ 60)
+ #define __NR_chroot                   (__NR_SYSCALL_BASE+ 61)
+@@ -93,8 +93,8 @@
+ #define __NR_getpgrp                  (__NR_SYSCALL_BASE+ 65)
+ #define __NR_setsid                   (__NR_SYSCALL_BASE+ 66)
+ #define __NR_sigaction                        (__NR_SYSCALL_BASE+ 67)
+-#define __NR_sgetmask                 (__NR_SYSCALL_BASE+ 68) /* removed */
+-#define __NR_ssetmask                 (__NR_SYSCALL_BASE+ 69) /* removed */
++                                      /* 68 was sys_sgetmask */
++                                      /* 69 was sys_ssetmask */
+ #define __NR_setreuid                 (__NR_SYSCALL_BASE+ 70)
+ #define __NR_setregid                 (__NR_SYSCALL_BASE+ 71)
+ #define __NR_sigsuspend                       (__NR_SYSCALL_BASE+ 72)
+@@ -123,10 +123,10 @@
+ #define __NR_fchown                   (__NR_SYSCALL_BASE+ 95)
+ #define __NR_getpriority              (__NR_SYSCALL_BASE+ 96)
+ #define __NR_setpriority              (__NR_SYSCALL_BASE+ 97)
+-#define __NR_profil                   (__NR_SYSCALL_BASE+ 98) /* removed */
++                                      /* 98 was sys_profil */
+ #define __NR_statfs                   (__NR_SYSCALL_BASE+ 99)
+ #define __NR_fstatfs                  (__NR_SYSCALL_BASE+100)
+-#define __NR_ioperm                   (__NR_SYSCALL_BASE+101)
++                                      /* 101 was sys_ioperm */
+ #define __NR_socketcall                       (__NR_SYSCALL_BASE+102)
+ #define __NR_syslog                   (__NR_SYSCALL_BASE+103)
+ #define __NR_setitimer                        (__NR_SYSCALL_BASE+104)
+@@ -137,7 +137,7 @@
+                                       /* 109 was sys_uname */
+                                       /* 110 was sys_iopl */
+ #define __NR_vhangup                  (__NR_SYSCALL_BASE+111)
+-#define __NR_idle                     (__NR_SYSCALL_BASE+112)
++                                      /* 112 was sys_idle */
+ #define __NR_syscall                  (__NR_SYSCALL_BASE+113) /* syscall to call a syscall! */
+ #define __NR_wait4                    (__NR_SYSCALL_BASE+114)
+ #define __NR_swapoff                  (__NR_SYSCALL_BASE+115)
+@@ -148,21 +148,21 @@
+ #define __NR_clone                    (__NR_SYSCALL_BASE+120)
+ #define __NR_setdomainname            (__NR_SYSCALL_BASE+121)
+ #define __NR_uname                    (__NR_SYSCALL_BASE+122)
+-#define __NR_modify_ldt                       (__NR_SYSCALL_BASE+123)
++                                      /* 123 was sys_modify_ldt */
+ #define __NR_adjtimex                 (__NR_SYSCALL_BASE+124)
+ #define __NR_mprotect                 (__NR_SYSCALL_BASE+125)
+ #define __NR_sigprocmask              (__NR_SYSCALL_BASE+126)
+-#define __NR_create_module            (__NR_SYSCALL_BASE+127) /* removed */
++                                      /* 127 was sys_create_module */
+ #define __NR_init_module              (__NR_SYSCALL_BASE+128)
+ #define __NR_delete_module            (__NR_SYSCALL_BASE+129)
+-#define __NR_get_kernel_syms          (__NR_SYSCALL_BASE+130) /* removed */
++                                      /* 130 was sys_get_kernel_syms */
+ #define __NR_quotactl                 (__NR_SYSCALL_BASE+131)
+ #define __NR_getpgid                  (__NR_SYSCALL_BASE+132)
+ #define __NR_fchdir                   (__NR_SYSCALL_BASE+133)
+ #define __NR_bdflush                  (__NR_SYSCALL_BASE+134)
+ #define __NR_sysfs                    (__NR_SYSCALL_BASE+135)
+ #define __NR_personality              (__NR_SYSCALL_BASE+136)
+-#define __NR_afs_syscall              (__NR_SYSCALL_BASE+137) /* Syscall for Andrew File System */
++                                      /* 137 was sys_afs_syscall */
+ #define __NR_setfsuid                 (__NR_SYSCALL_BASE+138)
+ #define __NR_setfsgid                 (__NR_SYSCALL_BASE+139)
+ #define __NR__llseek                  (__NR_SYSCALL_BASE+140)
+@@ -191,8 +191,8 @@
+ #define __NR_mremap                   (__NR_SYSCALL_BASE+163)
+ #define __NR_setresuid                        (__NR_SYSCALL_BASE+164)
+ #define __NR_getresuid                        (__NR_SYSCALL_BASE+165)
+-#define __NR_vm86                     (__NR_SYSCALL_BASE+166) /* removed */
+-#define __NR_query_module             (__NR_SYSCALL_BASE+167) /* removed */
++                                      /* 166 was sys_vm86 */
++                                      /* 167 was sys_query_module */
+ #define __NR_poll                     (__NR_SYSCALL_BASE+168)
+ #define __NR_nfsservctl                       (__NR_SYSCALL_BASE+169)
+ #define __NR_setresgid                        (__NR_SYSCALL_BASE+170)
+--- linux-2.6.0-test6/include/asm-cris/arch-v10/pgtable.h      2003-07-10 18:50:32.000000000 -0700
++++ 25/include/asm-cris/arch-v10/pgtable.h     2003-10-05 00:33:24.000000000 -0700
+@@ -7,11 +7,9 @@
+ #ifdef CONFIG_CRIS_LOW_MAP
+ #define VMALLOC_START     KSEG_7
+-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+ #define VMALLOC_END       KSEG_8
+ #else
+ #define VMALLOC_START     KSEG_D
+-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+ #define VMALLOC_END       KSEG_E
+ #endif
+--- linux-2.6.0-test6/include/asm-cris/cacheflush.h    2003-07-10 18:50:32.000000000 -0700
++++ 25/include/asm-cris/cacheflush.h   2003-10-05 00:33:24.000000000 -0700
+@@ -16,6 +16,13 @@
+ #define flush_icache_range(start, end)                do { } while (0)
+ #define flush_icache_page(vma,pg)             do { } while (0)
+ #define flush_icache_user_range(vma,pg,adr,len)       do { } while (0)
++#define flush_cache_vmap(start, end)          do { } while (0)
++#define flush_cache_vunmap(start, end)                do { } while (0)
++
++#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
++      memcpy(dst, src, len)
++#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
++      memcpy(dst, src, len)
+ void global_flush_tlb(void); 
+ int change_page_attr(struct page *page, int numpages, pgprot_t prot);
+--- linux-2.6.0-test6/include/asm-h8300/cacheflush.h   2003-06-14 12:18:07.000000000 -0700
++++ 25/include/asm-h8300/cacheflush.h  2003-10-05 00:33:24.000000000 -0700
+@@ -11,7 +11,6 @@
+  */
+ #define flush_cache_all()
+-#define       flush_cache_all()
+ #define       flush_cache_mm(mm)
+ #define       flush_cache_range(vma,a,b)
+ #define       flush_cache_page(vma,p)
+@@ -20,6 +19,8 @@
+ #define       flush_icache()
+ #define       flush_icache_page(vma,page)
+ #define       flush_icache_range(start,len)
++#define flush_cache_vmap(start, end)
++#define flush_cache_vunmap(start, end)
+ #define       cache_push_v(vaddr,len)
+ #define       cache_push(paddr,len)
+ #define       cache_clear(paddr,len)
+@@ -28,4 +29,9 @@
+ #define       flush_icache_user_range(vma,page,addr,len)
++#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
++      memcpy(dst, src, len)
++#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
++      memcpy(dst, src, len)
++
+ #endif /* _ASM_H8300_CACHEFLUSH_H */
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/include/asm-i386/atomic_kmap.h  2003-10-05 00:36:48.000000000 -0700
+@@ -0,0 +1,95 @@
++/*
++ * atomic_kmap.h: temporary virtual kernel memory mappings
++ *
++ * Copyright (C) 2003 Ingo Molnar <mingo@redhat.com>
++ */
++
++#ifndef _ASM_ATOMIC_KMAP_H
++#define _ASM_ATOMIC_KMAP_H
++
++#ifdef __KERNEL__
++
++#include <linux/config.h>
++#include <asm/tlbflush.h>
++
++#ifdef CONFIG_DEBUG_HIGHMEM
++#define HIGHMEM_DEBUG 1
++#else
++#define HIGHMEM_DEBUG 0
++#endif
++
++extern pte_t *kmap_pte;
++#define kmap_prot PAGE_KERNEL
++
++#define PKMAP_BASE (0xff000000UL)
++#define NR_SHARED_PMDS ((0xffffffff-PKMAP_BASE+1)/PMD_SIZE)
++
++static inline unsigned long __kmap_atomic_vaddr(enum km_type type)
++{
++      enum fixed_addresses idx;
++
++      idx = type + KM_TYPE_NR*smp_processor_id();
++      return __fix_to_virt(FIX_KMAP_BEGIN + idx);
++}
++
++static inline void *__kmap_atomic_noflush(struct page *page, enum km_type type)
++{
++      enum fixed_addresses idx;
++      unsigned long vaddr;
++
++      idx = type + KM_TYPE_NR*smp_processor_id();
++      vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
++      /*
++       * NOTE: entries that rely on some secondary TLB-flush
++       * effect must not be global:
++       */
++      set_pte(kmap_pte-idx, mk_pte(page, PAGE_KERNEL));
++
++      return (void*) vaddr;
++}
++
++static inline void *__kmap_atomic(struct page *page, enum km_type type)
++{
++      enum fixed_addresses idx;
++      unsigned long vaddr;
++
++      idx = type + KM_TYPE_NR*smp_processor_id();
++      vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
++#if HIGHMEM_DEBUG
++      BUG_ON(!pte_none(*(kmap_pte-idx)));
++#else
++      /*
++       * Performance optimization - do not flush if the new
++       * pte is the same as the old one:
++       */
++      if (pte_val(*(kmap_pte-idx)) == pte_val(mk_pte(page, kmap_prot)))
++              return (void *) vaddr;
++#endif
++      set_pte(kmap_pte-idx, mk_pte(page, kmap_prot));
++      __flush_tlb_one(vaddr);
++
++      return (void*) vaddr;
++}
++
++static inline void __kunmap_atomic(void *kvaddr, enum km_type type)
++{
++#if HIGHMEM_DEBUG
++      unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
++      enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();
++
++      BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN+idx));
++      /*
++       * force other mappings to Oops if they'll try to access
++       * this pte without first remap it
++       */
++      pte_clear(kmap_pte-idx);
++      __flush_tlb_one(vaddr);
++#endif
++}
++
++#define __kunmap_atomic_type(type) \
++              __kunmap_atomic((void *)__kmap_atomic_vaddr(type), (type))
++
++#endif /* __KERNEL__ */
++
++#endif /* _ASM_ATOMIC_KMAP_H */
+--- linux-2.6.0-test6/include/asm-i386/bugs.h  2003-09-08 13:58:59.000000000 -0700
++++ 25/include/asm-i386/bugs.h 2003-10-05 00:33:38.000000000 -0700
+@@ -1,11 +1,11 @@
+ /*
+  *  include/asm-i386/bugs.h
+  *
+- *  Copyright (C) 1994  Linus Torvalds
++ *  Copyright (C) 1994        Linus Torvalds
+  *
+  *  Cyrix stuff, June 1998 by:
+  *    - Rafael R. Reilova (moved everything from head.S),
+- *        <rreilova@ececs.uc.edu>
++ *      <rreilova@ececs.uc.edu>
+  *    - Channing Corn (tests & fixes),
+  *    - Andrew D. Balsa (code cleanup).
+  *
+@@ -25,7 +25,20 @@
+ #include <asm/processor.h>
+ #include <asm/i387.h>
+ #include <asm/msr.h>
+-
++#ifdef CONFIG_KGDB
++/*
++ * Provied the command line "gdb" initial break
++ */
++int __init kgdb_initial_break(char * str)
++{
++      if (*str == '\0'){
++              breakpoint();
++              return 1;
++      }
++      return 0;
++}
++__setup("gdb",kgdb_initial_break);
++#endif
+ static int __init no_halt(char *s)
+ {
+       boot_cpu_data.hlt_works_ok = 0;
+@@ -140,7 +153,7 @@ static void __init check_popad(void)
+         : "ecx", "edi" );
+       /* If this fails, it means that any user program may lock the CPU hard. Too bad. */
+       if (res != 12345678) printk( "Buggy.\n" );
+-                      else printk( "OK.\n" );
++                      else printk( "OK.\n" );
+ #endif
+ }
+--- linux-2.6.0-test6/include/asm-i386/cacheflush.h    2003-07-10 18:50:32.000000000 -0700
++++ 25/include/asm-i386/cacheflush.h   2003-10-05 00:33:24.000000000 -0700
+@@ -13,6 +13,13 @@
+ #define flush_icache_range(start, end)                do { } while (0)
+ #define flush_icache_page(vma,pg)             do { } while (0)
+ #define flush_icache_user_range(vma,pg,adr,len)       do { } while (0)
++#define flush_cache_vmap(start, end)          do { } while (0)
++#define flush_cache_vunmap(start, end)                do { } while (0)
++
++#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
++      memcpy(dst, src, len)
++#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
++      memcpy(dst, src, len)
+ void global_flush_tlb(void); 
+ int change_page_attr(struct page *page, int numpages, pgprot_t prot);
+--- linux-2.6.0-test6/include/asm-i386/checksum.h      2003-06-14 12:18:29.000000000 -0700
++++ 25/include/asm-i386/checksum.h     2003-10-05 00:36:48.000000000 -0700
+@@ -25,7 +25,7 @@ asmlinkage unsigned int csum_partial(con
+  * better 64-bit) boundary
+  */
+-asmlinkage unsigned int csum_partial_copy_generic( const char *src, char *dst, int len, int sum,
++asmlinkage unsigned int direct_csum_partial_copy_generic( const char *src, char *dst, int len, int sum,
+                                                  int *src_err_ptr, int *dst_err_ptr);
+ /*
+@@ -39,14 +39,19 @@ static __inline__
+ unsigned int csum_partial_copy_nocheck ( const char *src, char *dst,
+                                       int len, int sum)
+ {
+-      return csum_partial_copy_generic ( src, dst, len, sum, NULL, NULL);
++      /*
++       * The direct function is OK for kernel-space => kernel-space copies:
++       */
++      return direct_csum_partial_copy_generic ( src, dst, len, sum, NULL, NULL);
+ }
+ static __inline__
+ unsigned int csum_partial_copy_from_user ( const char *src, char *dst,
+                                               int len, int sum, int *err_ptr)
+ {
+-      return csum_partial_copy_generic ( src, dst, len, sum, err_ptr, NULL);
++      if (copy_from_user(dst, src, len))
++              *err_ptr = -EFAULT;
++      return csum_partial(dst, len, sum);
+ }
+ /*
+@@ -171,11 +176,26 @@ static __inline__ unsigned short int csu
+  *    Copy and checksum to user
+  */
+ #define HAVE_CSUM_COPY_USER
+-static __inline__ unsigned int csum_and_copy_to_user(const char *src, char *dst,
++static __inline__ unsigned int direct_csum_and_copy_to_user(const char *src, char *dst,
+                                   int len, int sum, int *err_ptr)
+ {
+       if (access_ok(VERIFY_WRITE, dst, len))
+-              return csum_partial_copy_generic(src, dst, len, sum, NULL, err_ptr);
++              return direct_csum_partial_copy_generic(src, dst, len, sum, NULL, err_ptr);
++
++      if (len)
++              *err_ptr = -EFAULT;
++
++      return -1; /* invalid checksum */
++}
++
++static __inline__ unsigned int csum_and_copy_to_user(const char *src, char *dst,
++                                  int len, int sum, int *err_ptr)
++{
++      if (access_ok(VERIFY_WRITE, dst, len)) {
++              if (copy_to_user(dst, src, len))
++                      *err_ptr = -EFAULT;
++              return csum_partial(src, len, sum);
++      }
+       if (len)
+               *err_ptr = -EFAULT;
+--- linux-2.6.0-test6/include/asm-i386/desc.h  2003-06-14 12:17:55.000000000 -0700
++++ 25/include/asm-i386/desc.h 2003-10-05 00:36:48.000000000 -0700
+@@ -21,6 +21,13 @@ struct Xgt_desc_struct {
+ extern struct Xgt_desc_struct idt_descr, cpu_gdt_descr[NR_CPUS];
++extern void trap_init_virtual_IDT(void);
++extern void trap_init_virtual_GDT(void);
++
++asmlinkage int system_call(void);
++asmlinkage void lcall7(void);
++asmlinkage void lcall27(void);
++
+ #define load_TR_desc() __asm__ __volatile__("ltr %%ax"::"a" (GDT_ENTRY_TSS*8))
+ #define load_LDT_desc() __asm__ __volatile__("lldt %%ax"::"a" (GDT_ENTRY_LDT*8))
+@@ -30,6 +37,7 @@ extern struct Xgt_desc_struct idt_descr,
+  */
+ extern struct desc_struct default_ldt[];
+ extern void set_intr_gate(unsigned int irq, void * addr);
++extern void set_trap_gate(unsigned int n, void *addr);
+ #define _set_tssldt_desc(n,addr,limit,type) \
+ __asm__ __volatile__ ("movw %w3,0(%2)\n\t" \
+@@ -90,31 +98,8 @@ static inline void load_TLS(struct threa
+ #undef C
+ }
+-static inline void clear_LDT(void)
+-{
+-      int cpu = get_cpu();
+-
+-      set_ldt_desc(cpu, &default_ldt[0], 5);
+-      load_LDT_desc();
+-      put_cpu();
+-}
+-
+-/*
+- * load one particular LDT into the current CPU
+- */
+-static inline void load_LDT_nolock(mm_context_t *pc, int cpu)
+-{
+-      void *segments = pc->ldt;
+-      int count = pc->size;
+-
+-      if (likely(!count)) {
+-              segments = &default_ldt[0];
+-              count = 5;
+-      }
+-              
+-      set_ldt_desc(cpu, segments, count);
+-      load_LDT_desc();
+-}
++extern struct page *default_ldt_page;
++extern void load_LDT_nolock(mm_context_t *pc, int cpu);
+ static inline void load_LDT(mm_context_t *pc)
+ {
+@@ -123,6 +108,6 @@ static inline void load_LDT(mm_context_t
+       put_cpu();
+ }
+-#endif /* !__ASSEMBLY__ */
++#endif /* !__ASSEMBLY__ */
+ #endif
+--- linux-2.6.0-test6/include/asm-i386/elf.h   2003-06-14 12:18:25.000000000 -0700
++++ 25/include/asm-i386/elf.h  2003-10-05 00:33:24.000000000 -0700
+@@ -127,11 +127,6 @@ extern int dump_task_extended_fpu (struc
+ #define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs) dump_task_fpu(tsk, elf_fpregs)
+ #define ELF_CORE_COPY_XFPREGS(tsk, elf_xfpregs) dump_task_extended_fpu(tsk, elf_xfpregs)
+-#ifdef CONFIG_SMP
+-extern void dump_smp_unlazy_fpu(void);
+-#define ELF_CORE_SYNC dump_smp_unlazy_fpu
+-#endif
+-
+ #define VSYSCALL_BASE (__fix_to_virt(FIX_VSYSCALL))
+ #define VSYSCALL_EHDR ((const struct elfhdr *) VSYSCALL_BASE)
+ #define VSYSCALL_ENTRY        ((unsigned long) &__kernel_vsyscall)
+@@ -162,7 +157,10 @@ do {                                                                            \
+       for (i = 0; i < VSYSCALL_EHDR->e_phnum; ++i) {                        \
+               struct elf_phdr phdr = vsyscall_phdrs[i];                     \
+               if (phdr.p_type == PT_LOAD) {                                 \
++                      BUG_ON(ofs != 0);                                     \
+                       ofs = phdr.p_offset = offset;                         \
++                      phdr.p_memsz = PAGE_ALIGN(phdr.p_memsz);              \
++                      phdr.p_filesz = phdr.p_memsz;                         \
+                       offset += phdr.p_filesz;                              \
+               }                                                             \
+               else                                                          \
+@@ -180,7 +178,7 @@ do {                                                                             \
+       for (i = 0; i < VSYSCALL_EHDR->e_phnum; ++i) {                        \
+               if (vsyscall_phdrs[i].p_type == PT_LOAD)                      \
+                       DUMP_WRITE((void *) vsyscall_phdrs[i].p_vaddr,        \
+-                                 vsyscall_phdrs[i].p_filesz);               \
++                                 PAGE_ALIGN(vsyscall_phdrs[i].p_memsz));    \
+       }                                                                     \
+ } while (0)
+--- linux-2.6.0-test6/include/asm-i386/fixmap.h        2003-06-14 12:17:57.000000000 -0700
++++ 25/include/asm-i386/fixmap.h       2003-10-05 00:36:48.000000000 -0700
+@@ -18,17 +18,15 @@
+ #include <asm/acpi.h>
+ #include <asm/apicdef.h>
+ #include <asm/page.h>
+-#ifdef CONFIG_HIGHMEM
+ #include <linux/threads.h>
+ #include <asm/kmap_types.h>
+-#endif
+ /*
+  * Here we define all the compile-time 'special' virtual
+  * addresses. The point is to have a constant address at
+  * compile time, but to set the physical address only
+- * in the boot process. We allocate these special addresses
+- * from the end of virtual memory (0xfffff000) backwards.
++ * in the boot process. We allocate these special  addresses
++ * from the end of virtual memory (0xffffe000) backwards.
+  * Also this lets us do fail-safe vmalloc(), we
+  * can guarantee that these special addresses and
+  * vmalloc()-ed addresses never overlap.
+@@ -41,11 +39,20 @@
+  * TLB entries of such buffers will not be flushed across
+  * task switches.
+  */
++
++/*
++ * on UP currently we will have no trace of the fixmap mechanizm,
++ * no page table allocations, etc. This might change in the
++ * future, say framebuffers for the console driver(s) could be
++ * fix-mapped?
++ */
+ enum fixed_addresses {
+       FIX_HOLE,
+       FIX_VSYSCALL,
+ #ifdef CONFIG_X86_LOCAL_APIC
+       FIX_APIC_BASE,  /* local (CPU) APIC) -- required for SMP or not */
++#else
++      FIX_VSTACK_HOLE_1,
+ #endif
+ #ifdef CONFIG_X86_IO_APIC
+       FIX_IO_APIC_BASE_0,
+@@ -57,16 +64,21 @@ enum fixed_addresses {
+       FIX_LI_PCIA,    /* Lithium PCI Bridge A */
+       FIX_LI_PCIB,    /* Lithium PCI Bridge B */
+ #endif
+-#ifdef CONFIG_X86_F00F_BUG
+-      FIX_F00F_IDT,   /* Virtual mapping for IDT */
+-#endif
++      FIX_IDT,
++      FIX_GDT_1,
++      FIX_GDT_0,
++      FIX_TSS_3,
++      FIX_TSS_2,
++      FIX_TSS_1,
++      FIX_TSS_0,
++      FIX_ENTRY_TRAMPOLINE_1,
++      FIX_ENTRY_TRAMPOLINE_0,
+ #ifdef CONFIG_X86_CYCLONE_TIMER
+       FIX_CYCLONE_TIMER, /*cyclone timer register*/
++      FIX_VSTACK_HOLE_2,
+ #endif 
+-#ifdef CONFIG_HIGHMEM
+       FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
+       FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
+-#endif
+ #ifdef CONFIG_ACPI_BOOT
+       FIX_ACPI_BEGIN,
+       FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1,
+@@ -95,12 +107,15 @@ extern void __set_fixmap (enum fixed_add
+               __set_fixmap(idx, 0, __pgprot(0))
+ /*
+- * used by vmalloc.c.
++ * used by vmalloc.c and various other places.
+  *
+  * Leave one empty page between vmalloc'ed areas and
+  * the start of the fixmap.
++ *
++ * IMPORTANT: dont change FIXADDR_TOP without adjusting KM_VSTACK0
++ * and KM_VSTACK1 so that the virtual stack is 8K aligned.
+  */
+-#define FIXADDR_TOP   (0xfffff000UL)
++#define FIXADDR_TOP   (0xffffe000UL)
+ #define __FIXADDR_SIZE        (__end_of_permanent_fixed_addresses << PAGE_SHIFT)
+ #define FIXADDR_START (FIXADDR_TOP - __FIXADDR_SIZE)
+--- linux-2.6.0-test6/include/asm-i386/highmem.h       2003-08-22 19:23:42.000000000 -0700
++++ 25/include/asm-i386/highmem.h      2003-10-05 00:36:48.000000000 -0700
+@@ -25,26 +25,19 @@
+ #include <linux/threads.h>
+ #include <asm/kmap_types.h>
+ #include <asm/tlbflush.h>
++#include <asm/atomic_kmap.h>
+ /* declarations for highmem.c */
+ extern unsigned long highstart_pfn, highend_pfn;
+-extern pte_t *kmap_pte;
+-extern pgprot_t kmap_prot;
+ extern pte_t *pkmap_page_table;
+-
+-extern void kmap_init(void);
++extern void kmap_init(void) __init;
+ /*
+  * Right now we initialize only a single pte table. It can be extended
+  * easily, subsequent pte tables have to be allocated in one physical
+  * chunk of RAM.
+  */
+-#if NR_CPUS <= 32
+-#define PKMAP_BASE (0xff800000UL)
+-#else
+-#define PKMAP_BASE (0xff600000UL)
+-#endif
+ #ifdef CONFIG_X86_PAE
+ #define LAST_PKMAP 512
+ #else
+@@ -63,6 +56,8 @@ void *kmap_atomic(struct page *page, enu
+ void kunmap_atomic(void *kvaddr, enum km_type type);
+ struct page *kmap_atomic_to_page(void *ptr);
++#define flush_cache_kmaps()   do { } while (0)
++
+ #endif /* __KERNEL__ */
+ #endif /* _ASM_HIGHMEM_H */
+--- linux-2.6.0-test6/include/asm-i386/hw_irq.h        2003-08-22 19:23:42.000000000 -0700
++++ 25/include/asm-i386/hw_irq.h       2003-10-05 00:36:27.000000000 -0700
+@@ -25,8 +25,9 @@
+  * Interrupt entry/exit code at both C and assembly level
+  */
+-extern int irq_vector[NR_IRQS];
+-#define IO_APIC_VECTOR(irq)   irq_vector[irq]
++extern u8 *irq_vector;
++#define IO_APIC_VECTOR(irq)   ((int)irq_vector[(irq)])
++extern int nr_irqs;
+ extern void (*interrupt[NR_IRQS])(void);
+@@ -41,6 +42,7 @@ asmlinkage void apic_timer_interrupt(voi
+ asmlinkage void error_interrupt(void);
+ asmlinkage void spurious_interrupt(void);
+ asmlinkage void thermal_interrupt(struct pt_regs);
++#define platform_legacy_irq(irq)      ((irq) < 16)
+ #endif
+ void mask_irq(unsigned int irq);
+--- linux-2.6.0-test6/include/asm-i386/io_apic.h       2003-08-22 19:23:42.000000000 -0700
++++ 25/include/asm-i386/io_apic.h      2003-10-05 00:36:21.000000000 -0700
+@@ -13,6 +13,46 @@
+ #ifdef CONFIG_X86_IO_APIC
++#ifdef CONFIG_PCI_USE_VECTOR
++static inline int use_pci_vector(void)        {return 1;}
++static inline void disable_edge_ioapic_vector(unsigned int vector) { }
++static inline void mask_and_ack_level_ioapic_vector(unsigned int vector) { }
++static inline void end_edge_ioapic_vector (unsigned int vector) { }
++#define startup_level_ioapic  startup_level_ioapic_vector
++#define shutdown_level_ioapic mask_IO_APIC_vector
++#define enable_level_ioapic   unmask_IO_APIC_vector
++#define disable_level_ioapic  mask_IO_APIC_vector
++#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_vector
++#define end_level_ioapic      end_level_ioapic_vector
++#define set_ioapic_affinity   set_ioapic_affinity_vector
++
++#define startup_edge_ioapic   startup_edge_ioapic_vector
++#define shutdown_edge_ioapic  disable_edge_ioapic_vector
++#define enable_edge_ioapic    unmask_IO_APIC_vector
++#define disable_edge_ioapic   disable_edge_ioapic_vector
++#define ack_edge_ioapic       ack_edge_ioapic_vector
++#define end_edge_ioapic       end_edge_ioapic_vector
++#else
++static inline int use_pci_vector(void)        {return 0;}
++static inline void disable_edge_ioapic_irq(unsigned int irq) { }
++static inline void mask_and_ack_level_ioapic_irq(unsigned int irq) { }
++static inline void end_edge_ioapic_irq (unsigned int irq) { }
++#define startup_level_ioapic  startup_level_ioapic_irq
++#define shutdown_level_ioapic mask_IO_APIC_irq
++#define enable_level_ioapic   unmask_IO_APIC_irq
++#define disable_level_ioapic  mask_IO_APIC_irq
++#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_irq
++#define end_level_ioapic      end_level_ioapic_irq
++#define set_ioapic_affinity   set_ioapic_affinity_irq
++
++#define startup_edge_ioapic   startup_edge_ioapic_irq
++#define shutdown_edge_ioapic  disable_edge_ioapic_irq
++#define enable_edge_ioapic    unmask_IO_APIC_irq
++#define disable_edge_ioapic   disable_edge_ioapic_irq
++#define ack_edge_ioapic       ack_edge_ioapic_irq
++#define end_edge_ioapic       end_edge_ioapic_irq
++#endif
++
+ #define APIC_MISMATCH_DEBUG
+ #define IO_APIC_BASE(idx) \
+@@ -177,4 +217,6 @@ extern int io_apic_set_pci_routing (int 
+ #define io_apic_assign_pci_irqs 0
+ #endif
++extern int assign_irq_vector(int irq);
++
+ #endif
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/include/asm-i386/kgdb.h 2003-10-05 00:33:50.000000000 -0700
+@@ -0,0 +1,76 @@
++#ifndef __KGDB
++#define __KGDB
++
++/*
++ * This file should not include ANY others.  This makes it usable
++ * most anywhere without the fear of include order or inclusion.
++ * Make it so!
++ *
++ * This file may be included all the time.  It is only active if
++ * CONFIG_KGDB is defined, otherwise it stubs out all the macros
++ * and entry points.
++ */
++#if defined(CONFIG_KGDB) && !defined(__ASSEMBLY__)
++
++extern void breakpoint(void);
++#define INIT_KGDB_INTS kgdb_enable_ints()
++
++#ifndef BREAKPOINT
++#define BREAKPOINT   asm("   int $3")
++#endif
++
++struct sk_buff;
++
++extern int kgdb_eth;
++extern unsigned kgdb_remoteip;
++extern unsigned short kgdb_listenport;
++extern unsigned short kgdb_sendport;
++extern unsigned char kgdb_remotemac[6];
++extern unsigned char kgdb_localmac[6];
++extern int kgdb_eth_need_breakpoint[];
++
++extern int kgdb_tty_hook(void);
++extern int kgdb_eth_hook(void);
++extern int gdb_net_interrupt(struct sk_buff *skb);
++
++/*
++ * GDB debug stub (or any debug stub) can point the 'linux_debug_hook'
++ * pointer to its routine and it will be entered as the first thing
++ * when a trap occurs.
++ *
++ * Return values are, at present, undefined.
++ *
++ * The debug hook routine does not necessarily return to its caller.
++ * It has the register image and thus may choose to resume execution
++ * anywhere it pleases.
++ */
++struct pt_regs;
++struct sk_buff;
++
++extern int kgdb_handle_exception(int trapno,
++                               int signo, int err_code, struct pt_regs *regs);
++extern int in_kgdb(struct pt_regs *regs);
++extern int kgdb_net_interrupt(struct sk_buff *skb);
++
++#ifdef CONFIG_KGDB_TS
++void kgdb_tstamp(int line, char *source, int data0, int data1);
++/*
++ * This is the time stamp function.  The macro adds the source info and
++ * does a cast on the data to allow most any 32-bit value.
++ */
++
++#define kgdb_ts(data0,data1) kgdb_tstamp(__LINE__,__FILE__,(int)data0,(int)data1)
++#else
++#define kgdb_ts(data0,data1)
++#endif
++#else                         /* CONFIG_KGDB  && ! __ASSEMBLY__ ,stubs follow... */
++#ifndef BREAKPOINT
++#define BREAKPOINT
++#endif
++#define kgdb_ts(data0,data1)
++#define in_kgdb
++#define kgdb_handle_exception
++#define breakpoint
++#define INIT_KGDB_INTS
++#endif
++#endif                                /* __KGDB */
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/include/asm-i386/kgdb_local.h   2003-10-05 00:33:38.000000000 -0700
+@@ -0,0 +1,102 @@
++#ifndef __KGDB_LOCAL
++#define ___KGDB_LOCAL
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/serial.h>
++#include <linux/serialP.h>
++#include <linux/spinlock.h>
++#include <asm/processor.h>
++#include <asm/msr.h>
++#include <asm/kgdb.h>
++
++#define PORT 0x3f8
++#ifdef CONFIG_KGDB_PORT
++#undef PORT
++#define PORT CONFIG_KGDB_PORT
++#endif
++#define IRQ 4
++#ifdef CONFIG_KGDB_IRQ
++#undef IRQ
++#define IRQ CONFIG_KGDB_IRQ
++#endif
++#define SB_CLOCK 1843200
++#define SB_BASE (SB_CLOCK/16)
++#define SB_BAUD9600 SB_BASE/9600
++#define SB_BAUD192  SB_BASE/19200
++#define SB_BAUD384  SB_BASE/38400
++#define SB_BAUD576  SB_BASE/57600
++#define SB_BAUD1152 SB_BASE/115200
++#ifdef CONFIG_KGDB_9600BAUD
++#define SB_BAUD SB_BAUD9600
++#endif
++#ifdef CONFIG_KGDB_19200BAUD
++#define SB_BAUD SB_BAUD192
++#endif
++#ifdef CONFIG_KGDB_38400BAUD
++#define SB_BAUD SB_BAUD384
++#endif
++#ifdef CONFIG_KGDB_57600BAUD
++#define SB_BAUD SB_BAUD576
++#endif
++#ifdef CONFIG_KGDB_115200BAUD
++#define SB_BAUD SB_BAUD1152
++#endif
++#ifndef SB_BAUD
++#define SB_BAUD SB_BAUD1152   /* Start with this if not given */
++#endif
++
++#ifndef CONFIG_X86_TSC
++#undef rdtsc
++#define rdtsc(a,b) if (a++ > 10000){a = 0; b++;}
++#undef rdtscll
++#define rdtscll(s) s++
++#endif
++
++#ifdef _raw_read_unlock               /* must use a name that is "define"ed, not an inline */
++#undef spin_lock
++#undef spin_trylock
++#undef spin_unlock
++#define spin_lock      _raw_spin_lock
++#define spin_trylock   _raw_spin_trylock
++#define spin_unlock    _raw_spin_unlock
++#else
++#endif
++#undef spin_unlock_wait
++#define spin_unlock_wait(x)  do { cpu_relax(); barrier();} \
++                                     while(spin_is_locked(x))
++
++#define SB_IER 1
++#define SB_MCR UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS
++
++#define FLAGS 0
++#define SB_STATE { \
++     magic: SSTATE_MAGIC, \
++     baud_base: SB_BASE,  \
++     port:      PORT,     \
++     irq:       IRQ,      \
++     flags:     FLAGS,    \
++     custom_divisor:SB_BAUD}
++#define SB_INFO  { \
++      magic: SERIAL_MAGIC, \
++      port:  PORT,0,FLAGS, \
++      state: &state,       \
++      tty:   (struct tty_struct *)&state, \
++      IER:   SB_IER,       \
++      MCR:   SB_MCR}
++extern void putDebugChar(int);
++/* RTAI support needs us to really stop/start interrupts */
++
++#define kgdb_sti() __asm__ __volatile__("sti": : :"memory")
++#define kgdb_cli() __asm__ __volatile__("cli": : :"memory")
++#define kgdb_local_save_flags(x) __asm__ __volatile__(\
++                                   "pushfl ; popl %0":"=g" (x): /* no input */)
++#define kgdb_local_irq_restore(x) __asm__ __volatile__(\
++                                   "pushl %0 ; popfl": \
++                                     /* no output */ :"g" (x):"memory", "cc")
++#define kgdb_local_irq_save(x) kgdb_local_save_flags(x); kgdb_cli()
++
++#ifdef CONFIG_SERIAL
++extern void shutdown_for_kgdb(struct async_struct *info);
++#endif
++#define INIT_KDEBUG putDebugChar("+");
++#endif                                /* __KGDB_LOCAL */
+--- linux-2.6.0-test6/include/asm-i386/kmap_types.h    2003-06-14 12:18:28.000000000 -0700
++++ 25/include/asm-i386/kmap_types.h   2003-10-05 00:36:48.000000000 -0700
+@@ -3,30 +3,36 @@
+ #include <linux/config.h>
+-#ifdef CONFIG_DEBUG_HIGHMEM
+-# define D(n) __KM_FENCE_##n ,
+-#else
+-# define D(n)
+-#endif
+-
+ enum km_type {
+-D(0)  KM_BOUNCE_READ,
+-D(1)  KM_SKB_SUNRPC_DATA,
+-D(2)  KM_SKB_DATA_SOFTIRQ,
+-D(3)  KM_USER0,
+-D(4)  KM_USER1,
+-D(5)  KM_BIO_SRC_IRQ,
+-D(6)  KM_BIO_DST_IRQ,
+-D(7)  KM_PTE0,
+-D(8)  KM_PTE1,
+-D(9)  KM_PTE2,
+-D(10) KM_IRQ0,
+-D(11) KM_IRQ1,
+-D(12) KM_SOFTIRQ0,
+-D(13) KM_SOFTIRQ1,
+-D(14) KM_TYPE_NR
+-};
+-
+-#undef D
++      /*
++       * IMPORTANT: don't move these 3 entries, and only add entries in
++       * pairs: the 4G/4G virtual stack must be 8K aligned on each cpu.
++       */
++      KM_BOUNCE_READ,
++      KM_VSTACK1,
++      KM_VSTACK0,
++      KM_LDT_PAGE15,
++      KM_LDT_PAGE0 = KM_LDT_PAGE15 + 16-1,
++      KM_USER_COPY,
++      KM_VSTACK_HOLE,
++      KM_SKB_SUNRPC_DATA,
++      KM_SKB_DATA_SOFTIRQ,
++      KM_USER0,
++      KM_USER1,
++      KM_BIO_SRC_IRQ,
++      KM_BIO_DST_IRQ,
++      KM_PTE0,
++      KM_PTE1,
++      KM_PTE2,
++      KM_IRQ0,
++      KM_IRQ1,
++      KM_SOFTIRQ0,
++      KM_SOFTIRQ1,
++      /*
++       * Add new entries in pairs:
++       * the 4G/4G virtual stack must be 8K aligned on each cpu.
++       */
++      KM_TYPE_NR
++};
+ #endif
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/include/asm-i386/lockmeter.h    2003-10-05 00:36:40.000000000 -0700
+@@ -0,0 +1,127 @@
++/*
++ *  Copyright (C) 1999,2000 Silicon Graphics, Inc.
++ *
++ *  Written by John Hawkes (hawkes@sgi.com)
++ *  Based on klstat.h by Jack Steiner (steiner@sgi.com)
++ *
++ *  Modified by Ray Bryant (raybry@us.ibm.com)
++ *  Changes Copyright (C) 2000 IBM, Inc.
++ *  Added save of index in spinlock_t to improve efficiency
++ *  of "hold" time reporting for spinlocks.
++ *  Added support for hold time statistics for read and write
++ *  locks.
++ *  Moved machine dependent code here from include/lockmeter.h.
++ *
++ */
++
++#ifndef _I386_LOCKMETER_H
++#define _I386_LOCKMETER_H
++
++#include <asm/spinlock.h>
++#include <asm/rwlock.h>
++
++#include <linux/version.h>
++
++#ifdef __KERNEL__
++extern unsigned long cpu_khz;
++#define CPU_CYCLE_FREQUENCY   (cpu_khz * 1000)
++#else
++#define CPU_CYCLE_FREQUENCY   450000000
++#endif
++
++#define THIS_CPU_NUMBER               smp_processor_id()
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
++#define local_irq_save(x) \
++    __asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory")
++
++#define local_irq_restore(x) \
++    __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory")
++#endif        /* Linux version 2.2.x */
++
++/*
++ * macros to cache and retrieve an index value inside of a spin lock
++ * these macros assume that there are less than 65536 simultaneous
++ * (read mode) holders of a rwlock.  Not normally a problem!!
++ * we also assume that the hash table has less than 65535 entries.
++ */
++/*
++ * instrumented spinlock structure -- never used to allocate storage
++ * only used in macros below to overlay a spinlock_t
++ */
++typedef struct inst_spinlock_s {
++      /* remember, Intel is little endian */
++      unsigned short lock;
++      unsigned short index;
++} inst_spinlock_t;
++#define PUT_INDEX(lock_ptr,indexv) ((inst_spinlock_t *)(lock_ptr))->index = indexv
++#define GET_INDEX(lock_ptr)        ((inst_spinlock_t *)(lock_ptr))->index
++
++/*
++ * macros to cache and retrieve an index value in a read/write lock
++ * as well as the cpu where a reader busy period started
++ * we use the 2nd word (the debug word) for this, so require the
++ * debug word to be present
++ */
++/*
++ * instrumented rwlock structure -- never used to allocate storage
++ * only used in macros below to overlay a rwlock_t
++ */
++typedef struct inst_rwlock_s {
++      volatile int lock;
++      unsigned short index;
++      unsigned short cpu;
++} inst_rwlock_t;
++#define PUT_RWINDEX(rwlock_ptr,indexv) ((inst_rwlock_t *)(rwlock_ptr))->index = indexv
++#define GET_RWINDEX(rwlock_ptr)        ((inst_rwlock_t *)(rwlock_ptr))->index
++#define PUT_RW_CPU(rwlock_ptr,cpuv)    ((inst_rwlock_t *)(rwlock_ptr))->cpu = cpuv
++#define GET_RW_CPU(rwlock_ptr)         ((inst_rwlock_t *)(rwlock_ptr))->cpu
++
++/*
++ * return the number of readers for a rwlock_t
++ */
++#define RWLOCK_READERS(rwlock_ptr)   rwlock_readers(rwlock_ptr)
++
++extern inline int rwlock_readers(rwlock_t *rwlock_ptr)
++{
++      int tmp = (int) rwlock_ptr->lock;
++      /* read and write lock attempts may cause the lock value to temporarily */
++      /* be negative.  Until it is >= 0 we know nothing (i. e. can't tell if  */
++      /* is -1 because it was write locked and somebody tried to read lock it */
++      /* or if it is -1 because it was read locked and somebody tried to write*/
++      /* lock it. ........................................................... */
++      do {
++              tmp = (int) rwlock_ptr->lock;
++      } while (tmp < 0);
++      if (tmp == 0) return(0);
++      else return(RW_LOCK_BIAS-tmp);
++}
++
++/*
++ * return true if rwlock is write locked
++ * (note that other lock attempts can cause the lock value to be negative)
++ */
++#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) ((rwlock_ptr)->lock <= 0)
++#define IABS(x) ((x) > 0 ? (x) : -(x))
++#define RWLOCK_IS_READ_LOCKED(rwlock_ptr)  ((IABS((rwlock_ptr)->lock) % RW_LOCK_BIAS) != 0)
++
++/* this is a lot of typing just to get gcc to emit "rdtsc" */
++static inline long long get_cycles64 (void)
++{
++#ifndef CONFIG_X86_TSC
++      #error this code requires CONFIG_X86_TSC
++#else
++      union longlong_u {
++              long long intlong;
++              struct intint_s {
++                      uint32_t eax;
++                      uint32_t edx;
++              } intint;
++      } longlong;
++
++      rdtsc(longlong.intint.eax,longlong.intint.edx);
++      return longlong.intlong;
++#endif
++}
++
++#endif /* _I386_LOCKMETER_H */
+--- linux-2.6.0-test6/include/asm-i386/mach-default/irq_vectors.h      2003-06-14 12:18:04.000000000 -0700
++++ 25/include/asm-i386/mach-default/irq_vectors.h     2003-10-05 00:36:20.000000000 -0700
+@@ -76,11 +76,21 @@
+  * Since vectors 0x00-0x1f are used/reserved for the CPU,
+  * the usable vector space is 0x20-0xff (224 vectors)
+  */
++/*
++ * The maximum number of vectors supported by i386 processors
++ * is limited to 256. For processors other than i386, NR_VECTORS
++ * should be changed accordingly.
++ */
++#define NR_VECTORS 256
++#ifdef CONFIG_PCI_USE_VECTOR
++#define NR_IRQS FIRST_SYSTEM_VECTOR
++#else
+ #ifdef CONFIG_X86_IO_APIC
+ #define NR_IRQS 224
+ #else
+ #define NR_IRQS 16
+ #endif
++#endif
+ #define FPU_IRQ                       13
+--- linux-2.6.0-test6/include/asm-i386/mman.h  2003-09-27 18:57:47.000000000 -0700
++++ 25/include/asm-i386/mman.h 2003-10-05 00:33:24.000000000 -0700
+@@ -8,8 +8,6 @@
+ #define PROT_NONE     0x0             /* page can not be accessed */
+ #define PROT_GROWSDOWN        0x01000000      /* mprotect flag: extend change to start of growsdown vma */
+ #define PROT_GROWSUP  0x02000000      /* mprotect flag: extend change to end of growsup vma */
+-#define PROT_GROWSDOWN        0x01000000      /* mprotect flag: extend change to start of growsdown vma */
+-#define PROT_GROWSUP  0x02000000      /* mprotect flag: extend change to end of growsup vma */
+ #define MAP_SHARED    0x01            /* Share changes */
+ #define MAP_PRIVATE   0x02            /* Changes are private */
+--- linux-2.6.0-test6/include/asm-i386/mmu_context.h   2003-08-22 19:23:42.000000000 -0700
++++ 25/include/asm-i386/mmu_context.h  2003-10-05 00:36:48.000000000 -0700
+@@ -29,6 +29,10 @@ static inline void switch_mm(struct mm_s
+ {
+       int cpu = smp_processor_id();
++#ifdef CONFIG_X86_SWITCH_PAGETABLES
++      if (tsk->mm)
++              tsk->thread_info->user_pgd = (void *)__pa(tsk->mm->pgd);
++#endif
+       if (likely(prev != next)) {
+               /* stop flush ipis for the previous mm */
+               cpu_clear(cpu, prev->cpu_vm_mask);
+@@ -39,12 +43,14 @@ static inline void switch_mm(struct mm_s
+               cpu_set(cpu, next->cpu_vm_mask);
+               /* Re-load page tables */
++#if !defined(CONFIG_X86_SWITCH_PAGETABLES)
+               load_cr3(next->pgd);
++#endif
+               /*
+                * load the LDT, if the LDT is different:
+                */
+-              if (unlikely(prev->context.ldt != next->context.ldt))
++              if (unlikely(prev->context.size + next->context.size))
+                       load_LDT_nolock(&next->context, cpu);
+       }
+ #ifdef CONFIG_SMP
+@@ -56,7 +62,9 @@ static inline void switch_mm(struct mm_s
+                       /* We were in lazy tlb mode and leave_mm disabled 
+                        * tlb flush IPI delivery. We must reload %cr3.
+                        */
++#if !defined(CONFIG_X86_SWITCH_PAGETABLES)
+                       load_cr3(next->pgd);
++#endif
+                       load_LDT_nolock(&next->context, cpu);
+               }
+       }
+@@ -67,6 +75,6 @@ static inline void switch_mm(struct mm_s
+       asm("movl %0,%%fs ; movl %0,%%gs": :"r" (0))
+ #define activate_mm(prev, next) \
+-      switch_mm((prev),(next),NULL)
++      switch_mm((prev),(next),current)
+ #endif
+--- linux-2.6.0-test6/include/asm-i386/mmu.h   2003-06-14 12:18:24.000000000 -0700
++++ 25/include/asm-i386/mmu.h  2003-10-05 00:36:48.000000000 -0700
+@@ -8,10 +8,13 @@
+  *
+  * cpu_vm_mask is used to optimize ldt flushing.
+  */
++
++#define MAX_LDT_PAGES 16
++
+ typedef struct { 
+       int size;
+       struct semaphore sem;
+-      void *ldt;
++      struct page *ldt_pages[MAX_LDT_PAGES];
+ } mm_context_t;
+ #endif
+--- linux-2.6.0-test6/include/asm-i386/numaq.h 2003-09-27 18:57:47.000000000 -0700
++++ 25/include/asm-i386/numaq.h        2003-10-05 00:34:38.000000000 -0700
+@@ -28,7 +28,6 @@
+ #ifdef CONFIG_X86_NUMAQ
+-#define MAX_NUMNODES          16
+ extern int get_memcfg_numaq(void);
+ /*
+--- linux-2.6.0-test6/include/asm-i386/numnodes.h      2003-09-27 18:57:47.000000000 -0700
++++ 25/include/asm-i386/numnodes.h     2003-10-05 00:34:38.000000000 -0700
+@@ -4,11 +4,15 @@
+ #include <linux/config.h>
+ #ifdef CONFIG_X86_NUMAQ
+-#include <asm/numaq.h>
+-#elif CONFIG_ACPI_SRAT
+-#include <asm/srat.h>
+-#else
+-#define MAX_NUMNODES  1
++
++/* Max 16 Nodes */
++#define NODES_SHIFT   4
++
++#elif defined(CONFIG_ACPI_SRAT)
++
++/* Max 8 Nodes */
++#define NODES_SHIFT   3
++
+ #endif /* CONFIG_X86_NUMAQ */
+ #endif /* _ASM_MAX_NUMNODES_H */
+--- linux-2.6.0-test6/include/asm-i386/page.h  2003-06-26 22:07:25.000000000 -0700
++++ 25/include/asm-i386/page.h 2003-10-05 00:36:48.000000000 -0700
+@@ -1,6 +1,8 @@
+ #ifndef _I386_PAGE_H
+ #define _I386_PAGE_H
++#include <linux/config.h>
++
+ /* PAGE_SHIFT determines the page size */
+ #define PAGE_SHIFT    12
+ #define PAGE_SIZE     (1UL << PAGE_SHIFT)
+@@ -9,11 +11,10 @@
+ #define LARGE_PAGE_MASK (~(LARGE_PAGE_SIZE-1))
+ #define LARGE_PAGE_SIZE (1UL << PMD_SHIFT)
+-#ifdef __KERNEL__
+-#ifndef __ASSEMBLY__
+-
+ #include <linux/config.h>
++#ifdef __KERNEL__
++#ifndef __ASSEMBLY__
+ #ifdef CONFIG_X86_USE_3DNOW
+ #include <asm/mmx.h>
+@@ -88,8 +89,19 @@ typedef struct { unsigned long pgprot; }
+  *
+  * If you want more physical memory than this then see the CONFIG_HIGHMEM4G
+  * and CONFIG_HIGHMEM64G options in the kernel configuration.
++ *
++ * Note: on PAE the kernel must never go below 32 MB, we use the
++ * first 8 entries of the 2-level boot pgd for PAE magic.
+  */
++#ifdef CONFIG_X86_4G_VM_LAYOUT
++#define __PAGE_OFFSET         (0x02000000)
++#define TASK_SIZE             (0xff000000)
++#else
++#define __PAGE_OFFSET         (0xc0000000)
++#define TASK_SIZE             (0xc0000000)
++#endif
++
+ /*
+  * This much address space is reserved for vmalloc() and iomap()
+  * as well as fixmap mappings.
+@@ -114,16 +126,10 @@ static __inline__ int get_order(unsigned
+ #endif /* __ASSEMBLY__ */
+-#ifdef __ASSEMBLY__
+-#define __PAGE_OFFSET         (0xC0000000)
+-#else
+-#define __PAGE_OFFSET         (0xC0000000UL)
+-#endif
+-
+-
+ #define PAGE_OFFSET           ((unsigned long)__PAGE_OFFSET)
+ #define VMALLOC_RESERVE               ((unsigned long)__VMALLOC_RESERVE)
+-#define MAXMEM                        (-__PAGE_OFFSET-__VMALLOC_RESERVE)
++#define __MAXMEM              (-__PAGE_OFFSET-__VMALLOC_RESERVE)
++#define MAXMEM                        ((unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE))
+ #define __pa(x)                       ((unsigned long)(x)-PAGE_OFFSET)
+ #define __va(x)                       ((void *)((unsigned long)(x)+PAGE_OFFSET))
+ #define pfn_to_kaddr(pfn)      __va((pfn) << PAGE_SHIFT)
+--- linux-2.6.0-test6/include/asm-i386/pgtable.h       2003-08-08 22:55:13.000000000 -0700
++++ 25/include/asm-i386/pgtable.h      2003-10-05 00:36:48.000000000 -0700
+@@ -32,16 +32,17 @@
+ #define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
+ extern unsigned long empty_zero_page[1024];
+ extern pgd_t swapper_pg_dir[1024];
+-extern kmem_cache_t *pgd_cache;
+-extern kmem_cache_t *pmd_cache;
++extern kmem_cache_t *pgd_cache, *pmd_cache, *kpmd_cache;
+ extern spinlock_t pgd_lock;
+ extern struct list_head pgd_list;
+ void pmd_ctor(void *, kmem_cache_t *, unsigned long);
++void kpmd_ctor(void *, kmem_cache_t *, unsigned long);
+ void pgd_ctor(void *, kmem_cache_t *, unsigned long);
+ void pgd_dtor(void *, kmem_cache_t *, unsigned long);
+ void pgtable_cache_init(void);
+ void paging_init(void);
++void setup_identity_mappings(pgd_t *pgd_base, unsigned long start, unsigned long end);
+ #endif /* !__ASSEMBLY__ */
+@@ -51,6 +52,11 @@ void paging_init(void);
+  * newer 3-level PAE-mode page tables.
+  */
+ #ifndef __ASSEMBLY__
++
++extern void set_system_gate(unsigned int n, void *addr);
++extern void init_entry_mappings(void);
++extern void entry_trampoline_setup(void);
++
+ #ifdef CONFIG_X86_PAE
+ # include <asm/pgtable-3level.h>
+ #else
+@@ -63,7 +69,12 @@ void paging_init(void);
+ #define PGDIR_SIZE    (1UL << PGDIR_SHIFT)
+ #define PGDIR_MASK    (~(PGDIR_SIZE-1))
+-#define USER_PTRS_PER_PGD     (TASK_SIZE/PGDIR_SIZE)
++#if defined(CONFIG_X86_PAE) && defined(CONFIG_X86_4G_VM_LAYOUT)
++# define USER_PTRS_PER_PGD    4
++#else
++# define USER_PTRS_PER_PGD    ((TASK_SIZE/PGDIR_SIZE) + ((TASK_SIZE % PGDIR_SIZE) + PGDIR_SIZE-1)/PGDIR_SIZE)
++#endif
++
+ #define FIRST_USER_PGD_NR     0
+ #define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT)
+@@ -85,7 +96,6 @@ void paging_init(void);
+ #define VMALLOC_OFFSET        (8*1024*1024)
+ #define VMALLOC_START (((unsigned long) high_memory + 2*VMALLOC_OFFSET-1) & \
+                                               ~(VMALLOC_OFFSET-1))
+-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+ #ifdef CONFIG_HIGHMEM
+ # define VMALLOC_END  (PKMAP_BASE-2*PAGE_SIZE)
+ #else
+@@ -234,6 +244,7 @@ static inline void ptep_mkdirty(pte_t *p
+ #define mk_pte(page, pgprot)  pfn_pte(page_to_pfn(page), (pgprot))
+ #define mk_pte_huge(entry) ((entry).pte_low |= _PAGE_PRESENT | _PAGE_PSE)
++#define mk_pte_phys(physpage, pgprot) pfn_pte((physpage) >> PAGE_SHIFT, pgprot)
+ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+ {
+--- linux-2.6.0-test6/include/asm-i386/processor.h     2003-09-27 18:57:47.000000000 -0700
++++ 25/include/asm-i386/processor.h    2003-10-05 00:36:49.000000000 -0700
+@@ -291,11 +291,6 @@ extern unsigned int machine_submodel_id;
+ extern unsigned int BIOS_revision;
+ extern unsigned int mca_pentium_flag;
+-/*
+- * User space process size: 3GB (default).
+- */
+-#define TASK_SIZE     (PAGE_OFFSET)
+-
+ /* This decides where the kernel will search for a free chunk of vm
+  * space during mmap's.
+  */
+@@ -406,6 +401,7 @@ struct tss_struct {
+ struct thread_struct {
+ /* cached TLS descriptors. */
+       struct desc_struct tls_array[GDT_ENTRY_TLS_ENTRIES];
++      void *stack_page0, *stack_page1;
+       unsigned long   esp0;
+       unsigned long   eip;
+       unsigned long   esp;
+@@ -491,6 +487,13 @@ extern void prepare_to_copy(struct task_
+  */
+ extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
++#ifdef CONFIG_X86_HIGH_ENTRY
++#define virtual_esp0(tsk) \
++      ((unsigned long)(tsk)->thread_info->virtual_stack + ((tsk)->thread.esp0 - (unsigned long)(tsk)->thread_info->real_stack))
++#else
++# define virtual_esp0(tsk) ((tsk)->thread.esp0)
++#endif
++
+ extern unsigned long thread_saved_pc(struct task_struct *tsk);
+ void show_trace(struct task_struct *task, unsigned long *stack);
+@@ -585,12 +588,12 @@ static inline void rep_nop(void)
+ /* Prefetch instructions for Pentium III and AMD Athlon */
+ /* It's not worth to care about 3dnow! prefetches for the K6
+-   because they are microcoded there and very slow. */
++   because they are microcoded there and very slow.
++   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)
+ {
+-      if (cpu_data[0].x86_vendor == X86_VENDOR_AMD)
+-              return;         /* Some athlons fault if the address is bad */
+       alternative_input(ASM_NOP4,
+                         "prefetchnta (%1)",
+                         X86_FEATURE_XMM,
+--- linux-2.6.0-test6/include/asm-i386/rwlock.h        2003-06-26 22:07:25.000000000 -0700
++++ 25/include/asm-i386/rwlock.h       2003-10-05 00:34:17.000000000 -0700
+@@ -20,28 +20,52 @@
+ #define RW_LOCK_BIAS           0x01000000
+ #define RW_LOCK_BIAS_STR      "0x01000000"
+-#define __build_read_lock_ptr(rw, helper)   \
+-      asm volatile(LOCK "subl $1,(%0)\n\t" \
+-                   "js 2f\n" \
+-                   "1:\n" \
+-                   LOCK_SECTION_START("") \
+-                   "2:\tcall " helper "\n\t" \
+-                   "jmp 1b\n" \
+-                   LOCK_SECTION_END \
+-                   ::"a" (rw) : "memory")
+-
+-#define __build_read_lock_const(rw, helper)   \
+-      asm volatile(LOCK "subl $1,%0\n\t" \
+-                   "js 2f\n" \
+-                   "1:\n" \
+-                   LOCK_SECTION_START("") \
+-                   "2:\tpushl %%eax\n\t" \
+-                   "leal %0,%%eax\n\t" \
+-                   "call " helper "\n\t" \
+-                   "popl %%eax\n\t" \
+-                   "jmp 1b\n" \
+-                   LOCK_SECTION_END \
+-                   :"=m" (*(volatile int *)rw) : : "memory")
++#ifdef CONFIG_SPINLINE
++
++      #define __build_read_lock_ptr(rw, helper)   \
++              asm volatile(LOCK "subl $1,(%0)\n\t" \
++                           "jns 1f\n\t" \
++                           "call " helper "\n\t" \
++                           "1:\t" \
++                           ::"a" (rw) : "memory")
++
++      #define __build_read_lock_const(rw, helper)   \
++              asm volatile(LOCK "subl $1,%0\n\t" \
++                           "jns 1f\n\t" \
++                           "pushl %%eax\n\t" \
++                           "leal %0,%%eax\n\t" \
++                           "call " helper "\n\t" \
++                           "popl %%eax\n\t" \
++                           "1:\t" \
++                           :"=m" (*(volatile int *)rw) : : "memory")
++
++#else /* !CONFIG_SPINLINE */
++
++      #define __build_read_lock_ptr(rw, helper)   \
++              asm volatile(LOCK "subl $1,(%0)\n\t" \
++                           "js 2f\n" \
++                           "1:\n" \
++                           LOCK_SECTION_START("") \
++                           "2:\tcall " helper "\n\t" \
++                           "jmp 1b\n" \
++                           LOCK_SECTION_END \
++                           ::"a" (rw) : "memory")
++
++      #define __build_read_lock_const(rw, helper)   \
++              asm volatile(LOCK "subl $1,%0\n\t" \
++                           "js 2f\n" \
++                           "1:\n" \
++                           LOCK_SECTION_START("") \
++                           "2:\tpushl %%eax\n\t" \
++                           "leal %0,%%eax\n\t" \
++                           "call " helper "\n\t" \
++                           "popl %%eax\n\t" \
++                           "jmp 1b\n" \
++                           LOCK_SECTION_END \
++                           :"=m" (*(volatile int *)rw) : : "memory")
++
++#endif /* CONFIG_SPINLINE */
++
+ #define __build_read_lock(rw, helper) do { \
+                                               if (__builtin_constant_p(rw)) \
+@@ -50,28 +74,51 @@
+                                                       __build_read_lock_ptr(rw, helper); \
+                                       } while (0)
+-#define __build_write_lock_ptr(rw, helper) \
+-      asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \
+-                   "jnz 2f\n" \
+-                   "1:\n" \
+-                   LOCK_SECTION_START("") \
+-                   "2:\tcall " helper "\n\t" \
+-                   "jmp 1b\n" \
+-                   LOCK_SECTION_END \
+-                   ::"a" (rw) : "memory")
+-
+-#define __build_write_lock_const(rw, helper) \
+-      asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",%0\n\t" \
+-                   "jnz 2f\n" \
+-                   "1:\n" \
+-                   LOCK_SECTION_START("") \
+-                   "2:\tpushl %%eax\n\t" \
+-                   "leal %0,%%eax\n\t" \
+-                   "call " helper "\n\t" \
+-                   "popl %%eax\n\t" \
+-                   "jmp 1b\n" \
+-                   LOCK_SECTION_END \
+-                   :"=m" (*(volatile int *)rw) : : "memory")
++#ifdef CONFIG_SPINLINE
++
++      #define __build_write_lock_ptr(rw, helper) \
++              asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \
++                           "jz 1f\n\t" \
++                           "call " helper "\n\t" \
++                           "1:\n" \
++                           ::"a" (rw) : "memory")
++
++      #define __build_write_lock_const(rw, helper) \
++              asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",%0\n\t" \
++                           "jz 1f\n\t" \
++                           "pushl %%eax\n\t" \
++                           "leal %0,%%eax\n\t" \
++                           "call " helper "\n\t" \
++                           "popl %%eax\n\t" \
++                           "1:\n" \
++                           :"=m" (*(volatile int *)rw) : : "memory")
++
++#else /* !CONFIG_SPINLINE */
++
++      #define __build_write_lock_ptr(rw, helper) \
++              asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \
++                           "jnz 2f\n" \
++                           "1:\n" \
++                           LOCK_SECTION_START("") \
++                           "2:\tcall " helper "\n\t" \
++                           "jmp 1b\n" \
++                           LOCK_SECTION_END \
++                           ::"a" (rw) : "memory")
++
++      #define __build_write_lock_const(rw, helper) \
++              asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",%0\n\t" \
++                           "jnz 2f\n" \
++                           "1:\n" \
++                           LOCK_SECTION_START("") \
++                           "2:\tpushl %%eax\n\t" \
++                           "leal %0,%%eax\n\t" \
++                           "call " helper "\n\t" \
++                           "popl %%eax\n\t" \
++                           "jmp 1b\n" \
++                           LOCK_SECTION_END \
++                           :"=m" (*(volatile int *)rw) : : "memory")
++
++#endif /* CONFIG_SPINLINE */
+ #define __build_write_lock(rw, helper)        do { \
+                                               if (__builtin_constant_p(rw)) \
+--- linux-2.6.0-test6/include/asm-i386/setup.h 2003-09-27 18:57:47.000000000 -0700
++++ 25/include/asm-i386/setup.h        2003-10-05 00:36:22.000000000 -0700
+@@ -29,6 +29,11 @@
+ #define IST_INFO   (*(struct ist_info *) (PARAM+0x60))
+ #define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80))
+ #define SYS_DESC_TABLE (*(struct sys_desc_table_struct*)(PARAM+0xa0))
++#define EFI_SYSTAB ((efi_system_table_t *) *((unsigned long *)(PARAM+0x1c4)))
++#define EFI_MEMDESC_SIZE (*((unsigned long *) (PARAM+0x1c8)))
++#define EFI_MEMDESC_VERSION (*((unsigned long *) (PARAM+0x1cc)))
++#define EFI_MEMMAP ((efi_memory_desc_t *) *((unsigned long *)(PARAM+0x1d0)))
++#define EFI_MEMMAP_SIZE (*((unsigned long *) (PARAM+0x1d4)))
+ #define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2))
+ #define RAMDISK_FLAGS (*(unsigned short *) (PARAM+0x1F8))
+ #define VIDEO_MODE (*(unsigned short *) (PARAM+0x1FA))
+--- linux-2.6.0-test6/include/asm-i386/spinlock.h      2003-06-26 22:07:25.000000000 -0700
++++ 25/include/asm-i386/spinlock.h     2003-10-05 00:36:40.000000000 -0700
+@@ -43,18 +43,35 @@ typedef struct {
+ #define spin_is_locked(x)     (*(volatile signed char *)(&(x)->lock) <= 0)
+ #define spin_unlock_wait(x)   do { barrier(); } while(spin_is_locked(x))
+-#define spin_lock_string \
+-      "\n1:\t" \
+-      "lock ; decb %0\n\t" \
+-      "js 2f\n" \
+-      LOCK_SECTION_START("") \
+-      "2:\t" \
+-      "rep;nop\n\t" \
+-      "cmpb $0,%0\n\t" \
+-      "jle 2b\n\t" \
+-      "jmp 1b\n" \
+-      LOCK_SECTION_END
++#ifdef CONFIG_SPINLINE
++      #define spin_lock_string \
++              "\n1:\t" \
++              "lock ; decb %0\n\t" \
++              "js 2f\n" \
++              "jmp 3f\n" \
++              "2:\t" \
++              "rep;nop\n\t" \
++              "cmpb $0,%0\n\t" \
++              "jle 2b\n\t" \
++              "jmp 1b\n" \
++              "3:\t"
++
++#else /* !CONFIG_SPINLINE */
++
++      #define spin_lock_string \
++              "\n1:\t" \
++              "lock ; decb %0\n\t" \
++              "js 2f\n" \
++              LOCK_SECTION_START("") \
++              "2:\t" \
++              "rep;nop\n\t" \
++              "cmpb $0,%0\n\t" \
++              "jle 2b\n\t" \
++              "jmp 1b\n" \
++              LOCK_SECTION_END
++
++#endif /* CONFIG_SPINLINE */
+ /*
+  * This works. Despite all the confusion.
+  * (except on PPro SMP or if we are using OOSTORE)
+@@ -138,6 +155,11 @@ here:
+  */
+ typedef struct {
+       volatile unsigned int lock;
++#ifdef CONFIG_LOCKMETER
++      /* required for LOCKMETER since all bits in lock are used */
++      /* and we need this storage for CPU and lock INDEX        */
++      unsigned lockmeter_magic;
++#endif
+ #ifdef CONFIG_DEBUG_SPINLOCK
+       unsigned magic;
+ #endif
+@@ -145,11 +167,19 @@ typedef struct {
+ #define RWLOCK_MAGIC  0xdeaf1eed
++#ifdef CONFIG_LOCKMETER
++#ifdef CONFIG_DEBUG_SPINLOCK
++#define RWLOCK_MAGIC_INIT     , 0, RWLOCK_MAGIC
++#else
++#define RWLOCK_MAGIC_INIT     , 0
++#endif
++#else /* !CONFIG_LOCKMETER */
+ #ifdef CONFIG_DEBUG_SPINLOCK
+ #define RWLOCK_MAGIC_INIT     , RWLOCK_MAGIC
+ #else
+ #define RWLOCK_MAGIC_INIT     /* */
+ #endif
++#endif /* !CONFIG_LOCKMETER */
+ #define RW_LOCK_UNLOCKED (rwlock_t) { RW_LOCK_BIAS RWLOCK_MAGIC_INIT }
+@@ -196,4 +226,58 @@ static inline int _raw_write_trylock(rwl
+       return 0;
+ }
++#ifdef CONFIG_LOCKMETER
++static inline int _raw_read_trylock(rwlock_t *lock)
++{
++/* FIXME -- replace with assembler */
++      atomic_t *count = (atomic_t *)lock;
++      atomic_dec(count);
++      if (count->counter > 0)
++              return 1;
++      atomic_inc(count);
++      return 0;
++}
++#endif
++
++#if defined(CONFIG_LOCKMETER) && defined(CONFIG_HAVE_DEC_LOCK)
++extern void _metered_spin_lock  (spinlock_t *lock);
++extern void _metered_spin_unlock(spinlock_t *lock);
++
++/*
++ *  Matches what is in arch/i386/lib/dec_and_lock.c, except this one is
++ *  "static inline" so that the spin_lock(), if actually invoked, is charged
++ *  against the real caller, not against the catch-all atomic_dec_and_lock
++ */
++static inline int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
++{
++      int counter;
++      int newcount;
++
++repeat:
++      counter = atomic_read(atomic);
++      newcount = counter-1;
++
++      if (!newcount)
++              goto slow_path;
++
++      asm volatile("lock; cmpxchgl %1,%2"
++              :"=a" (newcount)
++              :"r" (newcount), "m" (atomic->counter), "0" (counter));
++
++      /* If the above failed, "eax" will have changed */
++      if (newcount != counter)
++              goto repeat;
++      return 0;
++
++slow_path:
++      _metered_spin_lock(lock);
++      if (atomic_dec_and_test(atomic))
++              return 1;
++      _metered_spin_unlock(lock);
++      return 0;
++}
++
++#define ATOMIC_DEC_AND_LOCK
++#endif
++
+ #endif /* __ASM_SPINLOCK_H */
+--- linux-2.6.0-test6/include/asm-i386/srat.h  2003-09-27 18:57:47.000000000 -0700
++++ 25/include/asm-i386/srat.h 2003-10-05 00:34:38.000000000 -0700
+@@ -31,7 +31,6 @@
+ #error CONFIG_ACPI_SRAT not defined, and srat.h header has been included
+ #endif
+-#define MAX_NUMNODES          8
+ extern int get_memcfg_from_srat(void);
+ extern unsigned long *get_zholes_size(int);
+--- linux-2.6.0-test6/include/asm-i386/string.h        2003-06-14 12:18:51.000000000 -0700
++++ 25/include/asm-i386/string.h       2003-10-05 00:36:48.000000000 -0700
+@@ -56,6 +56,29 @@ __asm__ __volatile__(
+ return dest;
+ }
++/*
++ * This is a more generic variant of strncpy_count() suitable for
++ * implementing string-access routines with all sorts of return
++ * code semantics. It's used by mm/usercopy.c.
++ */
++static inline size_t strncpy_count(char * dest,const char *src,size_t count)
++{
++      __asm__ __volatile__(
++
++      "1:\tdecl %0\n\t"
++      "js 2f\n\t"
++      "lodsb\n\t"
++      "stosb\n\t"
++      "testb %%al,%%al\n\t"
++      "jne 1b\n\t"
++      "2:"
++      "incl %0"
++      : "=c" (count)
++      :"S" (src),"D" (dest),"0" (count) : "memory");
++
++      return count;
++}
++
+ #define __HAVE_ARCH_STRCAT
+ static inline char * strcat(char * dest,const char * src)
+ {
+--- linux-2.6.0-test6/include/asm-i386/thread_info.h   2003-07-27 12:14:40.000000000 -0700
++++ 25/include/asm-i386/thread_info.h  2003-10-05 00:36:48.000000000 -0700
+@@ -33,23 +33,12 @@ struct thread_info {
+                                                  0-0xBFFFFFFF for user-thead
+                                                  0-0xFFFFFFFF for kernel-thread
+                                               */
+-      struct restart_block    restart_block;
++      void *real_stack, *virtual_stack, *user_pgd;
++      struct restart_block    restart_block;
+       __u8                    supervisor_stack[0];
+ };
+-#else /* !__ASSEMBLY__ */
+-
+-/* offsets into the thread_info struct for assembly code access */
+-#define TI_TASK               0x00000000
+-#define TI_EXEC_DOMAIN        0x00000004
+-#define TI_FLAGS      0x00000008
+-#define TI_STATUS     0x0000000C
+-#define TI_CPU                0x00000010
+-#define TI_PRE_COUNT  0x00000014
+-#define TI_ADDR_LIMIT 0x00000018
+-#define TI_RESTART_BLOCK 0x000001C
+-
+ #endif
+ #define PREEMPT_ACTIVE                0x4000000
+@@ -61,7 +50,7 @@ struct thread_info {
+  */
+ #ifndef __ASSEMBLY__
+-#define INIT_THREAD_INFO(tsk)                 \
++#define INIT_THREAD_INFO(tsk, thread_info)    \
+ {                                             \
+       .task           = &tsk,                 \
+       .exec_domain    = &default_exec_domain, \
+@@ -72,6 +61,7 @@ struct thread_info {
+       .restart_block = {                      \
+               .fn = do_no_restart_syscall,    \
+       },                                      \
++      .real_stack     = &thread_info,         \
+ }
+ #define init_thread_info      (init_thread_union.thread_info)
+@@ -113,6 +103,7 @@ static inline struct thread_info *curren
+ #define TIF_NEED_RESCHED      3       /* rescheduling necessary */
+ #define TIF_SINGLESTEP                4       /* restore singlestep on return to user mode */
+ #define TIF_IRET              5       /* return with iret */
++#define TIF_DB7                       6       /* has debug registers */
+ #define TIF_POLLING_NRFLAG    16      /* true if poll_idle() is polling TIF_NEED_RESCHED */
+ #define _TIF_SYSCALL_TRACE    (1<<TIF_SYSCALL_TRACE)
+@@ -121,6 +112,7 @@ static inline struct thread_info *curren
+ #define _TIF_NEED_RESCHED     (1<<TIF_NEED_RESCHED)
+ #define _TIF_SINGLESTEP               (1<<TIF_SINGLESTEP)
+ #define _TIF_IRET             (1<<TIF_IRET)
++#define _TIF_DB7              (1<<TIF_DB7)
+ #define _TIF_POLLING_NRFLAG   (1<<TIF_POLLING_NRFLAG)
+ #define _TIF_WORK_MASK                0x0000FFFE      /* work to do on interrupt/exception return */
+--- linux-2.6.0-test6/include/asm-i386/tlbflush.h      2003-06-14 12:18:35.000000000 -0700
++++ 25/include/asm-i386/tlbflush.h     2003-10-05 00:36:48.000000000 -0700
+@@ -85,22 +85,28 @@ extern unsigned long pgkern_mask;
+ static inline void flush_tlb_mm(struct mm_struct *mm)
+ {
++#ifndef CONFIG_X86_SWITCH_PAGETABLES
+       if (mm == current->active_mm)
+               __flush_tlb();
++#endif
+ }
+ static inline void flush_tlb_page(struct vm_area_struct *vma,
+       unsigned long addr)
+ {
++#ifndef CONFIG_X86_SWITCH_PAGETABLES
+       if (vma->vm_mm == current->active_mm)
+               __flush_tlb_one(addr);
++#endif
+ }
+ static inline void flush_tlb_range(struct vm_area_struct *vma,
+       unsigned long start, unsigned long end)
+ {
++#ifndef CONFIG_X86_SWITCH_PAGETABLES
+       if (vma->vm_mm == current->active_mm)
+               __flush_tlb();
++#endif
+ }
+ #else
+@@ -111,11 +117,10 @@ static inline void flush_tlb_range(struc
+       __flush_tlb()
+ extern void flush_tlb_all(void);
+-extern void flush_tlb_current_task(void);
+ extern void flush_tlb_mm(struct mm_struct *);
+ extern void flush_tlb_page(struct vm_area_struct *, unsigned long);
+-#define flush_tlb()   flush_tlb_current_task()
++#define flush_tlb()   flush_tlb_all()
+ static inline void flush_tlb_range(struct vm_area_struct * vma, unsigned long start, unsigned long end)
+ {
+--- linux-2.6.0-test6/include/asm-i386/uaccess.h       2003-09-27 18:57:47.000000000 -0700
++++ 25/include/asm-i386/uaccess.h      2003-10-05 00:36:48.000000000 -0700
+@@ -26,7 +26,7 @@
+ #define KERNEL_DS     MAKE_MM_SEG(0xFFFFFFFFUL)
+-#define USER_DS               MAKE_MM_SEG(PAGE_OFFSET)
++#define USER_DS               MAKE_MM_SEG(TASK_SIZE)
+ #define get_ds()      (KERNEL_DS)
+ #define get_fs()      (current_thread_info()->addr_limit)
+@@ -149,6 +149,45 @@ extern void __get_user_4(void);
+               :"=a" (ret),"=d" (x) \
+               :"0" (ptr))
++extern int get_user_size(unsigned int size, void *val, const void *ptr);
++extern int put_user_size(unsigned int size, const void *val, void *ptr);
++extern int zero_user_size(unsigned int size, void *ptr);
++extern int copy_str_fromuser_size(unsigned int size, void *val, const void *ptr);
++extern int strlen_fromuser_size(unsigned int size, const void *ptr);
++
++
++# define indirect_get_user(x,ptr)                                     \
++({    int __ret_gu,__val_gu;                                          \
++      __typeof__(ptr) __ptr_gu = (ptr);                               \
++      __ret_gu = get_user_size(sizeof(*__ptr_gu), &__val_gu,__ptr_gu) ? -EFAULT : 0;\
++      (x) = (__typeof__(*__ptr_gu))__val_gu;                          \
++      __ret_gu;                                                       \
++})
++#define indirect_put_user(x,ptr)                                      \
++({                                                                    \
++      __typeof__(*(ptr)) *__ptr_pu = (ptr), __x_pu = (x);             \
++      put_user_size(sizeof(*__ptr_pu), &__x_pu, __ptr_pu) ? -EFAULT : 0; \
++})
++#define __indirect_put_user indirect_put_user
++#define __indirect_get_user indirect_get_user
++
++#define indirect_copy_from_user(to,from,n) get_user_size(n,to,from)
++#define indirect_copy_to_user(to,from,n) put_user_size(n,from,to)
++
++#define __indirect_copy_from_user indirect_copy_from_user
++#define __indirect_copy_to_user indirect_copy_to_user
++
++#define indirect_strncpy_from_user(dst, src, count) \
++              copy_str_fromuser_size(count, dst, src)
++
++extern int strlen_fromuser_size(unsigned int size, const void *ptr);
++#define indirect_strnlen_user(str, n) strlen_fromuser_size(n, str)
++#define indirect_strlen_user(str) indirect_strnlen_user(str, ~0UL >> 1)
++
++extern int zero_user_size(unsigned int size, void *ptr);
++
++#define indirect_clear_user(mem, len) zero_user_size(len, mem)
++#define __indirect_clear_user clear_user
+ /* Careful: we have to cast the result to the type of the pointer for sign reasons */
+ /**
+@@ -168,7 +207,7 @@ extern void __get_user_4(void);
+  * Returns zero on success, or -EFAULT on error.
+  * On error, the variable @x is set to zero.
+  */
+-#define get_user(x,ptr)                                                       \
++#define direct_get_user(x,ptr)                                                \
+ ({    int __ret_gu,__val_gu;                                          \
+       switch(sizeof (*(ptr))) {                                       \
+       case 1:  __get_user_x(1,__ret_gu,__val_gu,ptr); break;          \
+@@ -198,7 +237,7 @@ extern void __put_user_bad(void);
+  *
+  * Returns zero on success, or -EFAULT on error.
+  */
+-#define put_user(x,ptr)                                                       \
++#define direct_put_user(x,ptr)                                                \
+   __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
+@@ -222,7 +261,7 @@ extern void __put_user_bad(void);
+  * Returns zero on success, or -EFAULT on error.
+  * On error, the variable @x is set to zero.
+  */
+-#define __get_user(x,ptr) \
++#define __direct_get_user(x,ptr) \
+   __get_user_nocheck((x),(ptr),sizeof(*(ptr)))
+@@ -245,7 +284,7 @@ extern void __put_user_bad(void);
+  *
+  * Returns zero on success, or -EFAULT on error.
+  */
+-#define __put_user(x,ptr) \
++#define __direct_put_user(x,ptr) \
+   __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
+ #define __put_user_nocheck(x,ptr,size)                                \
+@@ -396,7 +435,7 @@ unsigned long __copy_from_user_ll(void *
+  * On success, this will be zero.
+  */
+ static inline unsigned long
+-__copy_to_user(void __user *to, const void *from, unsigned long n)
++__direct_copy_to_user(void __user *to, const void *from, unsigned long n)
+ {
+       if (__builtin_constant_p(n)) {
+               unsigned long ret;
+@@ -434,7 +473,7 @@ __copy_to_user(void __user *to, const vo
+  * data to the requested size using zero bytes.
+  */
+ static inline unsigned long
+-__copy_from_user(void *to, const void __user *from, unsigned long n)
++__direct_copy_from_user(void *to, const void __user *from, unsigned long n)
+ {
+       if (__builtin_constant_p(n)) {
+               unsigned long ret;
+@@ -468,11 +507,11 @@ __copy_from_user(void *to, const void __
+  * On success, this will be zero.
+  */
+ static inline unsigned long
+-copy_to_user(void __user *to, const void *from, unsigned long n)
++direct_copy_to_user(void __user *to, const void *from, unsigned long n)
+ {
+       might_sleep();
+       if (access_ok(VERIFY_WRITE, to, n))
+-              n = __copy_to_user(to, from, n);
++              n = __direct_copy_to_user(to, from, n);
+       return n;
+ }
+@@ -493,11 +532,11 @@ copy_to_user(void __user *to, const void
+  * data to the requested size using zero bytes.
+  */
+ static inline unsigned long
+-copy_from_user(void *to, const void __user *from, unsigned long n)
++direct_copy_from_user(void *to, const void __user *from, unsigned long n)
+ {
+       might_sleep();
+       if (access_ok(VERIFY_READ, from, n))
+-              n = __copy_from_user(to, from, n);
++              n = __direct_copy_from_user(to, from, n);
+       else
+               memset(to, 0, n);
+       return n;
+@@ -520,10 +559,68 @@ long __strncpy_from_user(char *dst, cons
+  * If there is a limit on the length of a valid string, you may wish to
+  * consider using strnlen_user() instead.
+  */
+-#define strlen_user(str) strnlen_user(str, ~0UL >> 1)
+-long strnlen_user(const char __user *str, long n);
+-unsigned long clear_user(void __user *mem, unsigned long len);
+-unsigned long __clear_user(void __user *mem, unsigned long len);
++long direct_strncpy_from_user(char *dst, const char *src, long count);
++long __direct_strncpy_from_user(char *dst, const char *src, long count);
++#define direct_strlen_user(str) direct_strnlen_user(str, ~0UL >> 1)
++long direct_strnlen_user(const char *str, long n);
++unsigned long direct_clear_user(void *mem, unsigned long len);
++unsigned long __direct_clear_user(void *mem, unsigned long len);
++
++extern int indirect_uaccess;
++
++#ifdef CONFIG_X86_UACCESS_INDIRECT
++
++/*
++ * Return code and zeroing semantics:
++
++ __clear_user          0                      <-> bytes not done
++ clear_user            0                      <-> bytes not done
++ __copy_to_user        0                      <-> bytes not done
++ copy_to_user          0                      <-> bytes not done
++ __copy_from_user      0                      <-> bytes not done, zero rest
++ copy_from_user        0                      <-> bytes not done, zero rest
++ __get_user            0                      <-> -EFAULT
++ get_user              0                      <-> -EFAULT
++ __put_user            0                      <-> -EFAULT
++ put_user              0                      <-> -EFAULT
++ strlen_user           strlen + 1             <-> 0
++ strnlen_user          strlen + 1 (or n+1)    <-> 0
++ strncpy_from_user     strlen (or n)          <-> -EFAULT
++
++ */
++
++#define __clear_user(mem,len) __indirect_clear_user(mem,len)
++#define clear_user(mem,len) indirect_clear_user(mem,len)
++#define __copy_to_user(to,from,n) __indirect_copy_to_user(to,from,n)
++#define copy_to_user(to,from,n) indirect_copy_to_user(to,from,n)
++#define __copy_from_user(to,from,n) __indirect_copy_from_user(to,from,n)
++#define copy_from_user(to,from,n) indirect_copy_from_user(to,from,n)
++#define __get_user(val,ptr) __indirect_get_user(val,ptr)
++#define get_user(val,ptr) indirect_get_user(val,ptr)
++#define __put_user(val,ptr) __indirect_put_user(val,ptr)
++#define put_user(val,ptr) indirect_put_user(val,ptr)
++#define strlen_user(str) indirect_strlen_user(str)
++#define strnlen_user(src,count) indirect_strnlen_user(src,count)
++#define strncpy_from_user(dst,src,count) \
++                      indirect_strncpy_from_user(dst,src,count)
++
++#else
++
++#define __clear_user __direct_clear_user
++#define clear_user direct_clear_user
++#define __copy_to_user __direct_copy_to_user
++#define copy_to_user direct_copy_to_user
++#define __copy_from_user __direct_copy_from_user
++#define copy_from_user direct_copy_from_user
++#define __get_user __direct_get_user
++#define get_user direct_get_user
++#define __put_user __direct_put_user
++#define put_user direct_put_user
++#define strlen_user direct_strlen_user
++#define strnlen_user direct_strnlen_user
++#define strncpy_from_user direct_strncpy_from_user
++
++#endif /* CONFIG_X86_UACCESS_INDIRECT */
+ #endif /* __i386_UACCESS_H */
+--- linux-2.6.0-test6/include/asm-i386/unistd.h        2003-08-22 19:23:42.000000000 -0700
++++ 25/include/asm-i386/unistd.h       2003-10-05 00:33:24.000000000 -0700
+@@ -278,8 +278,9 @@
+ #define __NR_tgkill           270
+ #define __NR_utimes           271
+ #define __NR_fadvise64_64     272
++#define __NR_vserver          273
+-#define NR_syscalls 273
++#define NR_syscalls 274
+ /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
+--- linux-2.6.0-test6/include/asm-ia64/acpi.h  2003-09-27 18:57:47.000000000 -0700
++++ 25/include/asm-ia64/acpi.h 2003-10-05 00:34:41.000000000 -0700
+@@ -99,7 +99,7 @@ int acpi_get_addr_space (void *obj, u8 t
+ /* Proximity bitmap length; _PXM is at most 255 (8 bit)*/
+ #define MAX_PXM_DOMAINS (256)
+ extern int __initdata pxm_to_nid_map[MAX_PXM_DOMAINS];
+-extern int __initdata nid_to_pxm_map[NR_NODES];
++extern int __initdata nid_to_pxm_map[MAX_NUMNODES];
+ #endif
+ #endif /*__KERNEL__*/
+--- linux-2.6.0-test6/include/asm-ia64/cacheflush.h    2003-06-14 12:18:00.000000000 -0700
++++ 25/include/asm-ia64/cacheflush.h   2003-10-05 00:33:24.000000000 -0700
+@@ -21,6 +21,8 @@
+ #define flush_cache_range(vma, start, end)    do { } while (0)
+ #define flush_cache_page(vma, vmaddr)         do { } while (0)
+ #define flush_icache_page(vma,page)           do { } while (0)
++#define flush_cache_vmap(start, end)          do { } while (0)
++#define flush_cache_vunmap(start, end)                do { } while (0)
+ #define flush_dcache_page(page)                       \
+ do {                                          \
+@@ -35,4 +37,11 @@ do {                                                                                                \
+       flush_icache_range(_addr, _addr + (len));                                               \
+ } while (0)
++#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
++do { memcpy(dst, src, len); \
++     flush_icache_user_range(vma, page, vaddr, len); \
++} while (0)
++#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
++      memcpy(dst, src, len)
++
+ #endif /* _ASM_IA64_CACHEFLUSH_H */
+--- linux-2.6.0-test6/include/asm-ia64/elf.h   2003-07-27 12:14:40.000000000 -0700
++++ 25/include/asm-ia64/elf.h  2003-10-05 00:33:24.000000000 -0700
+@@ -206,42 +206,46 @@ do {                                                                             \
+       NEW_AUX_ENT(AT_SYSINFO_EHDR, (unsigned long) GATE_EHDR);                \
+ } while (0)
++
+ /*
+- * These macros parameterize elf_core_dump in fs/binfmt_elf.c to write out extra segments
+- * containing the gate DSO contents.  Dumping its contents makes post-mortem fully
+- * interpretable later without matching up the same kernel and hardware config to see what
+- * IP values meant.  Dumping its extra ELF program headers includes all the other
+- * information a debugger needs to easily find how the gate DSO was being used.
++ * These macros parameterize elf_core_dump in fs/binfmt_elf.c to write out
++ * extra segments containing the gate DSO contents.  Dumping its
++ * contents makes post-mortem fully interpretable later without matching up
++ * the same kernel and hardware config to see what PC values meant.
++ * Dumping its extra ELF program headers includes all the other information
++ * a debugger needs to easily find how the gate DSO was being used.
+  */
+ #define ELF_CORE_EXTRA_PHDRS          (GATE_EHDR->e_phnum)
+ #define ELF_CORE_WRITE_EXTRA_PHDRS                                            \
+ do {                                                                          \
+-      const struct elf_phdr *const gate_phdrs =                               \
+-              (const struct elf_phdr *) (GATE_ADDR + GATE_EHDR->e_phoff);     \
++      const struct elf_phdr *const vsyscall_phdrs =                         \
++              (const struct elf_phdr *) (GATE_ADDR + GATE_EHDR->e_phoff);   \
+       int i;                                                                  \
+-      Elf64_Off ofs = 0;                                                      \
++      Elf32_Off ofs = 0;                                                    \
+       for (i = 0; i < GATE_EHDR->e_phnum; ++i) {                              \
+-              struct elf_phdr phdr = gate_phdrs[i];                           \
++              struct elf_phdr phdr = vsyscall_phdrs[i];                     \
+               if (phdr.p_type == PT_LOAD) {                                   \
++                      BUG_ON(ofs != 0);                                     \
+                       ofs = phdr.p_offset = offset;                           \
++                      phdr.p_memsz = PAGE_ALIGN(phdr.p_memsz);              \
++                      phdr.p_filesz = phdr.p_memsz;                         \
+                       offset += phdr.p_filesz;                                \
+-              } else                                                          \
++              }                                                             \
++              else                                                          \
+                       phdr.p_offset += ofs;                                   \
+               phdr.p_paddr = 0; /* match other core phdrs */                  \
+               DUMP_WRITE(&phdr, sizeof(phdr));                                \
+       }                                                                       \
+ } while (0)
+-
+ #define ELF_CORE_WRITE_EXTRA_DATA                                     \
+ do {                                                                  \
+-      const struct elf_phdr *const gate_phdrs =                       \
+-              (const struct elf_phdr *) (GATE_ADDR                    \
+-                                         + GATE_EHDR->e_phoff);       \
++      const struct elf_phdr *const vsyscall_phdrs =                         \
++              (const struct elf_phdr *) (GATE_ADDR + GATE_EHDR->e_phoff);   \
+       int i;                                                          \
+       for (i = 0; i < GATE_EHDR->e_phnum; ++i) {                      \
+-              if (gate_phdrs[i].p_type == PT_LOAD)                    \
+-                      DUMP_WRITE((void *) gate_phdrs[i].p_vaddr,      \
+-                                 gate_phdrs[i].p_filesz);             \
++              if (vsyscall_phdrs[i].p_type == PT_LOAD)                      \
++                      DUMP_WRITE((void *) vsyscall_phdrs[i].p_vaddr,        \
++                                 PAGE_ALIGN(vsyscall_phdrs[i].p_memsz));    \
+       }                                                               \
+ } while (0)
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/include/asm-ia64/lockmeter.h    2003-10-05 00:36:40.000000000 -0700
+@@ -0,0 +1,72 @@
++/*
++ *  Copyright (C) 1999,2000 Silicon Graphics, Inc.
++ *
++ *  Written by John Hawkes (hawkes@sgi.com)
++ *  Based on klstat.h by Jack Steiner (steiner@sgi.com)
++ */
++
++#ifndef _IA64_LOCKMETER_H
++#define _IA64_LOCKMETER_H
++
++#ifdef local_cpu_data
++#define CPU_CYCLE_FREQUENCY   local_cpu_data->itc_freq
++#else
++#define CPU_CYCLE_FREQUENCY   my_cpu_data.itc_freq
++#endif
++#define get_cycles64()                get_cycles()
++
++#define THIS_CPU_NUMBER               smp_processor_id()
++
++/*
++ * macros to cache and retrieve an index value inside of a lock
++ * these macros assume that there are less than 65536 simultaneous
++ * (read mode) holders of a rwlock.
++ * we also assume that the hash table has less than 32767 entries.
++ */
++/*
++ * instrumented spinlock structure -- never used to allocate storage
++ * only used in macros below to overlay a spinlock_t
++ */
++typedef struct inst_spinlock_s {
++      /* remember, Intel is little endian */
++      volatile unsigned short lock;
++      volatile unsigned short index;
++} inst_spinlock_t;
++#define PUT_INDEX(lock_ptr,indexv) ((inst_spinlock_t *)(lock_ptr))->index = indexv
++#define GET_INDEX(lock_ptr)        ((inst_spinlock_t *)(lock_ptr))->index
++
++/*
++ * macros to cache and retrieve an index value in a read/write lock
++ * as well as the cpu where a reader busy period started
++ * we use the 2nd word (the debug word) for this, so require the
++ * debug word to be present
++ */
++/*
++ * instrumented rwlock structure -- never used to allocate storage
++ * only used in macros below to overlay a rwlock_t
++ */
++typedef struct inst_rwlock_s {
++      volatile int read_counter:31;
++      volatile int write_lock:1;
++      volatile unsigned short index;
++      volatile unsigned short cpu;
++} inst_rwlock_t;
++#define PUT_RWINDEX(rwlock_ptr,indexv) ((inst_rwlock_t *)(rwlock_ptr))->index = indexv
++#define GET_RWINDEX(rwlock_ptr)        ((inst_rwlock_t *)(rwlock_ptr))->index
++#define PUT_RW_CPU(rwlock_ptr,cpuv)    ((inst_rwlock_t *)(rwlock_ptr))->cpu = cpuv
++#define GET_RW_CPU(rwlock_ptr)         ((inst_rwlock_t *)(rwlock_ptr))->cpu
++
++/*
++ * return the number of readers for a rwlock_t
++ */
++#define RWLOCK_READERS(rwlock_ptr)    ((rwlock_ptr)->read_counter)
++
++/*
++ * return true if rwlock is write locked
++ * (note that other lock attempts can cause the lock value to be negative)
++ */
++#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) ((rwlock_ptr)->write_lock)
++#define RWLOCK_IS_READ_LOCKED(rwlock_ptr)  ((rwlock_ptr)->read_counter)
++
++#endif /* _IA64_LOCKMETER_H */
++
+--- linux-2.6.0-test6/include/asm-ia64/mmzone.h        2003-06-14 12:18:52.000000000 -0700
++++ 25/include/asm-ia64/mmzone.h       2003-10-05 00:34:41.000000000 -0700
+@@ -92,14 +92,12 @@
+ extern unsigned long max_low_pfn;
+-#ifdef CONFIG_IA64_DIG
++#if defined(CONFIG_IA64_DIG)
+ /*
+  * Platform definitions for DIG platform with contiguous memory.
+  */
+-#define MAX_PHYSNODE_ID       8       /* Maximum node number +1 */
+-#define NR_NODES      8       /* Maximum number of nodes in SSI */
+-
++#define MAX_PHYSNODE_ID       8               /* Maximum node number +1 */
+ #define MAX_PHYS_MEMORY       (1UL << 40)     /* 1 TB */
+ /*
+@@ -119,37 +117,34 @@ extern unsigned long max_low_pfn;
+ # error Unsupported bank and nodesize!
+ #endif
+ #define BANKSIZE              (1UL << BANKSHIFT)
+-#define BANK_OFFSET(addr)     ((unsigned long)(addr) & (BANKSIZE-1))
+-#define NR_BANKS              (NR_BANKS_PER_NODE * NR_NODES)
+-
+-/*
+- * VALID_MEM_KADDR returns a boolean to indicate if a kaddr is
+- * potentially a valid cacheable identity mapped RAM memory address.
+- * Note that the RAM may or may not actually be present!!
+- */
+-#define VALID_MEM_KADDR(kaddr)        1
+-
+-/*
+- * Given a nodeid & a bank number, find the address of the mem_map
+- * entry for the first page of the bank.
+- */
+-#define BANK_MEM_MAP_INDEX(kaddr) \
+-      (((unsigned long)(kaddr) & (MAX_PHYS_MEMORY-1)) >> BANKSHIFT)
+ #elif defined(CONFIG_IA64_SGI_SN2)
++
+ /*
+  * SGI SN2 discontig definitions
+  */
+ #define MAX_PHYSNODE_ID       2048    /* 2048 node ids (also called nasid) */
+-#define NR_NODES      128     /* Maximum number of nodes in SSI */
+ #define MAX_PHYS_MEMORY       (1UL << 49)
+-#define BANKSHIFT             38
+ #define NR_BANKS_PER_NODE     4
++#define BANKSHIFT             38
+ #define SN2_NODE_SIZE         (64UL*1024*1024*1024)   /* 64GB per node */
+ #define BANKSIZE              (SN2_NODE_SIZE/NR_BANKS_PER_NODE)
++
++#endif /* CONFIG_IA64_DIG */
++
++#if defined(CONFIG_IA64_DIG) || defined (CONFIG_IA64_SGI_SN2)
++/* Common defines for both platforms */
++#include <asm/numnodes.h>
+ #define BANK_OFFSET(addr)     ((unsigned long)(addr) & (BANKSIZE-1))
+-#define NR_BANKS              (NR_BANKS_PER_NODE * NR_NODES)
++#define NR_BANKS              (NR_BANKS_PER_NODE * (1 << NODES_SHIFT))
++#define NR_MEMBLKS            (NR_BANKS)
++
++/*
++ * VALID_MEM_KADDR returns a boolean to indicate if a kaddr is
++ * potentially a valid cacheable identity mapped RAM memory address.
++ * Note that the RAM may or may not actually be present!!
++ */
+ #define VALID_MEM_KADDR(kaddr)        1
+ /*
+@@ -159,5 +154,6 @@ extern unsigned long max_low_pfn;
+ #define BANK_MEM_MAP_INDEX(kaddr) \
+       (((unsigned long)(kaddr) & (MAX_PHYS_MEMORY-1)) >> BANKSHIFT)
+-#endif /* CONFIG_IA64_DIG */
++#endif /* CONFIG_IA64_DIG || CONFIG_IA64_SGI_SN2 */
++
+ #endif /* _ASM_IA64_MMZONE_H */
+--- linux-2.6.0-test6/include/asm-ia64/nodedata.h      2003-06-22 12:04:45.000000000 -0700
++++ 25/include/asm-ia64/nodedata.h     2003-10-05 00:34:41.000000000 -0700
+@@ -8,12 +8,10 @@
+  * Copyright (c) 2002 Erich Focht <efocht@ess.nec.de>
+  * Copyright (c) 2002 Kimio Suganuma <k-suganuma@da.jp.nec.com>
+  */
+-
+-
+ #ifndef _ASM_IA64_NODEDATA_H
+ #define _ASM_IA64_NODEDATA_H
+-
++#include <linux/numa.h>
+ #include <asm/mmzone.h>
+ /*
+@@ -24,9 +22,9 @@ struct pglist_data;
+ struct ia64_node_data {
+       short                   active_cpu_count;
+       short                   node;
+-        struct pglist_data    *pg_data_ptrs[NR_NODES];
++      struct pglist_data      *pg_data_ptrs[MAX_NUMNODES];
+       struct page             *bank_mem_map_base[NR_BANKS];
+-      struct ia64_node_data   *node_data_ptrs[NR_NODES];
++      struct ia64_node_data   *node_data_ptrs[MAX_NUMNODES];
+       short                   node_id_map[NR_BANKS];
+ };
+--- linux-2.6.0-test6/include/asm-ia64/numa.h  2003-09-27 18:57:47.000000000 -0700
++++ 25/include/asm-ia64/numa.h 2003-10-05 00:34:41.000000000 -0700
+@@ -16,17 +16,11 @@
+ #ifdef CONFIG_NUMA
+-#ifdef CONFIG_DISCONTIGMEM
+-# include <asm/mmzone.h>
+-# define NR_MEMBLKS   (NR_BANKS)
+-#else
+-# define NR_NODES     (8)
+-# define NR_MEMBLKS   (NR_NODES * 8)
+-#endif
+-
++#include <linux/numa.h>
+ #include <linux/cache.h>
++
+ extern volatile char cpu_to_node_map[NR_CPUS] __cacheline_aligned;
+-extern volatile cpumask_t node_to_cpu_mask[NR_NODES] __cacheline_aligned;
++extern volatile cpumask_t node_to_cpu_mask[MAX_NUMNODES] __cacheline_aligned;
+ /* Stuff below this line could be architecture independent */
+@@ -60,7 +54,7 @@ extern struct node_cpuid_s node_cpuid[NR
+  * proportional to the memory access latency ratios.
+  */
+-extern u8 numa_slit[NR_NODES * NR_NODES];
++extern u8 numa_slit[MAX_NUMNODES * MAX_NUMNODES];
+ #define node_distance(from,to) (numa_slit[from * numnodes + to])
+ extern int paddr_to_nid(unsigned long paddr);
+--- linux-2.6.0-test6/include/asm-ia64/numnodes.h      2003-06-14 12:18:52.000000000 -0700
++++ 25/include/asm-ia64/numnodes.h     2003-10-05 00:34:41.000000000 -0700
+@@ -1,7 +1,12 @@
+ #ifndef _ASM_MAX_NUMNODES_H
+ #define _ASM_MAX_NUMNODES_H
+-#include <asm/mmzone.h>
+-#define MAX_NUMNODES  NR_NODES
++#ifdef CONFIG_IA64_DIG
++/* Max 8 Nodes */
++#define NODES_SHIFT   3
++#elif defined(CONFIG_IA64_SGI_SN2)
++/* Max 128 Nodes */
++#define NODES_SHIFT   7
++#endif
+ #endif /* _ASM_MAX_NUMNODES_H */
+--- linux-2.6.0-test6/include/asm-ia64/pgtable.h       2003-06-22 12:04:45.000000000 -0700
++++ 25/include/asm-ia64/pgtable.h      2003-10-05 00:33:24.000000000 -0700
+@@ -207,7 +207,6 @@ ia64_phys_addr_valid (unsigned long addr
+ #define RGN_KERNEL    7
+ #define VMALLOC_START         0xa000000200000000
+-#define VMALLOC_VMADDR(x)     ((unsigned long)(x))
+ #ifdef CONFIG_VIRTUAL_MEM_MAP
+ # define VMALLOC_END_INIT     (0xa000000000000000 + (1UL << (4*PAGE_SHIFT - 9)))
+ # define VMALLOC_END          vmalloc_end
+--- linux-2.6.0-test6/include/asm-ia64/sn/pda.h        2003-06-22 12:04:45.000000000 -0700
++++ 25/include/asm-ia64/sn/pda.h       2003-10-05 00:34:41.000000000 -0700
+@@ -10,6 +10,7 @@
+ #include <linux/config.h>
+ #include <linux/cache.h>
++#include <linux/numa.h>
+ #include <asm/percpu.h>
+ #include <asm/system.h>
+ #include <asm/processor.h>
+@@ -56,7 +57,7 @@ typedef struct pda_s {
+       unsigned long   sn_soft_irr[4];
+       unsigned long   sn_in_service_ivecs[4];
+-      short           cnodeid_to_nasid_table[NR_NODES];       
++      short           cnodeid_to_nasid_table[MAX_NUMNODES];
+       int             sn_lb_int_war_ticks;
+       int             sn_last_irq;
+       int             sn_first_irq;
+--- linux-2.6.0-test6/include/asm-ia64/spinlock.h      2003-09-27 18:57:47.000000000 -0700
++++ 25/include/asm-ia64/spinlock.h     2003-10-05 00:36:40.000000000 -0700
+@@ -110,8 +110,18 @@ do {                                                                                      \
+ typedef struct {
+       volatile int read_counter       : 31;
+       volatile int write_lock         :  1;
++#ifdef CONFIG_LOCKMETER
++      /* required for LOCKMETER since all bits in lock are used */
++      /* and we need this storage for CPU and lock INDEX        */
++      unsigned lockmeter_magic;
++#endif
+ } rwlock_t;
++
++#ifdef CONFIG_LOCKMETER
++#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0, 0 }
++#else
+ #define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 }
++#endif
+ #define rwlock_init(x)                do { *(x) = RW_LOCK_UNLOCKED; } while(0)
+ #define rwlock_is_locked(x)   (*(volatile int *) (x) != 0)
+@@ -127,6 +137,48 @@ do {                                                                                      \
+       }                                                                               \
+ } while (0)
++#ifdef CONFIG_LOCKMETER
++/*
++ * HACK: This works, but still have a timing window that affects performance:
++ * we see that no one owns the Write lock, then someone * else grabs for Write
++ * lock before we do a read_lock().
++ * This means that on rare occasions our read_lock() will stall and spin-wait
++ * until we acquire for Read, instead of simply returning a trylock failure.
++ */
++static inline int _raw_read_trylock(rwlock_t *rw)
++{
++      if (rw->write_lock) {
++              return 0;
++      } else {
++              _raw_read_lock(rw);
++              return 1;
++      }
++}
++
++static inline int _raw_write_trylock(rwlock_t *rw)
++{
++      if (!(rw->write_lock)) {
++          /* isn't currently write-locked... that looks promising... */
++          if (test_and_set_bit(31, rw) == 0) {
++              /* now it is write-locked by me... */
++              if (rw->read_counter) {
++                  /* really read-locked, so release write-lock and fail */
++                  clear_bit(31, rw);
++              } else {
++                  /* we've the the write-lock, no read-lockers... success! */
++                  barrier();
++                  return 1;
++              }
++
++          }
++      }
++
++      /* falls through ... fails to write-lock */
++      barrier();
++      return 0;
++}
++#endif
++
+ #define _raw_read_unlock(rw)                                  \
+ do {                                                          \
+       rwlock_t *__read_lock_ptr = (rw);                       \
+@@ -190,4 +242,25 @@ do {                                                                              \
+       clear_bit(31, (x));                                                             \
+ })
++#ifdef CONFIG_LOCKMETER
++extern void _metered_spin_lock  (spinlock_t *lock);
++extern void _metered_spin_unlock(spinlock_t *lock);
++
++/*
++ *  Use a less efficient, and inline, atomic_dec_and_lock() if lockmetering
++ *  so we can see the callerPC of who is actually doing the spin_lock().
++ *  Otherwise, all we see is the generic rollup of all locks done by
++ *  atomic_dec_and_lock().
++ */
++static inline int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
++{
++      _metered_spin_lock(lock);
++      if (atomic_dec_and_test(atomic))
++              return 1;
++      _metered_spin_unlock(lock);
++      return 0;
++}
++#define ATOMIC_DEC_AND_LOCK
++#endif
++
+ #endif /*  _ASM_IA64_SPINLOCK_H */
+--- linux-2.6.0-test6/include/asm-m68k/bitops.h        2003-06-14 12:18:52.000000000 -0700
++++ 25/include/asm-m68k/bitops.h       2003-10-05 00:33:24.000000000 -0700
+@@ -164,9 +164,10 @@ extern __inline__ int test_bit(int nr, c
+       return ((1UL << (nr & 31)) & (((const volatile unsigned long *) vaddr)[nr >> 5])) != 0;
+ }
+-extern __inline__ int find_first_zero_bit(unsigned long * vaddr, unsigned size)
++extern __inline__ int find_first_zero_bit(const unsigned long *vaddr,
++                                        unsigned size)
+ {
+-      unsigned long *p = vaddr, *addr = vaddr;
++      const unsigned long *p = vaddr, *addr = vaddr;
+       unsigned long allones = ~0UL;
+       int res;
+       unsigned long num;
+@@ -187,11 +188,11 @@ extern __inline__ int find_first_zero_bi
+       return ((p - addr) << 5) + (res ^ 31);
+ }
+-extern __inline__ int find_next_zero_bit (unsigned long *vaddr, int size,
++extern __inline__ int find_next_zero_bit (const unsigned long *vaddr, int size,
+                                     int offset)
+ {
+-      unsigned long *addr = vaddr;
+-      unsigned long *p = addr + (offset >> 5);
++      const unsigned long *addr = vaddr;
++      const unsigned long *p = addr + (offset >> 5);
+       int set = 0, bit = offset & 31UL, res;
+       if (offset >= size)
+@@ -263,7 +264,7 @@ static inline int fls(int x)
+  * unlikely to be set. It's guaranteed that at least one of the 140
+  * bits is cleared.
+  */
+-static inline int sched_find_first_bit(unsigned long *b)
++static inline int sched_find_first_bit(const unsigned long *b)
+ {
+       if (unlikely(b[0]))
+               return __ffs(b[0]);
+--- linux-2.6.0-test6/include/asm-m68k/cacheflush.h    2003-07-27 12:14:40.000000000 -0700
++++ 25/include/asm-m68k/cacheflush.h   2003-10-05 00:33:24.000000000 -0700
+@@ -80,6 +80,9 @@ extern void cache_push_v(unsigned long v
+ #define flush_cache_all() __flush_cache_all()
++#define flush_cache_vmap(start, end)          flush_cache_all()
++#define flush_cache_vunmap(start, end)                flush_cache_all()
++
+ extern inline void flush_cache_mm(struct mm_struct *mm)
+ {
+       if (mm == current->mm)
+@@ -127,6 +130,10 @@ extern inline void __flush_page_to_ram(v
+ #define flush_dcache_page(page)               __flush_page_to_ram(page_address(page))
+ #define flush_icache_page(vma, page)  __flush_page_to_ram(page_address(page))
+ #define flush_icache_user_range(vma,pg,adr,len)       do { } while (0)
++#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
++      memcpy(dst, src, len)
++#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
++      memcpy(dst, src, len)
+ extern void flush_icache_range(unsigned long address, unsigned long endaddr);
+--- linux-2.6.0-test6/include/asm-m68knommu/cacheflush.h       2003-06-14 12:18:34.000000000 -0700
++++ 25/include/asm-m68knommu/cacheflush.h      2003-10-05 00:33:24.000000000 -0700
+@@ -15,7 +15,13 @@
+ #define flush_icache_range(start,len)         __flush_cache_all()
+ #define flush_icache_page(vma,pg)             do { } while (0)
+ #define flush_icache_user_range(vma,pg,adr,len)       do { } while (0)
++#define flush_cache_vmap(start, end)          flush_cache_all()
++#define flush_cache_vunmap(start, end)                flush_cache_all()
++#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
++      memcpy(dst, src, len)
++#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
++      memcpy(dst, src, len)
+ extern inline void __flush_cache_all(void)
+ {
+--- linux-2.6.0-test6/include/asm-m68k/pci.h   2003-06-14 12:18:09.000000000 -0700
++++ 25/include/asm-m68k/pci.h  2003-10-05 00:33:24.000000000 -0700
+@@ -7,6 +7,8 @@
+  * Written by Wout Klaren.
+  */
++#include <asm/scatterlist.h>
++
+ struct pci_ops;
+ /*
+--- linux-2.6.0-test6/include/asm-m68k/pgtable.h       2003-06-14 12:18:32.000000000 -0700
++++ 25/include/asm-m68k/pgtable.h      2003-10-05 00:33:24.000000000 -0700
+@@ -79,12 +79,10 @@
+  */
+ #define VMALLOC_OFFSET        (8*1024*1024)
+ #define VMALLOC_START (((unsigned long) high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+ #define VMALLOC_END KMAP_START
+ #else
+ extern unsigned long vmalloc_end;
+ #define VMALLOC_START 0x0f800000
+-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+ #define VMALLOC_END vmalloc_end
+ #endif /* CONFIG_SUN3 */
+--- linux-2.6.0-test6/include/asm-m68k/zorro.h 2003-06-14 12:18:03.000000000 -0700
++++ 25/include/asm-m68k/zorro.h        2003-10-05 00:33:24.000000000 -0700
+@@ -42,4 +42,4 @@ extern inline void *z_remap_fullcache(un
+ #define z_iounmap iounmap
+ #define z_ioremap z_remap_nocache_ser
+-#endif /* _ASM_ZORRO_H */
++#endif /* _ASM_M68K_ZORRO_H */
+--- linux-2.6.0-test6/include/asm-mips/cacheflush.h    2003-08-08 22:55:13.000000000 -0700
++++ 25/include/asm-mips/cacheflush.h   2003-10-05 00:33:24.000000000 -0700
+@@ -43,7 +43,15 @@ extern void (*flush_icache_page)(struct 
+ extern void (*flush_icache_range)(unsigned long start, unsigned long end);
+ #define flush_icache_user_range(vma, page, addr, len)   \
+                                       flush_icache_page(vma, page)
++#define flush_cache_vmap(start, end)          flush_cache_all()
++#define flush_cache_vunmap(start, end)                flush_cache_all()
++#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
++do { memcpy(dst, src, len); \
++     flush_icache_user_range(vma, page, vaddr, len); \
++} while (0)
++#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
++      memcpy(dst, src, len)
+ extern void (*flush_cache_sigtramp)(unsigned long addr);
+ extern void (*flush_icache_all)(void);
+--- linux-2.6.0-test6/include/asm-mips/highmem.h       2003-07-02 14:53:17.000000000 -0700
++++ 25/include/asm-mips/highmem.h      2003-10-05 00:33:24.000000000 -0700
+@@ -54,6 +54,8 @@ extern void *kmap_atomic(struct page *pa
+ extern void kunmap_atomic(void *kvaddr, enum km_type type);
+ extern struct page *kmap_atomic_to_page(void *ptr);
++#define flush_cache_kmaps()   flush_cache_all()
++
+ #endif /* __KERNEL__ */
+ #endif /* _ASM_HIGHMEM_H */
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/include/asm-mips/lockmeter.h    2003-10-05 00:36:40.000000000 -0700
+@@ -0,0 +1,126 @@
++/*
++ *  Copyright (C) 1999,2000 Silicon Graphics, Inc.
++ *
++ *  Written by John Hawkes (hawkes@sgi.com)
++ *  Based on klstat.h by Jack Steiner (steiner@sgi.com)
++ *  Ported to mips32 for Asita Technologies
++ *   by D.J. Barrow ( dj.barrow@asitatechnologies.com )
++ */
++#ifndef _ASM_LOCKMETER_H
++#define _ASM_LOCKMETER_H
++
++/* do_gettimeoffset is a function pointer on mips */
++/* & it is not included by <linux/time.h> */
++#include <asm/time.h>
++#include <linux/time.h>
++#include <asm/div64.h>
++
++#define SPINLOCK_MAGIC_INIT   /* */
++
++#define CPU_CYCLE_FREQUENCY   get_cpu_cycle_frequency()
++
++#define THIS_CPU_NUMBER               smp_processor_id()
++
++static uint32_t cpu_cycle_frequency = 0;
++
++static uint32_t get_cpu_cycle_frequency(void)
++{
++    /* a total hack, slow and invasive, but ... it works */
++    int sec;
++    uint32_t start_cycles;
++    struct timeval tv;
++
++    if (cpu_cycle_frequency == 0) {   /* uninitialized */
++      do_gettimeofday(&tv);
++      sec = tv.tv_sec;        /* set up to catch the tv_sec rollover */
++      while (sec == tv.tv_sec) { do_gettimeofday(&tv); }
++      sec = tv.tv_sec;        /* rolled over to a new sec value */
++      start_cycles = get_cycles();
++      while (sec == tv.tv_sec) { do_gettimeofday(&tv); }
++      cpu_cycle_frequency = get_cycles() - start_cycles;
++    }
++
++    return cpu_cycle_frequency;
++}
++
++extern struct timeval xtime;
++
++static uint64_t get_cycles64(void)
++{
++    static uint64_t last_get_cycles64 = 0;
++    uint64_t ret;
++    unsigned long sec;
++    unsigned long usec, usec_offset;
++
++again:
++    sec  = xtime.tv_sec;
++    usec = xtime.tv_usec;
++    usec_offset = do_gettimeoffset();
++    if ((xtime.tv_sec != sec)  ||
++      (xtime.tv_usec != usec)||
++      (usec_offset >= 20000))
++      goto again;
++
++    ret = ((uint64_t)(usec + usec_offset) * cpu_cycle_frequency);
++    /* We can't do a normal 64 bit division on mips without libgcc.a */
++    do_div(ret,1000000);
++    ret +=  ((uint64_t)sec * cpu_cycle_frequency);
++
++    /* XXX why does time go backwards?  do_gettimeoffset?  general time adj? */
++    if (ret <= last_get_cycles64)
++      ret  = last_get_cycles64+1;
++    last_get_cycles64 = ret;
++
++    return ret;
++}
++
++/*
++ * macros to cache and retrieve an index value inside of a lock
++ * these macros assume that there are less than 65536 simultaneous
++ * (read mode) holders of a rwlock.
++ * we also assume that the hash table has less than 32767 entries.
++ * the high order bit is used for write locking a rw_lock
++ */
++#define INDEX_MASK   0x7FFF0000
++#define READERS_MASK 0x0000FFFF
++#define INDEX_SHIFT 16
++#define PUT_INDEX(lockp,index)   \
++        lockp->lock = (((lockp->lock) & ~INDEX_MASK) | (index) << INDEX_SHIFT)
++#define GET_INDEX(lockp) \
++        (((lockp->lock) & INDEX_MASK) >> INDEX_SHIFT)
++
++/*
++ * macros to cache and retrieve an index value in a read/write lock
++ * as well as the cpu where a reader busy period started
++ * we use the 2nd word (the debug word) for this, so require the
++ * debug word to be present
++ */
++/*
++ * instrumented rwlock structure -- never used to allocate storage
++ * only used in macros below to overlay a rwlock_t
++ */
++typedef struct inst_rwlock_s {
++      volatile int lock;
++      unsigned short index;
++      unsigned short cpu;
++} inst_rwlock_t;
++#define PUT_RWINDEX(rwlock_ptr,indexv) ((inst_rwlock_t *)(rwlock_ptr))->index = indexv
++#define GET_RWINDEX(rwlock_ptr)        ((inst_rwlock_t *)(rwlock_ptr))->index
++#define PUT_RW_CPU(rwlock_ptr,cpuv)    ((inst_rwlock_t *)(rwlock_ptr))->cpu = cpuv
++#define GET_RW_CPU(rwlock_ptr)         ((inst_rwlock_t *)(rwlock_ptr))->cpu
++
++/*
++ * return the number of readers for a rwlock_t
++ */
++#define RWLOCK_READERS(rwlock_ptr)   rwlock_readers(rwlock_ptr)
++
++extern inline int rwlock_readers(rwlock_t *rwlock_ptr)
++{
++      int tmp = (int) rwlock_ptr->lock;
++      return (tmp >= 0) ? tmp : 0;
++}
++
++#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) ((rwlock_ptr)->lock < 0)
++#define RWLOCK_IS_READ_LOCKED(rwlock_ptr)  ((rwlock_ptr)->lock > 0)
++
++#endif /* _ASM_LOCKMETER_H */
+--- linux-2.6.0-test6/include/asm-mips/pgtable-32.h    2003-08-08 22:55:13.000000000 -0700
++++ 25/include/asm-mips/pgtable-32.h   2003-10-05 00:33:24.000000000 -0700
+@@ -79,7 +79,6 @@ extern int add_temporary_entry(unsigned 
+ #define FIRST_USER_PGD_NR     0
+ #define VMALLOC_START     KSEG2
+-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+ #if CONFIG_HIGHMEM
+ # define VMALLOC_END  (PKMAP_BASE-2*PAGE_SIZE)
+--- linux-2.6.0-test6/include/asm-mips/pgtable-64.h    2003-08-08 22:55:13.000000000 -0700
++++ 25/include/asm-mips/pgtable-64.h   2003-10-05 00:33:24.000000000 -0700
+@@ -64,7 +64,6 @@
+ #define FIRST_USER_PGD_NR     0
+ #define VMALLOC_START         XKSEG
+-#define VMALLOC_VMADDR(x)     ((unsigned long)(x))
+ #define VMALLOC_END   \
+       (VMALLOC_START + ((1 << PGD_ORDER) * PTRS_PER_PTE * PAGE_SIZE))
+--- linux-2.6.0-test6/include/asm-mips/spinlock.h      2003-07-02 14:53:17.000000000 -0700
++++ 25/include/asm-mips/spinlock.h     2003-10-05 00:36:40.000000000 -0700
+@@ -91,9 +91,18 @@ static inline unsigned int _raw_spin_try
+ typedef struct {
+       volatile unsigned int lock;
++#ifdef CONFIG_LOCKMETER
++      /* required for LOCKMETER since all bits in lock are used */
++      /* and we need this storage for CPU and lock INDEX        */
++      unsigned lockmeter_magic;
++#endif
+ } rwlock_t;
++#ifdef CONFIG_LOCKMETER
++#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 }
++#else
+ #define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
++#endif
+ #define rwlock_init(x)  do { *(x) = RW_LOCK_UNLOCKED; } while(0)
+--- linux-2.6.0-test6/include/asm-parisc/atomic.h      2003-09-27 18:57:47.000000000 -0700
++++ 25/include/asm-parisc/atomic.h     2003-10-05 00:33:24.000000000 -0700
+@@ -129,8 +129,9 @@ __cmpxchg(volatile void *ptr, unsigned l
+ /* It's possible to reduce all atomic operations to either
+- * __atomic_add_return, __atomic_set and __atomic_ret (the latter
+- * is there only for consistency). */
++ * __atomic_add_return, atomic_set and atomic_read (the latter
++ * is there only for consistency).
++ */
+ static __inline__ int __atomic_add_return(int i, atomic_t *v)
+ {
+@@ -144,7 +145,7 @@ static __inline__ int __atomic_add_retur
+       return ret;
+ }
+-static __inline__ void __atomic_set(atomic_t *v, int i) 
++static __inline__ void atomic_set(atomic_t *v, int i) 
+ {
+       unsigned long flags;
+       SPIN_LOCK_IRQSAVE(ATOMIC_HASH(v), flags);
+@@ -154,28 +155,25 @@ static __inline__ void __atomic_set(atom
+       SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(v), flags);
+ }
+-static __inline__ int __atomic_read(atomic_t *v)
++static __inline__ int atomic_read(const atomic_t *v)
+ {
+       return v->counter;
+ }
+ /* exported interface */
+-#define atomic_add(i,v)               ((void)(__atomic_add_return( (i),(v))))
+-#define atomic_sub(i,v)               ((void)(__atomic_add_return(-(i),(v))))
+-#define atomic_inc(v)         ((void)(__atomic_add_return(   1,(v))))
+-#define atomic_dec(v)         ((void)(__atomic_add_return(  -1,(v))))
++#define atomic_add(i,v)       ((void)(__atomic_add_return( ((int)i),(v))))
++#define atomic_sub(i,v)       ((void)(__atomic_add_return(-((int)i),(v))))
++#define atomic_inc(v) ((void)(__atomic_add_return(   1,(v))))
++#define atomic_dec(v) ((void)(__atomic_add_return(  -1,(v))))
+-#define atomic_add_return(i,v)        (__atomic_add_return( (i),(v)))
+-#define atomic_sub_return(i,v)        (__atomic_add_return(-(i),(v)))
++#define atomic_add_return(i,v)        (__atomic_add_return( ((int)i),(v)))
++#define atomic_sub_return(i,v)        (__atomic_add_return(-((int)i),(v)))
+ #define atomic_inc_return(v)  (__atomic_add_return(   1,(v)))
+ #define atomic_dec_return(v)  (__atomic_add_return(  -1,(v)))
+ #define atomic_dec_and_test(v)        (atomic_dec_return(v) == 0)
+-#define atomic_set(v,i)               (__atomic_set((v),i))
+-#define atomic_read(v)                (__atomic_read(v))
+-
+ #define ATOMIC_INIT(i)        { (i) }
+ #define smp_mb__before_atomic_dec()   smp_mb()
+--- linux-2.6.0-test6/include/asm-parisc/bitops.h      2003-09-27 18:57:47.000000000 -0700
++++ 25/include/asm-parisc/bitops.h     2003-10-05 00:33:24.000000000 -0700
+@@ -232,24 +232,24 @@ static __inline__ unsigned long __ffs(un
+ #if BITS_PER_LONG > 32
+               " ldi       63,%1\n"
+               " extrd,u,*<>  %0,63,32,%%r0\n"
+-              " extrd,u,*TR  %0,31,32,%0\n"
++              " extrd,u,*TR  %0,31,32,%0\n"   /* move top 32-bits down */
+               " addi    -32,%1,%1\n"
+ #else
+               " ldi       31,%1\n"
+ #endif
+               " extru,<>  %0,31,16,%%r0\n"
+-              " extru,TR  %0,15,16,%0\n"
++              " extru,TR  %0,15,16,%0\n"      /* xxxx0000 -> 0000xxxx */
+               " addi    -16,%1,%1\n"
+               " extru,<>  %0,31,8,%%r0\n"
+-              " extru,TR  %0,23,8,%0\n"
++              " extru,TR  %0,23,8,%0\n"       /* 0000xx00 -> 000000xx */
+               " addi    -8,%1,%1\n"
+               " extru,<>  %0,31,4,%%r0\n"
+-              " extru,TR  %0,27,4,%0\n"
++              " extru,TR  %0,27,4,%0\n"       /* 000000x0 -> 0000000x */
+               " addi    -4,%1,%1\n"
+               " extru,<>  %0,31,2,%%r0\n"
+-              " extru,TR  %0,29,2,%0\n"
++              " extru,TR  %0,29,2,%0\n"       /* 0000000y, 1100b -> 0011b */
+               " addi    -2,%1,%1\n"
+-              " extru,=  %0,31,1,%%r0\n"
++              " extru,=  %0,31,1,%%r0\n"      /* check last bit */
+               " addi    -1,%1,%1\n"
+                       : "+r" (x), "=r" (ret) );
+       return ret;
+@@ -291,7 +291,7 @@ static __inline__ int fls(int x)
+       "       zdep,TR         %0,27,28,%0\n"          /* x0000000 */
+       "       addi            4,%1,%1\n"
+       "       extru,<>        %0,1,2,%%r0\n"
+-      "       zdep,TR         %0,29,30,%0\n"          /* y0000000 (y&3 = 0 */
++      "       zdep,TR         %0,29,30,%0\n"          /* y0000000 (y&3 = 0) */
+       "       addi            2,%1,%1\n"
+       "       extru,=         %0,0,1,%%r0\n"
+       "       addi            1,%1,%1\n"              /* if y & 8, add 1 */
+--- linux-2.6.0-test6/include/asm-parisc/cacheflush.h  2003-09-27 18:57:47.000000000 -0700
++++ 25/include/asm-parisc/cacheflush.h 2003-10-05 00:33:24.000000000 -0700
+@@ -30,6 +30,9 @@ static inline void flush_cache_all(void)
+       on_each_cpu(cacheflush_h_tmp_function, NULL, 1, 1);
+ }
++#define flush_cache_vmap(start, end)          flush_cache_all()
++#define flush_cache_vunmap(start, end)                flush_cache_all()
++
+ /* The following value needs to be tuned and probably scaled with the
+  * cache size.
+  */
+@@ -82,6 +85,13 @@ static inline void flush_dcache_page(str
+         flush_user_dcache_range(addr, addr + len); \
+       flush_user_icache_range(addr, addr + len); } while (0)
++#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
++do { memcpy(dst, src, len); \
++     flush_icache_user_range(vma, page, vaddr, len); \
++} while (0)
++#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
++      memcpy(dst, src, len)
++
+ static inline void flush_cache_range(struct vm_area_struct *vma,
+               unsigned long start, unsigned long end)
+ {
+--- linux-2.6.0-test6/include/asm-parisc/dma-mapping.h 2003-06-14 12:18:07.000000000 -0700
++++ 25/include/asm-parisc/dma-mapping.h        2003-10-05 00:33:24.000000000 -0700
+@@ -2,6 +2,7 @@
+ #define _PARISC_DMA_MAPPING_H
+ #include <linux/mm.h>
++#include <linux/config.h>
+ #include <asm/cacheflush.h>
+ /*
+--- linux-2.6.0-test6/include/asm-parisc/elf.h 2003-09-27 18:57:47.000000000 -0700
++++ 25/include/asm-parisc/elf.h        2003-10-05 00:33:24.000000000 -0700
+@@ -144,6 +144,30 @@
+ #define R_PARISC_LTOFF_TP16DF 231     /* 16 bits LT-TP-rel. address.  */
+ #define R_PARISC_HIRESERVE    255
++#define PA_PLABEL_FDESC               0x02    /* bit set if PLABEL points to
++                                       * a function descriptor, not
++                                       * an address */
++
++/* The following are PA function descriptors 
++ *
++ * addr:      the absolute address of the function
++ * gp:                either the data pointer (r27) for non-PIC code or the
++ *            the PLT pointer (r19) for PIC code */
++
++/* Format for the Elf32 Function descriptor */
++typedef struct elf32_fdesc {
++      __u32   addr;
++      __u32   gp;
++} Elf32_Fdesc;
++
++/* Format for the Elf64 Function descriptor */
++typedef struct elf64_fdesc {
++      __u64   dummy[2]; /* FIXME: nothing uses these, why waste
++                         * the space */
++      __u64   addr;
++      __u64   gp;
++} Elf64_Fdesc;
++
+ /* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr.  */
+ #define PT_HP_TLS             (PT_LOOS + 0x0)
+@@ -215,7 +239,10 @@ typedef unsigned long elf_greg_t;
+ #ifdef __KERNEL__
+ #define SET_PERSONALITY(ex, ibcs2) \
+-      current->personality = PER_LINUX
++      current->personality = PER_LINUX; \
++      current->thread.map_base = DEFAULT_MAP_BASE; \
++      current->thread.task_size = DEFAULT_TASK_SIZE \
++
+ #endif
+ /*
+--- linux-2.6.0-test6/include/asm-parisc/ioctl.h       2003-06-14 12:17:55.000000000 -0700
++++ 25/include/asm-parisc/ioctl.h      2003-10-05 00:33:24.000000000 -0700
+@@ -44,11 +44,21 @@
+        ((nr)   << _IOC_NRSHIFT) | \
+        ((size) << _IOC_SIZESHIFT))
++/* provoke compile error for invalid uses of size argument */
++extern int __invalid_size_argument_for_IOC;
++#define _IOC_TYPECHECK(t) \
++      ((sizeof(t) == sizeof(t[1]) && \
++        sizeof(t) < (1 << _IOC_SIZEBITS)) ? \
++        sizeof(t) : __invalid_size_argument_for_IOC)
++
+ /* used to create numbers */
+ #define _IO(type,nr)          _IOC(_IOC_NONE,(type),(nr),0)
+-#define _IOR(type,nr,size)    _IOC(_IOC_READ,(type),(nr),sizeof(size))
+-#define _IOW(type,nr,size)    _IOC(_IOC_WRITE,(type),(nr),sizeof(size))
+-#define _IOWR(type,nr,size)   _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))
++#define _IOR(type,nr,size)    _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))
++#define _IOW(type,nr,size)    _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
++#define _IOWR(type,nr,size)   _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
++#define _IOR_BAD(type,nr,size)        _IOC(_IOC_READ,(type),(nr),sizeof(size))
++#define _IOW_BAD(type,nr,size)        _IOC(_IOC_WRITE,(type),(nr),sizeof(size))
++#define _IOWR_BAD(type,nr,size)       _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))
+ /* used to decode ioctl numbers.. */
+ #define _IOC_DIR(nr)          (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
+--- linux-2.6.0-test6/include/asm-parisc/irq.h 2003-06-14 12:18:07.000000000 -0700
++++ 25/include/asm-parisc/irq.h        2003-10-05 00:33:24.000000000 -0700
+@@ -17,6 +17,7 @@
+ #include <linux/string.h>
+ #include <linux/interrupt.h>
++#include <linux/config.h>
+ #define CPU_IRQ_REGION                1
+--- linux-2.6.0-test6/include/asm-parisc/keyboard.h    2003-06-14 12:18:04.000000000 -0700
++++ 25/include/asm-parisc/keyboard.h   2003-10-05 00:33:24.000000000 -0700
+@@ -25,8 +25,6 @@
+ #ifndef _PARISC_KEYBOARD_H
+ #define _PARISC_KEYBOARD_H
+-#include <linux/config.h>
+-
+ #ifdef __KERNEL__
+ #include <linux/kernel.h>
+--- linux-2.6.0-test6/include/asm-parisc/page.h        2003-06-14 12:18:00.000000000 -0700
++++ 25/include/asm-parisc/page.h       2003-10-05 00:33:24.000000000 -0700
+@@ -7,6 +7,7 @@
+ #define PAGE_MASK     (~(PAGE_SIZE-1))
+ #ifdef __KERNEL__
++#include <linux/config.h>
+ #ifndef __ASSEMBLY__
+ #include <asm/cache.h>
+--- linux-2.6.0-test6/include/asm-parisc/param.h       2003-06-14 12:18:08.000000000 -0700
++++ 25/include/asm-parisc/param.h      2003-10-05 00:33:24.000000000 -0700
+@@ -2,6 +2,7 @@
+ #define _ASMPARISC_PARAM_H
+ #ifdef __KERNEL__
++#include <linux/config.h>
+ # ifdef CONFIG_PA20
+ #  define HZ          1000            /* Faster machines */
+ # else
+--- linux-2.6.0-test6/include/asm-parisc/pci.h 2003-06-14 12:18:29.000000000 -0700
++++ 25/include/asm-parisc/pci.h        2003-10-05 00:33:24.000000000 -0700
+@@ -1,6 +1,7 @@
+ #ifndef __ASM_PARISC_PCI_H
+ #define __ASM_PARISC_PCI_H
++#include <linux/config.h>
+ #include <asm/scatterlist.h>
+ /*
+--- linux-2.6.0-test6/include/asm-parisc/pdc.h 2003-06-14 12:17:55.000000000 -0700
++++ 25/include/asm-parisc/pdc.h        2003-10-05 00:33:24.000000000 -0700
+@@ -1,6 +1,8 @@
+ #ifndef _PARISC_PDC_H
+ #define _PARISC_PDC_H
++#include <linux/config.h>
++
+ /*
+  *    PDC return values ...
+  *    All PDC calls return a subset of these errors. 
+@@ -191,8 +193,8 @@ typedef struct {
+ #define PDC_IO                135             /* log error info, reset IO system */
+ #define PDC_IO_READ_AND_CLEAR_ERRORS  0
+-#define PDC_IO_READ_AND_LOG_ERRORS    1
+-#define PDC_IO_SUSPEND_USB            2
++#define PDC_IO_RESET                  1
++#define PDC_IO_RESET_DEVICES          2
+ /* sets bits 6&7 (little endian) of the HcControl Register */
+ #define PDC_IO_USB_SUSPEND    0xC000000000000000
+ #define PDC_IO_EEPROM_IO_ERR_TABLE_FULL       -5      /* return value */
+@@ -951,7 +953,8 @@ int pdc_do_firm_test_reset(unsigned long
+ int pdc_do_reset(void);
+ int pdc_soft_power_info(unsigned long *power_reg);
+ int pdc_soft_power_button(int sw_control);
+-void pdc_suspend_usb(void);
++void pdc_io_reset(void);
++void pdc_io_reset_devices(void);
+ int pdc_iodc_getc(void);
+ void pdc_iodc_putc(unsigned char c);
+ void pdc_iodc_outc(unsigned char c);
+--- linux-2.6.0-test6/include/asm-parisc/pgalloc.h     2003-06-14 12:18:35.000000000 -0700
++++ 25/include/asm-parisc/pgalloc.h    2003-10-05 00:33:24.000000000 -0700
+@@ -1,7 +1,6 @@
+ #ifndef _ASM_PGALLOC_H
+ #define _ASM_PGALLOC_H
+-#include <linux/config.h>
+ #include <linux/gfp.h>
+ #include <linux/mm.h>
+ #include <linux/threads.h>
+--- linux-2.6.0-test6/include/asm-parisc/pgtable.h     2003-07-13 21:44:35.000000000 -0700
++++ 25/include/asm-parisc/pgtable.h    2003-10-05 00:33:24.000000000 -0700
+@@ -1,6 +1,7 @@
+ #ifndef _PARISC_PGTABLE_H
+ #define _PARISC_PGTABLE_H
++#include <linux/config.h>
+ #include <asm/fixmap.h>
+ #ifndef __ASSEMBLY__
+@@ -108,7 +109,6 @@
+ extern  void *vmalloc_start;
+ #define PCXL_DMA_MAP_SIZE   (8*1024*1024)
+ #define VMALLOC_START   ((unsigned long)vmalloc_start)
+-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+ /* this is a fixmap remnant, see fixmap.h */
+ #define VMALLOC_END   (TMPALIAS_MAP_START)
+ #endif
+--- linux-2.6.0-test6/include/asm-parisc/processor.h   2003-09-27 18:57:47.000000000 -0700
++++ 25/include/asm-parisc/processor.h  2003-10-05 00:33:24.000000000 -0700
+@@ -36,10 +36,18 @@
+ #define current_text_addr() ({ void *pc; __asm__("\n\tblr 0,%0\n\tnop":"=r" (pc)); pc; })
+ #define TASK_SIZE               (current->thread.task_size)
+-#define DEFAULT_TASK_SIZE       (0xFFF00000UL)
+-
+ #define TASK_UNMAPPED_BASE      (current->thread.map_base)
+-#define DEFAULT_MAP_BASE        (0x40000000UL)
++
++#define DEFAULT_TASK_SIZE32   (0xFFF00000UL)
++#define DEFAULT_MAP_BASE32    (0x40000000UL)
++
++#ifdef __LP64__
++#define DEFAULT_TASK_SIZE       (MAX_ADDRESS-0xf000000)
++#define DEFAULT_MAP_BASE        (0x200000000UL)
++#else
++#define DEFAULT_TASK_SIZE     DEFAULT_TASK_SIZE32
++#define DEFAULT_MAP_BASE      DEFAULT_MAP_BASE32
++#endif
+ #ifndef __ASSEMBLY__
+@@ -247,8 +255,18 @@ on downward growing arches, it looks lik
+  *
+  * Note that the S/390 people took the easy way out and hacked their
+  * GCC to make the stack grow downwards.
++ *
++ * Final Note: For entry from syscall, the W (wide) bit of the PSW
++ * is stuffed into the lowest bit of the user sp (%r30), so we fill
++ * it in here from the current->personality
+  */
++#ifdef __LP64__
++#define USER_WIDE_MODE        (personality(current->personality) == PER_LINUX)
++#else
++#define USER_WIDE_MODE        0
++#endif
++
+ #define start_thread(regs, new_pc, new_sp) do {               \
+       elf_addr_t *sp = (elf_addr_t *)new_sp;          \
+       __u32 spaceid = (__u32)current->mm->context;    \
+@@ -266,12 +284,12 @@ on downward growing arches, it looks lik
+       regs->sr[5] = spaceid;                          \
+       regs->sr[6] = spaceid;                          \
+       regs->sr[7] = spaceid;                          \
+-      regs->gr[ 0] = USER_PSW;                        \
++      regs->gr[ 0] = USER_PSW | (USER_WIDE_MODE ? PSW_W : 0); \
+       regs->fr[ 0] = 0LL;                             \
+       regs->fr[ 1] = 0LL;                             \
+       regs->fr[ 2] = 0LL;                             \
+       regs->fr[ 3] = 0LL;                             \
+-      regs->gr[30] = ((unsigned long)sp + 63) &~ 63;  \
++      regs->gr[30] = (((unsigned long)sp + 63) &~ 63) | (USER_WIDE_MODE ? 1 : 0); \
+       regs->gr[31] = pc;                              \
+                                                       \
+       get_user(regs->gr[25], (argv - 1));             \
+@@ -299,8 +317,6 @@ static inline unsigned long get_wchan(st
+ #define KSTK_EIP(tsk) ((tsk)->thread.regs.iaoq[0])
+ #define KSTK_ESP(tsk) ((tsk)->thread.regs.gr[30])
+-#endif /* __ASSEMBLY__ */
+-
+ #ifdef  CONFIG_PA20
+ #define ARCH_HAS_PREFETCH
+ extern inline void prefetch(const void *addr)
+@@ -317,4 +333,6 @@ extern inline void prefetchw(const void 
+ #define cpu_relax()   barrier()
++#endif /* __ASSEMBLY__ */
++
+ #endif /* __ASM_PARISC_PROCESSOR_H */
+--- linux-2.6.0-test6/include/asm-parisc/rt_sigframe.h 2003-06-14 12:18:08.000000000 -0700
++++ 25/include/asm-parisc/rt_sigframe.h        2003-10-05 00:33:24.000000000 -0700
+@@ -13,7 +13,20 @@ struct rt_sigframe {
+  * which Linux/parisc uses is sp-20 for the saved return pointer...)
+  * Then, the stack pointer must be rounded to a cache line (64 bytes).
+  */
++#define SIGFRAME32            64
++#define FUNCTIONCALLFRAME32   48
++#define PARISC_RT_SIGFRAME_SIZE32                                     \
++      (((sizeof(struct rt_sigframe) + FUNCTIONCALLFRAME32) + SIGFRAME32) & -SIGFRAME32)
++
++#ifdef __LP64__
++#define       SIGFRAME                128
++#define FUNCTIONCALLFRAME     96
+ #define PARISC_RT_SIGFRAME_SIZE                                       \
+-      (((sizeof(struct rt_sigframe) + 48) + 63) & -64)
++      (((sizeof(struct rt_sigframe) + FUNCTIONCALLFRAME) + SIGFRAME) & -SIGFRAME)
++#else
++#define       SIGFRAME                SIGFRAME32
++#define FUNCTIONCALLFRAME     FUNCTIONCALLFRAME32
++#define PARISC_RT_SIGFRAME_SIZE       PARISC_RT_SIGFRAME_SIZE32
++#endif
+ #endif
+--- linux-2.6.0-test6/include/asm-parisc/tlbflush.h    2003-06-14 12:18:51.000000000 -0700
++++ 25/include/asm-parisc/tlbflush.h   2003-10-05 00:33:24.000000000 -0700
+@@ -3,6 +3,7 @@
+ /* TLB flushing routines.... */
++#include <linux/config.h>
+ #include <linux/mm.h>
+ #include <asm/mmu_context.h>
+--- linux-2.6.0-test6/include/asm-ppc64/cacheflush.h   2003-06-14 12:17:57.000000000 -0700
++++ 25/include/asm-ppc64/cacheflush.h  2003-10-05 00:33:24.000000000 -0700
+@@ -14,12 +14,22 @@
+ #define flush_cache_range(vma, start, end)    do { } while (0)
+ #define flush_cache_page(vma, vmaddr)         do { } while (0)
+ #define flush_icache_page(vma, page)          do { } while (0)
++#define flush_cache_vmap(start, end)          do { } while (0)
++#define flush_cache_vunmap(start, end)                do { } while (0)
+ extern void flush_dcache_page(struct page *page);
+ extern void flush_icache_range(unsigned long, unsigned long);
+ extern void flush_icache_user_range(struct vm_area_struct *vma,
+                                   struct page *page, unsigned long addr,
+                                   int len);
++
++#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
++do { memcpy(dst, src, len); \
++     flush_icache_user_range(vma, page, vaddr, len); \
++} while (0)
++#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
++      memcpy(dst, src, len)
++
+ extern void __flush_dcache_icache(void *page_va);
+ #endif /* _PPC64_CACHEFLUSH_H */
+--- linux-2.6.0-test6/include/asm-ppc64/elf.h  2003-06-14 12:18:29.000000000 -0700
++++ 25/include/asm-ppc64/elf.h 2003-10-05 00:33:24.000000000 -0700
+@@ -128,11 +128,6 @@ static inline int dump_task_regs(struct 
+ extern int dump_task_fpu(struct task_struct *, elf_fpregset_t *); 
+ #define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs) dump_task_fpu(tsk, elf_fpregs)
+-#ifdef CONFIG_SMP
+-extern void dump_smp_unlazy_fpu(void);
+-#define ELF_CORE_SYNC dump_smp_unlazy_fpu
+-#endif
+-
+ #endif
+ /* This yields a mask that user programs can use to figure out what
+--- linux-2.6.0-test6/include/asm-ppc64/numnodes.h     2003-06-14 12:18:30.000000000 -0700
++++ 25/include/asm-ppc64/numnodes.h    2003-10-05 00:34:38.000000000 -0700
+@@ -1,6 +1,7 @@
+ #ifndef _ASM_MAX_NUMNODES_H
+ #define _ASM_MAX_NUMNODES_H
+-#define MAX_NUMNODES 16
++/* Max 16 Nodes */
++#define NODES_SHIFT   4
+ #endif /* _ASM_MAX_NUMNODES_H */
+--- linux-2.6.0-test6/include/asm-ppc64/pgtable.h      2003-09-27 18:57:47.000000000 -0700
++++ 25/include/asm-ppc64/pgtable.h     2003-10-05 00:33:24.000000000 -0700
+@@ -45,7 +45,6 @@
+  * Define the address range of the vmalloc VM area.
+  */
+ #define VMALLOC_START (0xD000000000000000)
+-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+ #define VMALLOC_END   (VMALLOC_START + VALID_EA_BITS)
+ /*
+--- linux-2.6.0-test6/include/asm-ppc64/semaphore.h    2003-09-27 18:57:47.000000000 -0700
++++ 25/include/asm-ppc64/semaphore.h   2003-10-05 00:34:19.000000000 -0700
+@@ -22,6 +22,7 @@ struct semaphore {
+        * sleeping on `wait'.
+        */
+       atomic_t count;
++      int sleepers;
+       wait_queue_head_t wait;
+ #ifdef WAITQUEUE_DEBUG
+       long __magic;
+@@ -37,6 +38,7 @@ struct semaphore {
+ #define __SEMAPHORE_INITIALIZER(name, count) \
+       { ATOMIC_INIT(count), \
++        0, \
+         __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
+         __SEM_DEBUG_INIT(name) }
+@@ -52,6 +54,7 @@ struct semaphore {
+ static inline void sema_init (struct semaphore *sem, int val)
+ {
+       atomic_set(&sem->count, val);
++      sem->sleepers = 0;
+       init_waitqueue_head(&sem->wait);
+ #ifdef WAITQUEUE_DEBUG
+       sem->__magic = (long)&sem->__magic;
+--- linux-2.6.0-test6/include/asm-ppc/cacheflush.h     2003-06-14 12:18:29.000000000 -0700
++++ 25/include/asm-ppc/cacheflush.h    2003-10-05 00:33:24.000000000 -0700
+@@ -24,12 +24,21 @@
+ #define flush_cache_range(vma, a, b)  do { } while (0)
+ #define flush_cache_page(vma, p)      do { } while (0)
+ #define flush_icache_page(vma, page)  do { } while (0)
++#define flush_cache_vmap(start, end)  do { } while (0)
++#define flush_cache_vunmap(start, end)        do { } while (0)
+ extern void flush_dcache_page(struct page *page);
+ extern void flush_icache_range(unsigned long, unsigned long);
+ extern void flush_icache_user_range(struct vm_area_struct *vma,
+               struct page *page, unsigned long addr, int len);
++#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
++do { memcpy(dst, src, len); \
++     flush_icache_user_range(vma, page, vaddr, len); \
++} while (0)
++#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
++      memcpy(dst, src, len)
++
+ extern void __flush_dcache_icache(void *page_va);
+ extern void __flush_dcache_icache_phys(unsigned long physaddr);
+--- linux-2.6.0-test6/include/asm-ppc/highmem.h        2003-09-27 18:57:47.000000000 -0700
++++ 25/include/asm-ppc/highmem.h       2003-10-05 00:33:24.000000000 -0700
+@@ -132,6 +132,8 @@ static inline struct page *kmap_atomic_t
+       return pte_page(kmap_pte[idx]);
+ }
++#define flush_cache_kmaps()   flush_cache_all()
++
+ #endif /* __KERNEL__ */
+ #endif /* _ASM_HIGHMEM_H */
+--- linux-2.6.0-test6/include/asm-ppc/pgtable.h        2003-09-27 18:57:47.000000000 -0700
++++ 25/include/asm-ppc/pgtable.h       2003-10-05 00:33:24.000000000 -0700
+@@ -129,7 +129,6 @@ extern unsigned long ioremap_bot, iorema
+ #else
+ #define VMALLOC_START ((((long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)))
+ #endif
+-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+ #define VMALLOC_END   ioremap_bot
+ /*
+--- linux-2.6.0-test6/include/asm-ppc/zorro.h  2003-06-14 12:18:30.000000000 -0700
++++ 25/include/asm-ppc/zorro.h 2003-10-05 00:33:24.000000000 -0700
+@@ -27,4 +27,4 @@ extern void *__ioremap(unsigned long add
+ #define z_ioremap ioremap
+ #define z_iounmap iounmap
+-#endif /* _ASM_ZORRO_H */
++#endif /* _ASM_PPC_ZORRO_H */
+--- linux-2.6.0-test6/include/asm-s390/cacheflush.h    2003-06-14 12:18:51.000000000 -0700
++++ 25/include/asm-s390/cacheflush.h   2003-10-05 00:33:24.000000000 -0700
+@@ -13,5 +13,12 @@
+ #define flush_icache_range(start, end)                do { } while (0)
+ #define flush_icache_page(vma,pg)             do { } while (0)
+ #define flush_icache_user_range(vma,pg,adr,len)       do { } while (0)
++#define flush_cache_vmap(start, end)          do { } while (0)
++#define flush_cache_vunmap(start, end)                do { } while (0)
++
++#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
++      memcpy(dst, src, len)
++#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
++      memcpy(dst, src, len)
+ #endif /* _S390_CACHEFLUSH_H */
+--- linux-2.6.0-test6/include/asm-s390/pgtable.h       2003-06-14 12:18:30.000000000 -0700
++++ 25/include/asm-s390/pgtable.h      2003-10-05 00:33:24.000000000 -0700
+@@ -117,7 +117,6 @@ extern char empty_zero_page[PAGE_SIZE];
+ #define VMALLOC_OFFSET  (8*1024*1024)
+ #define VMALLOC_START   (((unsigned long) high_memory + VMALLOC_OFFSET) \
+                        & ~(VMALLOC_OFFSET-1))
+-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+ #ifndef __s390x__
+ # define VMALLOC_END     (0x7fffffffL)
+ #else /* __s390x__ */
+--- linux-2.6.0-test6/include/asm-sh/cacheflush.h      2003-07-02 14:53:18.000000000 -0700
++++ 25/include/asm-sh/cacheflush.h     2003-10-05 00:33:24.000000000 -0700
+@@ -10,4 +10,14 @@ extern void __flush_purge_region(void *s
+ /* Flush (invalidate only) a region (smaller than a page) */
+ extern void __flush_invalidate_region(void *start, int size);
++#define flush_cache_vmap(start, end)          flush_cache_all()
++#define flush_cache_vunmap(start, end)                flush_cache_all()
++
++#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
++do { memcpy(dst, src, len); \
++     flush_icache_user_range(vma, page, vaddr, len); \
++} while (0)
++#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
++      memcpy(dst, src, len)
++
+ #endif /* __ASM_SH_CACHEFLUSH_H */
+--- linux-2.6.0-test6/include/asm-sh/mmzone.h  2003-07-02 14:53:18.000000000 -0700
++++ 25/include/asm-sh/mmzone.h 2003-10-05 00:34:40.000000000 -0700
+@@ -10,14 +10,14 @@
+ #include <linux/config.h>
++#ifdef CONFIG_DISCONTIGMEM
++
+ /* Currently, just for HP690 */
+ #define PHYSADDR_TO_NID(phys) ((((phys) - __MEMORY_START) >= 0x01000000)?1:0)
+-#define NR_NODES 2
+-extern pg_data_t discontig_page_data[NR_NODES];
+-extern bootmem_data_t discontig_node_bdata[NR_NODES];
++extern pg_data_t discontig_page_data[MAX_NUMNODES];
++extern bootmem_data_t discontig_node_bdata[MAX_NUMNODES];
+-#ifdef CONFIG_DISCONTIGMEM
+ /*
+  * Following are macros that each numa implmentation must define.
+  */
+@@ -46,7 +46,7 @@ static inline int is_valid_page(struct p
+ {
+       unsigned int i;
+-      for (i = 0; i < NR_NODES; i++) {
++      for (i = 0; i < MAX_NUMNODES; i++) {
+               if (page >= NODE_MEM_MAP(i) &&
+                   page < NODE_MEM_MAP(i) + NODE_DATA(i)->node_size)
+                       return 1;
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/include/asm-sh/numnodes.h       2003-10-05 00:34:40.000000000 -0700
+@@ -0,0 +1,7 @@
++#ifndef _ASM_MAX_NUMNODES_H
++#define _ASM_MAX_NUMNODES_H
++
++/* Max 2 Nodes */
++#define NODES_SHIFT   1
++
++#endif /* _ASM_MAX_NUMNODES_H */
+--- linux-2.6.0-test6/include/asm-sh/pgtable.h 2003-07-02 14:53:18.000000000 -0700
++++ 25/include/asm-sh/pgtable.h        2003-10-05 00:33:24.000000000 -0700
+@@ -51,7 +51,6 @@ extern unsigned long empty_zero_page[102
+  * Currently only 4-enty (16kB) is used (see arch/sh/mm/cache.c)
+  */
+ #define VMALLOC_START (P3SEG+0x00100000)
+-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+ #define VMALLOC_END   P4SEG
+ /*                    0x001     WT-bit on SH-4, 0 on SH-3 */
+--- linux-2.6.0-test6/include/asm-sparc64/cacheflush.h 2003-06-14 12:18:35.000000000 -0700
++++ 25/include/asm-sparc64/cacheflush.h        2003-10-05 00:33:24.000000000 -0700
+@@ -33,21 +33,17 @@ extern void flush_dcache_page_all(struct
+ extern void __flush_dcache_range(unsigned long start, unsigned long end);
+-extern void __flush_cache_all(void);
+-
+-#ifndef CONFIG_SMP
+-
+-#define flush_cache_all()     __flush_cache_all()
+-
+-#else /* CONFIG_SMP */
+-
+-extern void smp_flush_cache_all(void);
+-
+-#endif /* ! CONFIG_SMP */
+-
+ #define flush_icache_page(vma, pg)    do { } while(0)
+ #define flush_icache_user_range(vma,pg,adr,len)       do { } while (0)
++#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
++      memcpy(dst, src, len)
++#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
++      memcpy(dst, src, len)
++
+ extern void flush_dcache_page(struct page *page);
++#define flush_cache_vmap(start, end)          do { } while (0)
++#define flush_cache_vunmap(start, end)                do { } while (0)
++
+ #endif /* _SPARC64_CACHEFLUSH_H */
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/include/asm-sparc64/lockmeter.h 2003-10-05 00:36:40.000000000 -0700
+@@ -0,0 +1,45 @@
++/*
++ * Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com)
++ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
++ */
++
++#ifndef _SPARC64_LOCKMETER_H
++#define _SPARC64_LOCKMETER_H
++
++#include <linux/smp.h>
++#include <asm/spinlock.h>
++#include <asm/timer.h>
++#include <asm/timex.h>
++
++/* Actually, this is not the CPU frequency by the system tick
++ * frequency which is good enough for lock metering.
++ */
++#define CPU_CYCLE_FREQUENCY   (timer_tick_offset * HZ)
++#define THIS_CPU_NUMBER               smp_processor_id()
++
++#define PUT_INDEX(lock_ptr,indexv)    (lock_ptr)->index = (indexv)
++#define GET_INDEX(lock_ptr)           (lock_ptr)->index
++
++#define PUT_RWINDEX(rwlock_ptr,indexv) (rwlock_ptr)->index = (indexv)
++#define GET_RWINDEX(rwlock_ptr)        (rwlock_ptr)->index
++#define PUT_RW_CPU(rwlock_ptr,cpuv)    (rwlock_ptr)->cpu = (cpuv)
++#define GET_RW_CPU(rwlock_ptr)         (rwlock_ptr)->cpu
++
++#define RWLOCK_READERS(rwlock_ptr)    rwlock_readers(rwlock_ptr)
++
++extern inline int rwlock_readers(rwlock_t *rwlock_ptr)
++{
++      signed int tmp = rwlock_ptr->lock;
++
++      if (tmp > 0)
++              return tmp;
++      else
++              return 0;
++}
++
++#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr)    ((signed int)((rwlock_ptr)->lock) < 0)
++#define RWLOCK_IS_READ_LOCKED(rwlock_ptr)     ((signed int)((rwlock_ptr)->lock) > 0)
++
++#define get_cycles64()        get_cycles()
++
++#endif /* _SPARC64_LOCKMETER_H */
+--- linux-2.6.0-test6/include/asm-sparc64/pgtable.h    2003-06-14 12:17:56.000000000 -0700
++++ 25/include/asm-sparc64/pgtable.h   2003-10-05 00:33:24.000000000 -0700
+@@ -30,7 +30,6 @@
+ #define MODULES_LEN           0x000000007e000000
+ #define MODULES_END           0x0000000080000000
+ #define VMALLOC_START         0x0000000140000000
+-#define VMALLOC_VMADDR(x)     ((unsigned long)(x))
+ #define VMALLOC_END           0x0000000200000000
+ #define LOW_OBP_ADDRESS               0x00000000f0000000
+ #define HI_OBP_ADDRESS                0x0000000100000000
+--- linux-2.6.0-test6/include/asm-sparc64/spinlock.h   2003-06-26 22:07:26.000000000 -0700
++++ 25/include/asm-sparc64/spinlock.h  2003-10-05 00:36:40.000000000 -0700
+@@ -30,15 +30,23 @@
+ #ifndef CONFIG_DEBUG_SPINLOCK
+-typedef unsigned char spinlock_t;
+-#define SPIN_LOCK_UNLOCKED    0
++typedef struct {
++      unsigned char lock;
++      unsigned int  index;
++} spinlock_t;
+-#define spin_lock_init(lock)  (*((unsigned char *)(lock)) = 0)
+-#define spin_is_locked(lock)  (*((volatile unsigned char *)(lock)) != 0)
++#ifdef CONFIG_LOCKMETER
++#define SPIN_LOCK_UNLOCKED    (spinlock_t) {0, 0}
++#else
++#define SPIN_LOCK_UNLOCKED    (spinlock_t) { 0 }
++#endif
+-#define spin_unlock_wait(lock)        \
++#define spin_lock_init(__lock)        do { *(__lock) = SPIN_LOCK_UNLOCKED; } while(0)
++#define spin_is_locked(__lock)        (*((volatile unsigned char *)(&((__lock)->lock))) != 0)
++
++#define spin_unlock_wait(__lock)      \
+ do {  membar("#LoadLoad");    \
+-} while(*((volatile unsigned char *)lock))
++} while(*((volatile unsigned char *)(&(((spinlock_t *)__lock)->lock))))
+ static __inline__ void _raw_spin_lock(spinlock_t *lock)
+ {
+@@ -109,18 +117,34 @@ extern int _spin_trylock (spinlock_t *lo
+ #ifndef CONFIG_DEBUG_SPINLOCK
+-typedef unsigned int rwlock_t;
+-#define RW_LOCK_UNLOCKED      0
+-#define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while(0)
+-#define rwlock_is_locked(x) (*(x) != RW_LOCK_UNLOCKED)
++#ifdef CONFIG_LOCKMETER
++typedef struct {
++      unsigned int lock;
++      unsigned int index;
++      unsigned int cpu;
++} rwlock_t;
++#define RW_LOCK_UNLOCKED       (rwlock_t) { 0, 0, 0xff }
++#else
++typedef struct {
++      unsigned int lock;
++} rwlock_t;
++#define RW_LOCK_UNLOCKED        (rwlock_t) { 0 }
++#endif
++
++#define rwlock_init(lp)               do { *(lp) = RW_LOCK_UNLOCKED; } while(0)
++#define rwlock_is_locked(x)   ((x)->lock != 0)
++extern int __read_trylock(rwlock_t *);
+ extern void __read_lock(rwlock_t *);
+ extern void __read_unlock(rwlock_t *);
++extern int __write_trylock(rwlock_t *);
+ extern void __write_lock(rwlock_t *);
+ extern void __write_unlock(rwlock_t *);
++#define _raw_read_trylock(p)  __read_trylock(p)
+ #define _raw_read_lock(p)     __read_lock(p)
+ #define _raw_read_unlock(p)   __read_unlock(p)
++#define _raw_write_trylock(p) __write_trylock(p)
+ #define _raw_write_lock(p)    __write_lock(p)
+ #define _raw_write_unlock(p)  __write_unlock(p)
+--- linux-2.6.0-test6/include/asm-sparc64/tlbflush.h   2003-06-14 12:18:29.000000000 -0700
++++ 25/include/asm-sparc64/tlbflush.h  2003-10-05 00:33:24.000000000 -0700
+@@ -70,7 +70,6 @@ extern void smp_flush_tlb_range(struct m
+ extern void smp_flush_tlb_kernel_range(unsigned long start, unsigned long end);
+ extern void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page);
+-#define flush_cache_all()     smp_flush_cache_all()
+ #define flush_tlb_all()               smp_flush_tlb_all()
+ #define flush_tlb_mm(mm)      smp_flush_tlb_mm(mm)
+ #define flush_tlb_range(vma, start, end) \
+--- linux-2.6.0-test6/include/asm-sparc64/unistd.h     2003-09-08 13:58:59.000000000 -0700
++++ 25/include/asm-sparc64/unistd.h    2003-10-05 00:33:24.000000000 -0700
+@@ -285,7 +285,8 @@
+ #define __NR_timer_getoverrun 264
+ #define __NR_timer_delete     265
+ #define __NR_timer_create     266
+-/* WARNING: You MAY NOT add syscall numbers larger than 266, since
++/* #define __NR_vserver               267 Reserved for VSERVER */
++/* WARNING: You MAY NOT add syscall numbers larger than 267, since
+  *          all of the syscall tables in the Sparc kernel are
+  *          sized to have 267 entries (starting at zero).  Therefore
+  *          find a free slot in the 0-266 range.
+--- linux-2.6.0-test6/include/asm-sparc64/visasm.h     2003-06-14 12:17:58.000000000 -0700
++++ 25/include/asm-sparc64/visasm.h    2003-10-05 00:33:24.000000000 -0700
+@@ -17,7 +17,8 @@
+       andcc           %o5, (FPRS_FEF|FPRS_DU), %g0;   \
+       be,pt           %icc, 297f;                     \
+        sethi          %hi(297f), %g7;                 \
+-      ba,pt           %xcc, VISenter;                 \
++      sethi           %hi(VISenter), %g1;             \
++      jmpl            %g1 + %lo(VISenter), %g0;       \
+        or             %g7, %lo(297f), %g7;            \
+ 297:  wr              %g0, FPRS_FEF, %fprs;           \
+@@ -32,7 +33,8 @@
+       andcc           %o5, FPRS_FEF, %g0;             \
+       be,pt           %icc, 297f;                     \
+        sethi          %hi(298f), %g7;                 \
+-      ba,pt           %xcc, VISenterhalf;             \
++      sethi           %hi(VISenterhalf), %g1;         \
++      jmpl            %g1 + %lo(VISenterhalf), %g0;   \
+        or             %g7, %lo(298f), %g7;            \
+       clr             %o5;                            \
+ 297:  wr              %o5, FPRS_FEF, %fprs;           \
+@@ -48,7 +50,8 @@ static __inline__ void save_and_clear_fp
+ "             andcc %%o5, %0, %%g0\n"
+ "             be,pt %%icc, 299f\n"
+ "              sethi %%hi(298f), %%g7\n"
+-"             ba VISenter     ! Note. This cannot be bp, as it may be too far from VISenter.\n"
++"             sethi %%hi(VISenter), %%g1\n"
++"             jmpl %%g1 + %%lo(VISenter), %%g0\n"
+ "              or %%g7, %%lo(298f), %%g7\n"
+ "     298:    wr %%g0, 0, %%fprs\n"
+ "     299:\n"
+--- linux-2.6.0-test6/include/asm-sparc/cacheflush.h   2003-06-14 12:18:06.000000000 -0700
++++ 25/include/asm-sparc/cacheflush.h  2003-10-05 00:33:24.000000000 -0700
+@@ -56,6 +56,11 @@ BTFIXUPDEF_CALL(void, flush_cache_page, 
+ #define flush_icache_user_range(vma,pg,adr,len)       do { } while (0)
++#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
++      memcpy(dst, src, len)
++#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
++      memcpy(dst, src, len)
++
+ BTFIXUPDEF_CALL(void, __flush_page_to_ram, unsigned long)
+ BTFIXUPDEF_CALL(void, flush_sig_insns, struct mm_struct *, unsigned long)
+@@ -66,4 +71,7 @@ extern void sparc_flush_page_to_ram(stru
+ #define flush_dcache_page(page)                       sparc_flush_page_to_ram(page)
++#define flush_cache_vmap(start, end)          flush_cache_all()
++#define flush_cache_vunmap(start, end)                flush_cache_all()
++
+ #endif /* _SPARC_CACHEFLUSH_H */
+--- linux-2.6.0-test6/include/asm-sparc/highmem.h      2003-06-14 12:18:51.000000000 -0700
++++ 25/include/asm-sparc/highmem.h     2003-10-05 00:33:24.000000000 -0700
+@@ -89,6 +89,8 @@ static inline struct page *kmap_atomic_t
+       return pte_page(*pte);
+ }
++#define flush_cache_kmaps()   flush_cache_all()
++
+ #endif /* __KERNEL__ */
+ #endif /* _ASM_HIGHMEM_H */
+--- linux-2.6.0-test6/include/asm-sparc/pgtable.h      2003-06-14 12:18:22.000000000 -0700
++++ 25/include/asm-sparc/pgtable.h     2003-10-05 00:33:24.000000000 -0700
+@@ -101,8 +101,6 @@ BTFIXUPDEF_SIMM13(ptrs_per_pmd)
+ BTFIXUPDEF_SIMM13(ptrs_per_pgd)
+ BTFIXUPDEF_SIMM13(user_ptrs_per_pgd)
+-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+-
+ #define pte_ERROR(e)   __builtin_trap()
+ #define pmd_ERROR(e)   __builtin_trap()
+ #define pgd_ERROR(e)   __builtin_trap()
+--- linux-2.6.0-test6/include/asm-sparc/unistd.h       2003-09-08 13:58:59.000000000 -0700
++++ 25/include/asm-sparc/unistd.h      2003-10-05 00:33:24.000000000 -0700
+@@ -283,7 +283,8 @@
+ #define __NR_timer_getoverrun 264
+ #define __NR_timer_delete     265
+ #define __NR_timer_create     266
+-/* WARNING: You MAY NOT add syscall numbers larger than 266, since
++/* #define __NR_vserver               267 Reserved for VSERVER */
++/* WARNING: You MAY NOT add syscall numbers larger than 267, since
+  *          all of the syscall tables in the Sparc kernel are
+  *          sized to have 267 entries (starting at zero).  Therefore
+  *          find a free slot in the 0-266 range.
+--- linux-2.6.0-test6/include/asm-um/archparam-i386.h  2003-06-14 12:18:30.000000000 -0700
++++ 25/include/asm-um/archparam-i386.h 2003-10-05 00:34:32.000000000 -0700
+@@ -56,6 +56,65 @@ typedef elf_greg_t elf_gregset_t[ELF_NGR
+       pr_reg[16] = PT_REGS_SS(regs);          \
+ } while(0);
++#define VSYSCALL_BASE (__fix_to_virt(FIX_VSYSCALL))
++#define VSYSCALL_EHDR ((const struct elfhdr *) VSYSCALL_BASE)
++#define VSYSCALL_ENTRY        ((unsigned long) &__kernel_vsyscall)
++extern void *__kernel_vsyscall;
++
++/*
++ * Architecture-neutral AT_ values in 0-17, leave some room
++ * for more of them, start the x86-specific ones at 32.
++ */
++#define AT_SYSINFO            32
++#define AT_SYSINFO_EHDR               33
++
++#define ARCH_DLINFO                                           \
++do {                                                          \
++              NEW_AUX_ENT(AT_SYSINFO, VSYSCALL_ENTRY);        \
++              NEW_AUX_ENT(AT_SYSINFO_EHDR, VSYSCALL_BASE);    \
++} while (0)
++
++/*
++ * These macros parameterize elf_core_dump in fs/binfmt_elf.c to write out
++ * extra segments containing the vsyscall DSO contents.  Dumping its
++ * contents makes post-mortem fully interpretable later without matching up
++ * the same kernel and hardware config to see what PC values meant.
++ * Dumping its extra ELF program headers includes all the other information
++ * a debugger needs to easily find how the vsyscall DSO was being used.
++ */
++#define ELF_CORE_EXTRA_PHDRS          (VSYSCALL_EHDR->e_phnum)
++#define ELF_CORE_WRITE_EXTRA_PHDRS                                          \
++do {                                                                        \
++      const struct elf_phdr *const vsyscall_phdrs =                         \
++              (const struct elf_phdr *) (VSYSCALL_BASE                      \
++                                         + VSYSCALL_EHDR->e_phoff);         \
++      int i;                                                                \
++      Elf32_Off ofs = 0;                                                    \
++      for (i = 0; i < VSYSCALL_EHDR->e_phnum; ++i) {                        \
++              struct elf_phdr phdr = vsyscall_phdrs[i];                     \
++              if (phdr.p_type == PT_LOAD) {                                 \
++                      ofs = phdr.p_offset = offset;                         \
++                      offset += phdr.p_filesz;                              \
++              }                                                             \
++              else                                                          \
++                      phdr.p_offset += ofs;                                 \
++              phdr.p_paddr = 0; /* match other core phdrs */                \
++              DUMP_WRITE(&phdr, sizeof(phdr));                              \
++      }                                                                     \
++} while (0)
++#define ELF_CORE_WRITE_EXTRA_DATA                                           \
++do {                                                                        \
++      const struct elf_phdr *const vsyscall_phdrs =                         \
++              (const struct elf_phdr *) (VSYSCALL_BASE                      \
++                                         + VSYSCALL_EHDR->e_phoff);         \
++      int i;                                                                \
++      for (i = 0; i < VSYSCALL_EHDR->e_phnum; ++i) {                        \
++              if (vsyscall_phdrs[i].p_type == PT_LOAD)                      \
++                      DUMP_WRITE((void *) vsyscall_phdrs[i].p_vaddr,        \
++                                 vsyscall_phdrs[i].p_filesz);               \
++      }                                                                     \
++} while (0)
++
+ /********* Bits for asm-um/delay.h **********/
+ typedef unsigned long um_udelay_t;
+--- linux-2.6.0-test6/include/asm-um/common.lds.S      2003-06-14 12:18:00.000000000 -0700
++++ 25/include/asm-um/common.lds.S     2003-10-05 00:34:32.000000000 -0700
+@@ -1,3 +1,5 @@
++#include <asm-generic/vmlinux.lds.h>
++
+   .fini      : { *(.fini)    } =0x9090
+   _etext = .;
+   PROVIDE (etext = .);
+@@ -67,6 +69,10 @@
+   }
+   __initcall_end = .;
++  __con_initcall_start = .;
++  .con_initcall.init : { *(.con_initcall.init) }
++  __con_initcall_end = .;
++
+   __uml_initcall_start = .;
+   .uml.initcall.init : { *(.uml.initcall.init) }
+   __uml_initcall_end = .;
+@@ -80,7 +86,33 @@
+   .uml.exitcall : { *(.uml.exitcall.exit) }
+   __uml_exitcall_end = .;
+-  . = ALIGN(4096);
++  . = ALIGN(4);
++  __alt_instructions = .;
++  .altinstructions : { *(.altinstructions) } 
++  __alt_instructions_end = .; 
++  .altinstr_replacement : { *(.altinstr_replacement) } 
++  /* .exit.text is discard at runtime, not link time, to deal with references
++     from .altinstructions and .eh_frame */
++  .exit.text : { *(.exit.text) }
++  .exit.data : { *(.exit.data) }
++ 
++  __preinit_array_start = .;
++  .preinit_array : { *(.preinit_array) }
++  __preinit_array_end = .;
++  __init_array_start = .;
++  .init_array : { *(.init_array) }
++  __init_array_end = .;
++  __fini_array_start = .;
++  .fini_array : { *(.fini_array) }
++  __fini_array_end = .;
++
++   . = ALIGN(4096);
+   __initramfs_start = .;
+   .init.ramfs : { *(.init.ramfs) }
+   __initramfs_end = .;
++
++  /* Sections to be discarded */
++  /DISCARD/ : {
++      *(.exitcall.exit)
++  }
++ 
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/include/asm-um/cpufeature.h     2003-10-05 00:34:32.000000000 -0700
+@@ -0,0 +1,6 @@
++#ifndef __UM_CPUFEATURE_H
++#define __UM_CPUFEATURE_H
++
++#include "asm/arch/cpufeature.h"
++
++#endif
+--- linux-2.6.0-test6/include/asm-um/current.h 2003-06-14 12:17:57.000000000 -0700
++++ 25/include/asm-um/current.h        2003-10-05 00:34:32.000000000 -0700
+@@ -16,8 +16,10 @@ struct thread_info;
+ #define CURRENT_THREAD(dummy) (((unsigned long) &dummy) & \
+                               (PAGE_MASK << CONFIG_KERNEL_STACK_ORDER))
+-#define current ({ int dummy; \
+-                   ((struct thread_info *) CURRENT_THREAD(dummy))->task; })
++#define current_thread \
++      ({ int dummy; ((struct thread_info *) CURRENT_THREAD(dummy)); })
++
++#define current (current_thread->task)
+ #endif /* __ASSEMBLY__ */
+--- linux-2.6.0-test6/include/asm-um/fixmap.h  2003-06-14 12:18:33.000000000 -0700
++++ 25/include/asm-um/fixmap.h 2003-10-05 00:34:32.000000000 -0700
+@@ -34,6 +34,7 @@ enum fixed_addresses {
+       FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
+       FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
+ #endif
++      FIX_VSYSCALL,
+       __end_of_fixed_addresses
+ };
+@@ -63,6 +64,13 @@ extern unsigned long get_kmem_end(void);
+ #define __fix_to_virt(x)      (FIXADDR_TOP - ((x) << PAGE_SHIFT))
+ #define __virt_to_fix(x)      ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT)
++/*
++ * This is the range that is readable by user mode, and things
++ * acting like user mode such as get_user_pages.
++ */
++#define FIXADDR_USER_START    (__fix_to_virt(FIX_VSYSCALL))
++#define FIXADDR_USER_END      (FIXADDR_USER_START + PAGE_SIZE)
++
+ extern void __this_fixmap_does_not_exist(void);
+ /*
+--- linux-2.6.0-test6/include/asm-um/irq.h     2003-06-14 12:18:49.000000000 -0700
++++ 25/include/asm-um/irq.h    2003-10-05 00:34:32.000000000 -0700
+@@ -1,15 +1,6 @@
+ #ifndef __UM_IRQ_H
+ #define __UM_IRQ_H
+-/* The i386 irq.h has a struct task_struct in a prototype without including
+- * sched.h.  This forward declaration kills the resulting warning.
+- */
+-struct task_struct;
+-
+-#include "asm/ptrace.h"
+-
+-#undef NR_IRQS
+-
+ #define TIMER_IRQ             0
+ #define UMN_IRQ                       1
+ #define CONSOLE_IRQ           2
+@@ -28,8 +19,4 @@ struct task_struct;
+ #define LAST_IRQ XTERM_IRQ
+ #define NR_IRQS (LAST_IRQ + 1)
+-extern int um_request_irq(unsigned int irq, int fd, int type,
+-                        void (*handler)(int, void *, struct pt_regs *),
+-                        unsigned long irqflags,  const char * devname,
+-                        void *dev_id);
+ #endif
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/include/asm-um/local.h  2003-10-05 00:34:32.000000000 -0700
+@@ -0,0 +1,6 @@
++#ifndef __UM_LOCAL_H
++#define __UM_LOCAL_H
++
++#include "asm/arch/local.h"
++
++#endif
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/include/asm-um/module-generic.h 2003-10-05 00:34:32.000000000 -0700
+@@ -0,0 +1,6 @@
++#ifndef __UM_MODULE_GENERIC_H
++#define __UM_MODULE_GENERIC_H
++
++#include "asm/arch/module.h"
++
++#endif
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/include/asm-um/module-i386.h    2003-10-05 00:34:32.000000000 -0700
+@@ -0,0 +1,13 @@
++#ifndef __UM_MODULE_I386_H
++#define __UM_MODULE_I386_H
++
++/* UML is simple */
++struct mod_arch_specific
++{
++};
++
++#define Elf_Shdr Elf32_Shdr
++#define Elf_Sym Elf32_Sym
++#define Elf_Ehdr Elf32_Ehdr
++
++#endif
+--- linux-2.6.0-test6/include/asm-um/page.h    2003-06-14 12:18:23.000000000 -0700
++++ 25/include/asm-um/page.h   2003-10-05 00:34:32.000000000 -0700
+@@ -4,7 +4,6 @@
+ struct page;
+ #include "asm/arch/page.h"
+-#include "asm/bug.h"
+ #undef __pa
+ #undef __va
+--- linux-2.6.0-test6/include/asm-um/pgtable.h 2003-06-14 12:18:52.000000000 -0700
++++ 25/include/asm-um/pgtable.h        2003-10-05 00:34:32.000000000 -0700
+@@ -69,7 +69,6 @@ extern unsigned long high_physmem;
+ #define VMALLOC_OFFSET        (__va_space)
+ #define VMALLOC_START (((unsigned long) high_physmem + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+ #ifdef CONFIG_HIGHMEM
+ # define VMALLOC_END  (PKMAP_BASE-2*PAGE_SIZE)
+@@ -79,12 +78,13 @@ extern unsigned long high_physmem;
+ #define _PAGE_PRESENT 0x001
+ #define _PAGE_NEWPAGE 0x002
+-#define _PAGE_PROTNONE        0x004   /* If not present */
+-#define _PAGE_RW      0x008
+-#define _PAGE_USER    0x010
+-#define _PAGE_ACCESSED        0x020
+-#define _PAGE_DIRTY   0x040
+-#define _PAGE_NEWPROT   0x080
++#define _PAGE_NEWPROT   0x004
++#define _PAGE_FILE    0x008   /* set:pagecache unset:swap */
++#define _PAGE_PROTNONE        0x010   /* If not present */
++#define _PAGE_RW      0x020
++#define _PAGE_USER    0x040
++#define _PAGE_ACCESSED        0x080
++#define _PAGE_DIRTY   0x100
+ #define REGION_MASK   0xf0000000
+ #define REGION_SHIFT  28
+@@ -203,6 +203,16 @@ extern unsigned long pfn_to_phys(unsigne
+ #define pfn_pte(pfn, prot) __pte(pfn_to_phys(pfn) | pgprot_val(prot))
+ #define pfn_pmd(pfn, prot) __pmd(pfn_to_phys(pfn) | pgprot_val(prot))
++/*
++ * Bits 0 through 3 are taken
++ */
++#define PTE_FILE_MAX_BITS     28
++
++#define pte_to_pgoff(pte) ((pte).pte_low >> 4)
++
++#define pgoff_to_pte(off) \
++      ((pte_t) { ((off) << 4) + _PAGE_FILE })
++
+ static inline pte_t pte_mknewprot(pte_t pte)
+ {
+       pte_val(pte) |= _PAGE_NEWPROT;
+@@ -236,6 +246,12 @@ static inline void set_pte(pte_t *pteptr
+  * The following only work if pte_present() is true.
+  * Undefined behaviour if not..
+  */
++static inline int pte_user(pte_t pte)
++{ 
++      return((pte_val(pte) & _PAGE_USER) && 
++             !(pte_val(pte) & _PAGE_PROTNONE));
++}
++
+ static inline int pte_read(pte_t pte)
+ { 
+       return((pte_val(pte) & _PAGE_USER) && 
+@@ -253,6 +269,14 @@ static inline int pte_write(pte_t pte)
+              !(pte_val(pte) & _PAGE_PROTNONE));
+ }
++/*
++ * The following only works if pte_present() is not true.
++ */
++static inline int pte_file(pte_t pte)
++{ 
++      return (pte).pte_low & _PAGE_FILE; 
++}
++
+ static inline int pte_dirty(pte_t pte)        { return pte_val(pte) & _PAGE_DIRTY; }
+ static inline int pte_young(pte_t pte)        { return pte_val(pte) & _PAGE_ACCESSED; }
+ static inline int pte_newpage(pte_t pte) { return pte_val(pte) & _PAGE_NEWPAGE; }
+@@ -355,14 +379,26 @@ static inline pte_t pte_modify(pte_t pte
+ #define pmd_page(pmd) (phys_mem_map(pmd_val(pmd) & PAGE_MASK) + \
+                      ((phys_addr(pmd_val(pmd)) >> PAGE_SHIFT)))
+-/* to find an entry in a page-table-directory. */
++/*
++ * the pgd page can be thought of an array like this: pgd_t[PTRS_PER_PGD]
++ *
++ * this macro returns the index of the entry in the pgd page which would
++ * control the given virtual address
++ */
+ #define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
+-/* to find an entry in a page-table-directory */
++/*
++ * pgd_offset() returns a (pgd_t *)
++ * pgd_index() is used get the offset into the pgd page's array of pgd_t's;
++ */
+ #define pgd_offset(mm, address) \
+ ((mm)->pgd + ((address) >> PGDIR_SHIFT))
+-/* to find an entry in a kernel page-table-directory */
++
++/*
++ * a shortcut which implies the use of the kernel's pgd, instead
++ * of a process's
++ */
+ #define pgd_offset_k(address) pgd_offset(&init_mm, address)
+ #define pmd_index(address) \
+@@ -374,7 +410,12 @@ static inline pmd_t * pmd_offset(pgd_t *
+       return (pmd_t *) dir;
+ }
+-/* Find an entry in the third-level page table.. */ 
++/*
++ * the pte page can be thought of an array like this: pte_t[PTRS_PER_PTE]
++ *
++ * this macro returns the index of the entry in the pte page which would
++ * control the given virtual address
++ */
+ #define pte_index(address) (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+ #define pte_offset_kernel(dir, address) \
+       ((pte_t *) pmd_page_kernel(*(dir)) +  pte_index(address))
+@@ -400,11 +441,11 @@ typedef pte_t *pte_addr_t;
+ #define update_mmu_cache(vma,address,pte) do ; while (0)
+ /* Encode and de-code a swap entry */
+-#define __swp_type(x)                 (((x).val >> 3) & 0x7f)
+-#define __swp_offset(x)                       ((x).val >> 10)
++#define __swp_type(x)                 (((x).val >> 4) & 0x3f)
++#define __swp_offset(x)                       ((x).val >> 11)
+ #define __swp_entry(type, offset) \
+-      ((swp_entry_t) { ((type) << 3) | ((offset) << 10) })
++      ((swp_entry_t) { ((type) << 4) | ((offset) << 11) })
+ #define __pte_to_swp_entry(pte) \
+       ((swp_entry_t) { pte_val(pte_mkuptodate(pte)) })
+ #define __swp_entry_to_pte(x)         ((pte_t) { (x).val })
+--- linux-2.6.0-test6/include/asm-um/processor-generic.h       2003-06-14 12:17:59.000000000 -0700
++++ 25/include/asm-um/processor-generic.h      2003-10-05 00:34:32.000000000 -0700
+@@ -11,9 +11,7 @@ struct pt_regs;
+ struct task_struct;
+ #include "linux/config.h"
+-#include "linux/signal.h"
+ #include "asm/ptrace.h"
+-#include "asm/siginfo.h"
+ #include "choose-mode.h"
+ struct mm_struct;
+@@ -101,14 +99,19 @@ typedef struct {
+ } mm_segment_t;
+ extern struct task_struct *alloc_task_struct(void);
+-extern void free_task_struct(struct task_struct *task);
+ extern void release_thread(struct task_struct *);
+ extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
+ extern void dump_thread(struct pt_regs *regs, struct user *u);
++extern void prepare_to_copy(struct task_struct *tsk);
+ extern unsigned long thread_saved_pc(struct task_struct *t);
++static inline void mm_copy_segments(struct mm_struct *from_mm, 
++                                  struct mm_struct *new_mm)
++{
++}
++
+ #define init_stack    (init_thread_union.stack)
+ /*
+--- linux-2.6.0-test6/include/asm-um/processor-i386.h  2003-06-14 12:17:57.000000000 -0700
++++ 25/include/asm-um/processor-i386.h 2003-10-05 00:34:32.000000000 -0700
+@@ -6,8 +6,8 @@
+ #ifndef __UM_PROCESSOR_I386_H
+ #define __UM_PROCESSOR_I386_H
+-extern int cpu_has_xmm;
+-extern int cpu_has_cmov;
++extern int host_has_xmm;
++extern int host_has_cmov;
+ struct arch_thread {
+       unsigned long debugregs[8];
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/include/asm-um/sections.h       2003-10-05 00:34:32.000000000 -0700
+@@ -0,0 +1,7 @@
++#ifndef _UM_SECTIONS_H
++#define _UM_SECTIONS_H
++
++/* nothing to see, move along */
++#include <asm-generic/sections.h>
++
++#endif
+--- linux-2.6.0-test6/include/asm-um/smp.h     2003-08-22 19:23:42.000000000 -0700
++++ 25/include/asm-um/smp.h    2003-10-05 00:34:32.000000000 -0700
+@@ -10,7 +10,7 @@
+ extern cpumask_t cpu_online_map;
+-#define smp_processor_id() (current->thread_info->cpu)
++#define smp_processor_id() (current_thread->cpu)
+ #define cpu_logical_map(n) (n)
+ #define cpu_number_map(n) (n)
+ #define PROC_CHANGE_PENALTY   15 /* Pick a number, any number */
+--- linux-2.6.0-test6/include/asm-um/system-generic.h  2003-06-14 12:18:51.000000000 -0700
++++ 25/include/asm-um/system-generic.h 2003-10-05 00:34:32.000000000 -0700
+@@ -23,8 +23,10 @@ extern int get_signals(void);
+ extern void block_signals(void);
+ extern void unblock_signals(void);
+-#define local_save_flags(flags) do { (flags) = get_signals(); } while(0)
+-#define local_irq_restore(flags) do { set_signals(flags); } while(0)
++#define local_save_flags(flags) do { typecheck(unsigned long, flags); \
++                                   (flags) = get_signals(); } while(0)
++#define local_irq_restore(flags) do { typecheck(unsigned long, flags); \
++                                    set_signals(flags); } while(0)
+ #define local_irq_save(flags) do { local_save_flags(flags); \
+                                    local_irq_disable(); } while(0)
+@@ -39,4 +41,7 @@ extern void unblock_signals(void);
+         (flags == 0);                   \
+ })
++extern void *_switch_to(void *prev, void *next, void *last);
++#define switch_to(prev, next, last) prev = _switch_to(prev, next, last)
++
+ #endif
+--- linux-2.6.0-test6/include/asm-um/thread_info.h     2003-06-14 12:18:06.000000000 -0700
++++ 25/include/asm-um/thread_info.h    2003-10-05 00:34:32.000000000 -0700
+@@ -9,6 +9,7 @@
+ #ifndef __ASSEMBLY__
+ #include <asm/processor.h>
++#include <asm/types.h>
+ struct thread_info {
+       struct task_struct      *task;          /* main task structure */
+@@ -43,15 +44,18 @@ struct thread_info {
+ static inline struct thread_info *current_thread_info(void)
+ {
+       struct thread_info *ti;
+-      __asm__("andl %%esp,%0; ":"=r" (ti) : "0" (~16383UL));
++      unsigned long mask = PAGE_SIZE * 
++              (1 << CONFIG_KERNEL_STACK_ORDER) - 1;
++      __asm__("andl %%esp,%0; ":"=r" (ti) : "0" (~mask));
+       return ti;
+ }
+ /* thread information allocation */
+-#define THREAD_SIZE (4*PAGE_SIZE)
+-#define alloc_thread_info(tsk) ((struct thread_info *) \
+-      __get_free_pages(GFP_KERNEL,2))
+-#define free_thread_info(ti) free_pages((unsigned long) (ti), 2)
++#define THREAD_SIZE ((1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE)
++#define alloc_thread_info(tsk) \
++      ((struct thread_info *) kmalloc(THREAD_SIZE, GFP_KERNEL))
++#define free_thread_info(ti) kfree(ti)
++      
+ #define get_thread_info(ti) get_task_struct((ti)->task)
+ #define put_thread_info(ti) put_task_struct((ti)->task)
+@@ -65,11 +69,13 @@ static inline struct thread_info *curren
+ #define TIF_POLLING_NRFLAG      3       /* true if poll_idle() is polling 
+                                        * TIF_NEED_RESCHED 
+                                        */
++#define TIF_RESTART_BLOCK     4
+ #define _TIF_SYSCALL_TRACE    (1 << TIF_SYSCALL_TRACE)
+ #define _TIF_SIGPENDING               (1 << TIF_SIGPENDING)
+ #define _TIF_NEED_RESCHED     (1 << TIF_NEED_RESCHED)
+ #define _TIF_POLLING_NRFLAG     (1 << TIF_POLLING_NRFLAG)
++#define _TIF_RESTART_BLOCK    (1 << TIF_RESTART_BLOCK)
+ #endif
+--- linux-2.6.0-test6/include/asm-um/timex.h   2003-06-14 12:18:24.000000000 -0700
++++ 25/include/asm-um/timex.h  2003-10-05 00:34:32.000000000 -0700
+@@ -1,8 +1,6 @@
+ #ifndef __UM_TIMEX_H
+ #define __UM_TIMEX_H
+-#include "linux/time.h"
+-
+ typedef unsigned long cycles_t;
+ #define cacheflush_time (0)
+--- linux-2.6.0-test6/include/asm-v850/cacheflush.h    2003-07-27 12:14:40.000000000 -0700
++++ 25/include/asm-v850/cacheflush.h   2003-10-05 00:33:24.000000000 -0700
+@@ -27,6 +27,8 @@
+ #define flush_cache_range(vma, start, end)    ((void)0)
+ #define flush_cache_page(vma, vmaddr)         ((void)0)
+ #define flush_dcache_page(page)                       ((void)0)
++#define flush_cache_vmap(start, end)          ((void)0)
++#define flush_cache_vunmap(start, end)                ((void)0)
+ #ifdef CONFIG_NO_CACHE
+@@ -55,5 +57,11 @@ extern void flush_cache_sigtramp (unsign
+ #endif /* CONFIG_NO_CACHE */
++#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
++do { memcpy(dst, src, len); \
++     flush_icache_user_range(vma, page, vaddr, len); \
++} while (0)
++#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
++      memcpy(dst, src, len)
+ #endif /* __V850_CACHEFLUSH_H__ */
+--- linux-2.6.0-test6/include/asm-x86_64/cacheflush.h  2003-06-14 12:17:59.000000000 -0700
++++ 25/include/asm-x86_64/cacheflush.h 2003-10-05 00:33:24.000000000 -0700
+@@ -13,6 +13,13 @@
+ #define flush_icache_range(start, end)                do { } while (0)
+ #define flush_icache_page(vma,pg)             do { } while (0)
+ #define flush_icache_user_range(vma,pg,adr,len)       do { } while (0)
++#define flush_cache_vmap(start, end)          do { } while (0)
++#define flush_cache_vunmap(start, end)                do { } while (0)
++
++#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
++      memcpy(dst, src, len)
++#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
++      memcpy(dst, src, len)
+ void global_flush_tlb(void); 
+ int change_page_attr(struct page *page, int numpages, pgprot_t prot);
+--- linux-2.6.0-test6/include/asm-x86_64/elf.h 2003-06-14 12:18:30.000000000 -0700
++++ 25/include/asm-x86_64/elf.h        2003-10-05 00:33:24.000000000 -0700
+@@ -150,11 +150,6 @@ extern int dump_task_fpu (struct task_st
+ #define ELF_CORE_COPY_TASK_REGS(tsk, elf_regs) dump_task_regs(tsk, elf_regs)
+ #define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs) dump_task_fpu(tsk, elf_fpregs)
+-#ifdef CONFIG_SMP
+-extern void dump_smp_unlazy_fpu(void);
+-#define ELF_CORE_SYNC dump_smp_unlazy_fpu
+-#endif
+-
+ #endif
+ #endif
+--- linux-2.6.0-test6/include/asm-x86_64/mmzone.h      2003-07-10 18:50:32.000000000 -0700
++++ 25/include/asm-x86_64/mmzone.h     2003-10-05 00:34:38.000000000 -0700
+@@ -10,7 +10,6 @@
+ #define VIRTUAL_BUG_ON(x) 
+-#include <asm/numnodes.h>
+ #include <asm/smp.h>
+ #define MAXNODE 8 
+--- linux-2.6.0-test6/include/asm-x86_64/numnodes.h    2003-06-14 12:18:08.000000000 -0700
++++ 25/include/asm-x86_64/numnodes.h   2003-10-05 00:34:38.000000000 -0700
+@@ -3,10 +3,7 @@
+ #include <linux/config.h>
+-#ifdef CONFIG_DISCONTIGMEM
+-#define MAX_NUMNODES 8        /* APIC limit currently */
+-#else
+-#define MAX_NUMNODES 1
+-#endif
++/* Max 8 Nodes - APIC limit currently */
++#define NODES_SHIFT   3
+ #endif
+--- linux-2.6.0-test6/include/asm-x86_64/pgtable.h     2003-07-02 14:53:18.000000000 -0700
++++ 25/include/asm-x86_64/pgtable.h    2003-10-05 00:33:24.000000000 -0700
+@@ -126,7 +126,6 @@ static inline void set_pml4(pml4_t *dst,
+ #ifndef __ASSEMBLY__
+ #define VMALLOC_START    0xffffff0000000000
+ #define VMALLOC_END      0xffffff7fffffffff
+-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+ #define MODULES_VADDR    0xffffffffa0000000
+ #define MODULES_END      0xffffffffafffffff
+ #define MODULES_LEN   (MODULES_END - MODULES_VADDR)
+--- linux-2.6.0-test6/include/linux/acpi.h     2003-08-22 19:23:42.000000000 -0700
++++ 25/include/linux/acpi.h    2003-10-05 00:33:24.000000000 -0700
+@@ -424,17 +424,17 @@ int ec_write(u8 addr, u8 val);
+ #endif /*CONFIG_ACPI_EC*/
+-#ifdef CONFIG_ACPI
++#ifdef CONFIG_ACPI_INTERPRETER
+ int acpi_blacklisted(void);
+-#else
++#else /*!CONFIG_ACPI_INTERPRETER*/
+ static inline int acpi_blacklisted(void)
+ {
+       return 0;
+ }
+-#endif /*CONFIG_ACPI*/
++#endif /*!CONFIG_ACPI_INTERPRETER*/
+ #endif /*_LINUX_ACPI_H*/
+--- linux-2.6.0-test6/include/linux/aio.h      2003-06-26 22:07:26.000000000 -0700
++++ 25/include/linux/aio.h     2003-10-05 00:37:05.000000000 -0700
+@@ -29,21 +29,26 @@ struct kioctx;
+ #define KIF_LOCKED            0
+ #define KIF_KICKED            1
+ #define KIF_CANCELLED         2
++#define KIF_SYNCED            3
+ #define kiocbTryLock(iocb)    test_and_set_bit(KIF_LOCKED, &(iocb)->ki_flags)
+ #define kiocbTryKick(iocb)    test_and_set_bit(KIF_KICKED, &(iocb)->ki_flags)
++#define kiocbTrySync(iocb)    test_and_set_bit(KIF_SYNCED, &(iocb)->ki_flags)
+ #define kiocbSetLocked(iocb)  set_bit(KIF_LOCKED, &(iocb)->ki_flags)
+ #define kiocbSetKicked(iocb)  set_bit(KIF_KICKED, &(iocb)->ki_flags)
+ #define kiocbSetCancelled(iocb)       set_bit(KIF_CANCELLED, &(iocb)->ki_flags)
++#define kiocbSetSynced(iocb)  set_bit(KIF_SYNCED, &(iocb)->ki_flags)
+ #define kiocbClearLocked(iocb)        clear_bit(KIF_LOCKED, &(iocb)->ki_flags)
+ #define kiocbClearKicked(iocb)        clear_bit(KIF_KICKED, &(iocb)->ki_flags)
+ #define kiocbClearCancelled(iocb)     clear_bit(KIF_CANCELLED, &(iocb)->ki_flags)
++#define kiocbClearSynced(iocb)        clear_bit(KIF_SYNCED, &(iocb)->ki_flags)
+ #define kiocbIsLocked(iocb)   test_bit(KIF_LOCKED, &(iocb)->ki_flags)
+ #define kiocbIsKicked(iocb)   test_bit(KIF_KICKED, &(iocb)->ki_flags)
+ #define kiocbIsCancelled(iocb)        test_bit(KIF_CANCELLED, &(iocb)->ki_flags)
++#define kiocbIsSynced(iocb)   test_bit(KIF_SYNCED, &(iocb)->ki_flags)
+ struct kiocb {
+       struct list_head        ki_run_list;
+@@ -54,7 +59,7 @@ struct kiocb {
+       struct file             *ki_filp;
+       struct kioctx           *ki_ctx;        /* may be NULL for sync ops */
+       int                     (*ki_cancel)(struct kiocb *, struct io_event *);
+-      long                    (*ki_retry)(struct kiocb *);
++      ssize_t                 (*ki_retry)(struct kiocb *);
+       struct list_head        ki_list;        /* the aio core uses this
+                                                * for cancellation */
+@@ -63,6 +68,16 @@ struct kiocb {
+       __u64                   ki_user_data;   /* user's data for completion */
+       loff_t                  ki_pos;
++      /* State that we remember to be able to restart/retry  */
++      unsigned short          ki_opcode;
++      size_t                  ki_nbytes;      /* copy of iocb->aio_nbytes */
++      char                    *ki_buf;        /* remaining iocb->aio_buf */
++      size_t                  ki_left;        /* remaining bytes */
++      wait_queue_t            ki_wait;
++      long                    ki_retried;     /* just for testing */
++      long                    ki_kicked;      /* just for testing */
++      long                    ki_queued;      /* just for testing */
++
+       char                    private[KIOCB_PRIVATE_SIZE];
+ };
+@@ -77,6 +92,8 @@ struct kiocb {
+               (x)->ki_ctx = &tsk->active_mm->default_kioctx;  \
+               (x)->ki_cancel = NULL;                  \
+               (x)->ki_user_obj = tsk;                 \
++              (x)->ki_user_data = 0;                  \
++              init_wait((&(x)->ki_wait));             \
+       } while (0)
+ #define AIO_RING_MAGIC                        0xa10a10a1
+@@ -159,6 +176,17 @@ int FASTCALL(io_submit_one(struct kioctx
+ #define get_ioctx(kioctx)     do { if (unlikely(atomic_read(&(kioctx)->users) <= 0)) BUG(); atomic_inc(&(kioctx)->users); } while (0)
+ #define put_ioctx(kioctx)     do { if (unlikely(atomic_dec_and_test(&(kioctx)->users))) __put_ioctx(kioctx); else if (unlikely(atomic_read(&(kioctx)->users) < 0)) BUG(); } while (0)
++#define in_aio() !is_sync_wait(current->io_wait)
++/* may be used for debugging */
++#define warn_if_async()       if (in_aio()) {\
++      printk(KERN_ERR "%s(%s:%d) called in async context!\n", \
++      __FUNCTION__, __FILE__, __LINE__); \
++      dump_stack(); \
++      }
++
++#define io_wait_to_kiocb(wait) container_of(wait, struct kiocb, ki_wait)
++#define is_retried_kiocb(iocb) ((iocb)->ki_retried > 1)
++
+ #include <linux/aio_abi.h>
+ static inline struct kiocb *list_kiocb(struct list_head *h)
+--- linux-2.6.0-test6/include/linux/blkdev.h   2003-09-27 18:57:47.000000000 -0700
++++ 25/include/linux/blkdev.h  2003-10-05 00:36:58.000000000 -0700
+@@ -585,6 +585,7 @@ extern void blk_queue_free_tags(request_
+ extern int blk_queue_resize_tags(request_queue_t *, int);
+ extern void blk_queue_invalidate_tags(request_queue_t *);
+ extern void blk_congestion_wait(int rw, long timeout);
++extern int blk_congestion_wait_wq(int rw, long timeout, wait_queue_t *wait);
+ extern void blk_rq_bio_prep(request_queue_t *, struct request *, struct bio *);
+ extern void blk_rq_prep_restart(struct request *);
+--- linux-2.6.0-test6/include/linux/buffer_head.h      2003-08-22 19:23:42.000000000 -0700
++++ 25/include/linux/buffer_head.h     2003-10-05 00:37:00.000000000 -0700
+@@ -162,6 +162,7 @@ void mark_buffer_async_write(struct buff
+ void invalidate_bdev(struct block_device *, int);
+ int sync_blockdev(struct block_device *bdev);
+ void __wait_on_buffer(struct buffer_head *);
++int __wait_on_buffer_wq(struct buffer_head *, wait_queue_t *wait);
+ wait_queue_head_t *bh_waitq_head(struct buffer_head *bh);
+ void wake_up_buffer(struct buffer_head *bh);
+ int fsync_bdev(struct block_device *);
+@@ -173,6 +174,8 @@ void __brelse(struct buffer_head *);
+ void __bforget(struct buffer_head *);
+ void __breadahead(struct block_device *, sector_t block, int size);
+ struct buffer_head *__bread(struct block_device *, sector_t block, int size);
++struct buffer_head *__bread_wq(struct block_device *, sector_t block,
++      int size, wait_queue_t *wait);
+ struct buffer_head *alloc_buffer_head(int gfp_flags);
+ void free_buffer_head(struct buffer_head * bh);
+ void FASTCALL(unlock_buffer(struct buffer_head *bh));
+@@ -207,12 +210,6 @@ int nobh_prepare_write(struct page*, uns
+ int nobh_commit_write(struct file *, struct page *, unsigned, unsigned);
+ int nobh_truncate_page(struct address_space *, loff_t);
+-#define OSYNC_METADATA        (1<<0)
+-#define OSYNC_DATA    (1<<1)
+-#define OSYNC_INODE   (1<<2)
+-int generic_osync_inode(struct inode *, int);
+-
+-
+ /*
+  * inline definitions
+  */
+@@ -230,13 +227,13 @@ static inline void put_bh(struct buffer_
+ static inline void brelse(struct buffer_head *bh)
+ {
+-      if (bh)
++      if (bh && !IS_ERR(bh))
+               __brelse(bh);
+ }
+ static inline void bforget(struct buffer_head *bh)
+ {
+-      if (bh)
++      if (bh && !IS_ERR(bh))
+               __bforget(bh);
+ }
+@@ -253,7 +250,12 @@ sb_breadahead(struct super_block *sb, se
+ }
+ static inline struct buffer_head *
+-sb_getblk(struct super_block *sb, sector_t block)
++sb_bread_wq(struct super_block *sb, sector_t block, wait_queue_t *wait)
++{
++      return __bread_wq(sb->s_bdev, block, sb->s_blocksize, wait);
++}
++
++static inline struct buffer_head *sb_getblk(struct super_block *sb, sector_t block)
+ {
+       return __getblk(sb->s_bdev, block, sb->s_blocksize);
+ }
+@@ -277,16 +279,34 @@ map_bh(struct buffer_head *bh, struct su
+  * __wait_on_buffer() just to trip a debug check.  Because debug code in inline
+  * functions is bloaty.
+  */
+-static inline void wait_on_buffer(struct buffer_head *bh)
++
++static inline int wait_on_buffer_wq(struct buffer_head *bh, wait_queue_t *wait)
+ {
+       if (buffer_locked(bh) || atomic_read(&bh->b_count) == 0)
+-              __wait_on_buffer(bh);
++              return __wait_on_buffer_wq(bh, wait);
++
++      return 0;
++}
++
++static inline void wait_on_buffer(struct buffer_head *bh)
++{
++      wait_on_buffer_wq(bh, NULL);
++}
++
++static inline int lock_buffer_wq(struct buffer_head *bh, wait_queue_t *wait)
++{
++      while (test_set_buffer_locked(bh)) {
++              int ret = __wait_on_buffer_wq(bh, wait);
++              if (ret)
++                      return ret;
++      }
++
++      return 0;
+ }
+ static inline void lock_buffer(struct buffer_head *bh)
+ {
+-      while (test_set_buffer_locked(bh))
+-              __wait_on_buffer(bh);
++      lock_buffer_wq(bh, NULL);
+ }
+ #endif /* _LINUX_BUFFER_HEAD_H */
+--- linux-2.6.0-test6/include/linux/cdrom.h    2003-07-02 14:53:18.000000000 -0700
++++ 25/include/linux/cdrom.h   2003-10-05 00:33:59.000000000 -0700
+@@ -743,6 +743,7 @@ struct cdrom_device_info {
+ /* per-device flags */
+         __u8 sanyo_slot               : 2;    /* Sanyo 3 CD changer support */
+         __u8 reserved         : 6;    /* not used yet */
++      int for_data;
+       struct cdrom_write_settings write;
+ };
+@@ -776,9 +777,9 @@ struct cdrom_device_ops {
+ };
+ /* the general block_device operations structure: */
+-extern int cdrom_open(struct cdrom_device_info *, struct inode *, struct file *);
+-extern int cdrom_release(struct cdrom_device_info *, struct file *);
+-extern int cdrom_ioctl(struct cdrom_device_info *, struct inode *, unsigned, unsigned long);
++extern int cdrom_open(struct cdrom_device_info *, struct block_device *, struct file *);
++extern int cdrom_release(struct cdrom_device_info *);
++extern int cdrom_ioctl(struct cdrom_device_info *, struct block_device *, unsigned, unsigned long);
+ extern int cdrom_media_changed(struct cdrom_device_info *);
+ extern int register_cdrom(struct cdrom_device_info *cdi);
+--- linux-2.6.0-test6/include/linux/compat.h   2003-08-22 19:23:42.000000000 -0700
++++ 25/include/linux/compat.h  2003-10-05 00:34:44.000000000 -0700
+@@ -90,5 +90,12 @@ struct compat_statfs64 {
+       __u32 f_spare[5];
+ };
++struct compat_dirent {
++      u32             d_ino;
++      compat_off_t    d_off;
++      u16             d_reclen;
++      char            d_name[256];
++};
++
+ #endif /* CONFIG_COMPAT */
+ #endif /* _LINUX_COMPAT_H */
+--- linux-2.6.0-test6/include/linux/compat_ioctl.h     2003-09-27 18:57:47.000000000 -0700
++++ 25/include/linux/compat_ioctl.h    2003-10-05 00:33:24.000000000 -0700
+@@ -68,7 +68,7 @@ COMPATIBLE_IOCTL(HDIO_SET_MULTCOUNT)
+ COMPATIBLE_IOCTL(HDIO_DRIVE_CMD)
+ COMPATIBLE_IOCTL(HDIO_SET_PIO_MODE)
+ COMPATIBLE_IOCTL(HDIO_SET_NICE)
+-#ifndef CONFIG_ARCH_S390
++#ifdef CONFIG_BLK_DEV_FD
+ /* 0x02 -- Floppy ioctls */
+ COMPATIBLE_IOCTL(FDMSGON)
+ COMPATIBLE_IOCTL(FDMSGOFF)
+--- linux-2.6.0-test6/include/linux/compiler-gcc.h     2003-09-27 18:57:47.000000000 -0700
++++ 25/include/linux/compiler-gcc.h    2003-10-05 00:34:18.000000000 -0700
+@@ -13,5 +13,5 @@
+    shouldn't recognize the original var, and make assumptions about it */
+ #define RELOC_HIDE(ptr, off)                                  \
+   ({ unsigned long __ptr;                                     \
+-    __asm__ ("" : "=g"(__ptr) : "0"(ptr));            \
++      __asm__ ("" : "=r"(__ptr) : "0"(ptr));                  \
+     (typeof(ptr)) (__ptr + (off)); })
+--- linux-2.6.0-test6/include/linux/config.h   2003-06-26 22:07:26.000000000 -0700
++++ 25/include/linux/config.h  2003-10-05 00:33:43.000000000 -0700
+@@ -2,5 +2,8 @@
+ #define _LINUX_CONFIG_H
+ #include <linux/autoconf.h>
++#if defined(__i386__) && !defined(IN_BOOTLOADER)
++#include <asm/kgdb.h>
++#endif
+ #endif
+--- linux-2.6.0-test6/include/linux/dqblk_xfs.h        2003-06-14 12:18:29.000000000 -0700
++++ 25/include/linux/dqblk_xfs.h       2003-10-05 00:33:24.000000000 -0700
+@@ -105,15 +105,6 @@ typedef struct fs_disk_quota {
+ #define FS_DQ_TIMER_MASK      (FS_DQ_BTIMER | FS_DQ_ITIMER | FS_DQ_RTBTIMER)
+ /*
+- * The following constants define the default amount of time given a user
+- * before the soft limits are treated as hard limits (usually resulting
+- * in an allocation failure).  These may be modified by the quotactl(2)
+- * system call with the Q_XSETQLIM command.
+- */
+-#define       DQ_FTIMELIMIT   (7 * 24*60*60)          /* 1 week */
+-#define       DQ_BTIMELIMIT   (7 * 24*60*60)          /* 1 week */
+-
+-/*
+  * Various flags related to quotactl(2).  Only relevant to XFS filesystems.
+  */
+ #define XFS_QUOTA_UDQ_ACCT    (1<<0)  /* user quota accounting */
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/include/linux/dwarf2.h  2003-10-05 00:33:38.000000000 -0700
+@@ -0,0 +1,738 @@
++/* Declarations and definitions of codes relating to the DWARF2 symbolic
++   debugging information format.
++   Copyright (C) 1992, 1993, 1995, 1996, 1997, 1999, 2000, 2001, 2002
++   Free Software Foundation, Inc.
++
++   Written by Gary Funck (gary@intrepid.com) The Ada Joint Program
++   Office (AJPO), Florida State Unviversity and Silicon Graphics Inc.
++   provided support for this effort -- June 21, 1995.
++
++   Derived from the DWARF 1 implementation written by Ron Guilmette
++   (rfg@netcom.com), November 1990.
++
++   This file is part of GCC.
++
++   GCC is free software; you can redistribute it and/or modify it under
++   the terms of the GNU General Public License as published by the Free
++   Software Foundation; either version 2, or (at your option) any later
++   version.
++
++   GCC 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 GCC; see the file COPYING.  If not, write to the Free
++   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
++   02111-1307, USA.  */
++
++/* This file is derived from the DWARF specification (a public document)
++   Revision 2.0.0 (July 27, 1993) developed by the UNIX International
++   Programming Languages Special Interest Group (UI/PLSIG) and distributed
++   by UNIX International.  Copies of this specification are available from
++   UNIX International, 20 Waterview Boulevard, Parsippany, NJ, 07054.
++
++   This file also now contains definitions from the DWARF 3 specification.  */
++
++/* This file is shared between GCC and GDB, and should not contain
++   prototypes.        */
++
++#ifndef _ELF_DWARF2_H
++#define _ELF_DWARF2_H
++
++/* Structure found in the .debug_line section.        */
++#ifndef __ASSEMBLY__
++typedef struct
++{
++  unsigned char li_length        [4];
++  unsigned char li_version       [2];
++  unsigned char li_prologue_length [4];
++  unsigned char li_min_insn_length [1];
++  unsigned char li_default_is_stmt [1];
++  unsigned char li_line_base     [1];
++  unsigned char li_line_range    [1];
++  unsigned char li_opcode_base           [1];
++}
++DWARF2_External_LineInfo;
++
++typedef struct
++{
++  unsigned long  li_length;
++  unsigned short li_version;
++  unsigned int         li_prologue_length;
++  unsigned char  li_min_insn_length;
++  unsigned char  li_default_is_stmt;
++  int          li_line_base;
++  unsigned char  li_line_range;
++  unsigned char  li_opcode_base;
++}
++DWARF2_Internal_LineInfo;
++
++/* Structure found in .debug_pubnames section.        */
++typedef struct
++{
++  unsigned char pn_length  [4];
++  unsigned char pn_version [2];
++  unsigned char pn_offset  [4];
++  unsigned char pn_size    [4];
++}
++DWARF2_External_PubNames;
++
++typedef struct
++{
++  unsigned long  pn_length;
++  unsigned short pn_version;
++  unsigned long  pn_offset;
++  unsigned long  pn_size;
++}
++DWARF2_Internal_PubNames;
++
++/* Structure found in .debug_info section.  */
++typedef struct
++{
++  unsigned char  cu_length      [4];
++  unsigned char  cu_version     [2];
++  unsigned char  cu_abbrev_offset [4];
++  unsigned char  cu_pointer_size  [1];
++}
++DWARF2_External_CompUnit;
++
++typedef struct
++{
++  unsigned long  cu_length;
++  unsigned short cu_version;
++  unsigned long  cu_abbrev_offset;
++  unsigned char  cu_pointer_size;
++}
++DWARF2_Internal_CompUnit;
++
++typedef struct
++{
++  unsigned char  ar_length     [4];
++  unsigned char  ar_version    [2];
++  unsigned char  ar_info_offset  [4];
++  unsigned char  ar_pointer_size [1];
++  unsigned char  ar_segment_size [1];
++}
++DWARF2_External_ARange;
++
++typedef struct
++{
++  unsigned long  ar_length;
++  unsigned short ar_version;
++  unsigned long  ar_info_offset;
++  unsigned char  ar_pointer_size;
++  unsigned char  ar_segment_size;
++}
++DWARF2_Internal_ARange;
++
++#define ENUM(name) enum name {
++#define IF_NOT_ASM(a) a
++#define COMMA ,
++#else
++#define ENUM(name)
++#define IF_NOT_ASM(a)
++#define COMMA
++
++#endif
++
++/* Tag names and codes.  */
++ENUM(dwarf_tag)
++
++    DW_TAG_padding = 0x00 COMMA
++    DW_TAG_array_type = 0x01 COMMA
++    DW_TAG_class_type = 0x02 COMMA
++    DW_TAG_entry_point = 0x03 COMMA
++    DW_TAG_enumeration_type = 0x04 COMMA
++    DW_TAG_formal_parameter = 0x05 COMMA
++    DW_TAG_imported_declaration = 0x08 COMMA
++    DW_TAG_label = 0x0a COMMA
++    DW_TAG_lexical_block = 0x0b COMMA
++    DW_TAG_member = 0x0d COMMA
++    DW_TAG_pointer_type = 0x0f COMMA
++    DW_TAG_reference_type = 0x10 COMMA
++    DW_TAG_compile_unit = 0x11 COMMA
++    DW_TAG_string_type = 0x12 COMMA
++    DW_TAG_structure_type = 0x13 COMMA
++    DW_TAG_subroutine_type = 0x15 COMMA
++    DW_TAG_typedef = 0x16 COMMA
++    DW_TAG_union_type = 0x17 COMMA
++    DW_TAG_unspecified_parameters = 0x18 COMMA
++    DW_TAG_variant = 0x19 COMMA
++    DW_TAG_common_block = 0x1a COMMA
++    DW_TAG_common_inclusion = 0x1b COMMA
++    DW_TAG_inheritance = 0x1c COMMA
++    DW_TAG_inlined_subroutine = 0x1d COMMA
++    DW_TAG_module = 0x1e COMMA
++    DW_TAG_ptr_to_member_type = 0x1f COMMA
++    DW_TAG_set_type = 0x20 COMMA
++    DW_TAG_subrange_type = 0x21 COMMA
++    DW_TAG_with_stmt = 0x22 COMMA
++    DW_TAG_access_declaration = 0x23 COMMA
++    DW_TAG_base_type = 0x24 COMMA
++    DW_TAG_catch_block = 0x25 COMMA
++    DW_TAG_const_type = 0x26 COMMA
++    DW_TAG_constant = 0x27 COMMA
++    DW_TAG_enumerator = 0x28 COMMA
++    DW_TAG_file_type = 0x29 COMMA
++    DW_TAG_friend = 0x2a COMMA
++    DW_TAG_namelist = 0x2b COMMA
++    DW_TAG_namelist_item = 0x2c COMMA
++    DW_TAG_packed_type = 0x2d COMMA
++    DW_TAG_subprogram = 0x2e COMMA
++    DW_TAG_template_type_param = 0x2f COMMA
++    DW_TAG_template_value_param = 0x30 COMMA
++    DW_TAG_thrown_type = 0x31 COMMA
++    DW_TAG_try_block = 0x32 COMMA
++    DW_TAG_variant_part = 0x33 COMMA
++    DW_TAG_variable = 0x34 COMMA
++    DW_TAG_volatile_type = 0x35 COMMA
++    /* DWARF 3.  */
++    DW_TAG_dwarf_procedure = 0x36 COMMA
++    DW_TAG_restrict_type = 0x37 COMMA
++    DW_TAG_interface_type = 0x38 COMMA
++    DW_TAG_namespace = 0x39 COMMA
++    DW_TAG_imported_module = 0x3a COMMA
++    DW_TAG_unspecified_type = 0x3b COMMA
++    DW_TAG_partial_unit = 0x3c COMMA
++    DW_TAG_imported_unit = 0x3d COMMA
++    /* SGI/MIPS Extensions.  */
++    DW_TAG_MIPS_loop = 0x4081 COMMA
++    /* GNU extensions.        */
++    DW_TAG_format_label = 0x4101 COMMA        /* For FORTRAN 77 and Fortran 90.  */
++    DW_TAG_function_template = 0x4102 COMMA   /* For C++.  */
++    DW_TAG_class_template = 0x4103 COMMA      /* For C++.  */
++    DW_TAG_GNU_BINCL = 0x4104 COMMA
++    DW_TAG_GNU_EINCL = 0x4105 COMMA
++    /* Extensions for UPC.  See: http://upc.gwu.edu/~upc.  */
++    DW_TAG_upc_shared_type = 0x8765 COMMA
++    DW_TAG_upc_strict_type = 0x8766 COMMA
++    DW_TAG_upc_relaxed_type = 0x8767
++IF_NOT_ASM(};)
++
++#define DW_TAG_lo_user        0x4080
++#define DW_TAG_hi_user        0xffff
++
++/* Flag that tells whether entry has a child or not.  */
++#define DW_children_no         0
++#define       DW_children_yes  1
++
++/* Form names and codes.  */
++ENUM(dwarf_form)
++
++    DW_FORM_addr = 0x01 COMMA
++    DW_FORM_block2 = 0x03 COMMA
++    DW_FORM_block4 = 0x04 COMMA
++    DW_FORM_data2 = 0x05 COMMA
++    DW_FORM_data4 = 0x06 COMMA
++    DW_FORM_data8 = 0x07 COMMA
++    DW_FORM_string = 0x08 COMMA
++    DW_FORM_block = 0x09 COMMA
++    DW_FORM_block1 = 0x0a COMMA
++    DW_FORM_data1 = 0x0b COMMA
++    DW_FORM_flag = 0x0c COMMA
++    DW_FORM_sdata = 0x0d COMMA
++    DW_FORM_strp = 0x0e COMMA
++    DW_FORM_udata = 0x0f COMMA
++    DW_FORM_ref_addr = 0x10 COMMA
++    DW_FORM_ref1 = 0x11 COMMA
++    DW_FORM_ref2 = 0x12 COMMA
++    DW_FORM_ref4 = 0x13 COMMA
++    DW_FORM_ref8 = 0x14 COMMA
++    DW_FORM_ref_udata = 0x15 COMMA
++    DW_FORM_indirect = 0x16
++IF_NOT_ASM(};)
++
++/* Attribute names and codes.  */
++
++ENUM(dwarf_attribute)
++
++    DW_AT_sibling = 0x01 COMMA
++    DW_AT_location = 0x02 COMMA
++    DW_AT_name = 0x03 COMMA
++    DW_AT_ordering = 0x09 COMMA
++    DW_AT_subscr_data = 0x0a COMMA
++    DW_AT_byte_size = 0x0b COMMA
++    DW_AT_bit_offset = 0x0c COMMA
++    DW_AT_bit_size = 0x0d COMMA
++    DW_AT_element_list = 0x0f COMMA
++    DW_AT_stmt_list = 0x10 COMMA
++    DW_AT_low_pc = 0x11 COMMA
++    DW_AT_high_pc = 0x12 COMMA
++    DW_AT_language = 0x13 COMMA
++    DW_AT_member = 0x14 COMMA
++    DW_AT_discr = 0x15 COMMA
++    DW_AT_discr_value = 0x16 COMMA
++    DW_AT_visibility = 0x17 COMMA
++    DW_AT_import = 0x18 COMMA
++    DW_AT_string_length = 0x19 COMMA
++    DW_AT_common_reference = 0x1a COMMA
++    DW_AT_comp_dir = 0x1b COMMA
++    DW_AT_const_value = 0x1c COMMA
++    DW_AT_containing_type = 0x1d COMMA
++    DW_AT_default_value = 0x1e COMMA
++    DW_AT_inline = 0x20 COMMA
++    DW_AT_is_optional = 0x21 COMMA
++    DW_AT_lower_bound = 0x22 COMMA
++    DW_AT_producer = 0x25 COMMA
++    DW_AT_prototyped = 0x27 COMMA
++    DW_AT_return_addr = 0x2a COMMA
++    DW_AT_start_scope = 0x2c COMMA
++    DW_AT_stride_size = 0x2e COMMA
++    DW_AT_upper_bound = 0x2f COMMA
++    DW_AT_abstract_origin = 0x31 COMMA
++    DW_AT_accessibility = 0x32 COMMA
++    DW_AT_address_class = 0x33 COMMA
++    DW_AT_artificial = 0x34 COMMA
++    DW_AT_base_types = 0x35 COMMA
++    DW_AT_calling_convention = 0x36 COMMA
++    DW_AT_count = 0x37 COMMA
++    DW_AT_data_member_location = 0x38 COMMA
++    DW_AT_decl_column = 0x39 COMMA
++    DW_AT_decl_file = 0x3a COMMA
++    DW_AT_decl_line = 0x3b COMMA
++    DW_AT_declaration = 0x3c COMMA
++    DW_AT_discr_list = 0x3d COMMA
++    DW_AT_encoding = 0x3e COMMA
++    DW_AT_external = 0x3f COMMA
++    DW_AT_frame_base = 0x40 COMMA
++    DW_AT_friend = 0x41 COMMA
++    DW_AT_identifier_case = 0x42 COMMA
++    DW_AT_macro_info = 0x43 COMMA
++    DW_AT_namelist_items = 0x44 COMMA
++    DW_AT_priority = 0x45 COMMA
++    DW_AT_segment = 0x46 COMMA
++    DW_AT_specification = 0x47 COMMA
++    DW_AT_static_link = 0x48 COMMA
++    DW_AT_type = 0x49 COMMA
++    DW_AT_use_location = 0x4a COMMA
++    DW_AT_variable_parameter = 0x4b COMMA
++    DW_AT_virtuality = 0x4c COMMA
++    DW_AT_vtable_elem_location = 0x4d COMMA
++    /* DWARF 3 values.        */
++    DW_AT_allocated   = 0x4e COMMA
++    DW_AT_associated  = 0x4f COMMA
++    DW_AT_data_location = 0x50 COMMA
++    DW_AT_stride      = 0x51 COMMA
++    DW_AT_entry_pc    = 0x52 COMMA
++    DW_AT_use_UTF8    = 0x53 COMMA
++    DW_AT_extension   = 0x54 COMMA
++    DW_AT_ranges      = 0x55 COMMA
++    DW_AT_trampoline  = 0x56 COMMA
++    DW_AT_call_column = 0x57 COMMA
++    DW_AT_call_file   = 0x58 COMMA
++    DW_AT_call_line   = 0x59 COMMA
++    /* SGI/MIPS extensions.  */
++    DW_AT_MIPS_fde = 0x2001 COMMA
++    DW_AT_MIPS_loop_begin = 0x2002 COMMA
++    DW_AT_MIPS_tail_loop_begin = 0x2003 COMMA
++    DW_AT_MIPS_epilog_begin = 0x2004 COMMA
++    DW_AT_MIPS_loop_unroll_factor = 0x2005 COMMA
++    DW_AT_MIPS_software_pipeline_depth = 0x2006 COMMA
++    DW_AT_MIPS_linkage_name = 0x2007 COMMA
++    DW_AT_MIPS_stride = 0x2008 COMMA
++    DW_AT_MIPS_abstract_name = 0x2009 COMMA
++    DW_AT_MIPS_clone_origin = 0x200a COMMA
++    DW_AT_MIPS_has_inlines = 0x200b COMMA
++    /* GNU extensions.        */
++    DW_AT_sf_names   = 0x2101 COMMA
++    DW_AT_src_info   = 0x2102 COMMA
++    DW_AT_mac_info   = 0x2103 COMMA
++    DW_AT_src_coords = 0x2104 COMMA
++    DW_AT_body_begin = 0x2105 COMMA
++    DW_AT_body_end   = 0x2106 COMMA
++    DW_AT_GNU_vector = 0x2107 COMMA
++    /* VMS extensions.        */
++    DW_AT_VMS_rtnbeg_pd_address = 0x2201 COMMA
++    /* UPC extension.  */
++    DW_AT_upc_threads_scaled = 0x3210
++IF_NOT_ASM(};)
++
++#define DW_AT_lo_user 0x2000  /* Implementation-defined range start.  */
++#define DW_AT_hi_user 0x3ff0  /* Implementation-defined range end.  */
++
++/* Location atom names and codes.  */
++ENUM(dwarf_location_atom)
++
++    DW_OP_addr = 0x03 COMMA
++    DW_OP_deref = 0x06 COMMA
++    DW_OP_const1u = 0x08 COMMA
++    DW_OP_const1s = 0x09 COMMA
++    DW_OP_const2u = 0x0a COMMA
++    DW_OP_const2s = 0x0b COMMA
++    DW_OP_const4u = 0x0c COMMA
++    DW_OP_const4s = 0x0d COMMA
++    DW_OP_const8u = 0x0e COMMA
++    DW_OP_const8s = 0x0f COMMA
++    DW_OP_constu = 0x10 COMMA
++    DW_OP_consts = 0x11 COMMA
++    DW_OP_dup = 0x12 COMMA
++    DW_OP_drop = 0x13 COMMA
++    DW_OP_over = 0x14 COMMA
++    DW_OP_pick = 0x15 COMMA
++    DW_OP_swap = 0x16 COMMA
++    DW_OP_rot = 0x17 COMMA
++    DW_OP_xderef = 0x18 COMMA
++    DW_OP_abs = 0x19 COMMA
++    DW_OP_and = 0x1a COMMA
++    DW_OP_div = 0x1b COMMA
++    DW_OP_minus = 0x1c COMMA
++    DW_OP_mod = 0x1d COMMA
++    DW_OP_mul = 0x1e COMMA
++    DW_OP_neg = 0x1f COMMA
++    DW_OP_not = 0x20 COMMA
++    DW_OP_or = 0x21 COMMA
++    DW_OP_plus = 0x22 COMMA
++    DW_OP_plus_uconst = 0x23 COMMA
++    DW_OP_shl = 0x24 COMMA
++    DW_OP_shr = 0x25 COMMA
++    DW_OP_shra = 0x26 COMMA
++    DW_OP_xor = 0x27 COMMA
++    DW_OP_bra = 0x28 COMMA
++    DW_OP_eq = 0x29 COMMA
++    DW_OP_ge = 0x2a COMMA
++    DW_OP_gt = 0x2b COMMA
++    DW_OP_le = 0x2c COMMA
++    DW_OP_lt = 0x2d COMMA
++    DW_OP_ne = 0x2e COMMA
++    DW_OP_skip = 0x2f COMMA
++    DW_OP_lit0 = 0x30 COMMA
++    DW_OP_lit1 = 0x31 COMMA
++    DW_OP_lit2 = 0x32 COMMA
++    DW_OP_lit3 = 0x33 COMMA
++    DW_OP_lit4 = 0x34 COMMA
++    DW_OP_lit5 = 0x35 COMMA
++    DW_OP_lit6 = 0x36 COMMA
++    DW_OP_lit7 = 0x37 COMMA
++    DW_OP_lit8 = 0x38 COMMA
++    DW_OP_lit9 = 0x39 COMMA
++    DW_OP_lit10 = 0x3a COMMA
++    DW_OP_lit11 = 0x3b COMMA
++    DW_OP_lit12 = 0x3c COMMA
++    DW_OP_lit13 = 0x3d COMMA
++    DW_OP_lit14 = 0x3e COMMA
++    DW_OP_lit15 = 0x3f COMMA
++    DW_OP_lit16 = 0x40 COMMA
++    DW_OP_lit17 = 0x41 COMMA
++    DW_OP_lit18 = 0x42 COMMA
++    DW_OP_lit19 = 0x43 COMMA
++    DW_OP_lit20 = 0x44 COMMA
++    DW_OP_lit21 = 0x45 COMMA
++    DW_OP_lit22 = 0x46 COMMA
++    DW_OP_lit23 = 0x47 COMMA
++    DW_OP_lit24 = 0x48 COMMA
++    DW_OP_lit25 = 0x49 COMMA
++    DW_OP_lit26 = 0x4a COMMA
++    DW_OP_lit27 = 0x4b COMMA
++    DW_OP_lit28 = 0x4c COMMA
++    DW_OP_lit29 = 0x4d COMMA
++    DW_OP_lit30 = 0x4e COMMA
++    DW_OP_lit31 = 0x4f COMMA
++    DW_OP_reg0 = 0x50 COMMA
++    DW_OP_reg1 = 0x51 COMMA
++    DW_OP_reg2 = 0x52 COMMA
++    DW_OP_reg3 = 0x53 COMMA
++    DW_OP_reg4 = 0x54 COMMA
++    DW_OP_reg5 = 0x55 COMMA
++    DW_OP_reg6 = 0x56 COMMA
++    DW_OP_reg7 = 0x57 COMMA
++    DW_OP_reg8 = 0x58 COMMA
++    DW_OP_reg9 = 0x59 COMMA
++    DW_OP_reg10 = 0x5a COMMA
++    DW_OP_reg11 = 0x5b COMMA
++    DW_OP_reg12 = 0x5c COMMA
++    DW_OP_reg13 = 0x5d COMMA
++    DW_OP_reg14 = 0x5e COMMA
++    DW_OP_reg15 = 0x5f COMMA
++    DW_OP_reg16 = 0x60 COMMA
++    DW_OP_reg17 = 0x61 COMMA
++    DW_OP_reg18 = 0x62 COMMA
++    DW_OP_reg19 = 0x63 COMMA
++    DW_OP_reg20 = 0x64 COMMA
++    DW_OP_reg21 = 0x65 COMMA
++    DW_OP_reg22 = 0x66 COMMA
++    DW_OP_reg23 = 0x67 COMMA
++    DW_OP_reg24 = 0x68 COMMA
++    DW_OP_reg25 = 0x69 COMMA
++    DW_OP_reg26 = 0x6a COMMA
++    DW_OP_reg27 = 0x6b COMMA
++    DW_OP_reg28 = 0x6c COMMA
++    DW_OP_reg29 = 0x6d COMMA
++    DW_OP_reg30 = 0x6e COMMA
++    DW_OP_reg31 = 0x6f COMMA
++    DW_OP_breg0 = 0x70 COMMA
++    DW_OP_breg1 = 0x71 COMMA
++    DW_OP_breg2 = 0x72 COMMA
++    DW_OP_breg3 = 0x73 COMMA
++    DW_OP_breg4 = 0x74 COMMA
++    DW_OP_breg5 = 0x75 COMMA
++    DW_OP_breg6 = 0x76 COMMA
++    DW_OP_breg7 = 0x77 COMMA
++    DW_OP_breg8 = 0x78 COMMA
++    DW_OP_breg9 = 0x79 COMMA
++    DW_OP_breg10 = 0x7a COMMA
++    DW_OP_breg11 = 0x7b COMMA
++    DW_OP_breg12 = 0x7c COMMA
++    DW_OP_breg13 = 0x7d COMMA
++    DW_OP_breg14 = 0x7e COMMA
++    DW_OP_breg15 = 0x7f COMMA
++    DW_OP_breg16 = 0x80 COMMA
++    DW_OP_breg17 = 0x81 COMMA
++    DW_OP_breg18 = 0x82 COMMA
++    DW_OP_breg19 = 0x83 COMMA
++    DW_OP_breg20 = 0x84 COMMA
++    DW_OP_breg21 = 0x85 COMMA
++    DW_OP_breg22 = 0x86 COMMA
++    DW_OP_breg23 = 0x87 COMMA
++    DW_OP_breg24 = 0x88 COMMA
++    DW_OP_breg25 = 0x89 COMMA
++    DW_OP_breg26 = 0x8a COMMA
++    DW_OP_breg27 = 0x8b COMMA
++    DW_OP_breg28 = 0x8c COMMA
++    DW_OP_breg29 = 0x8d COMMA
++    DW_OP_breg30 = 0x8e COMMA
++    DW_OP_breg31 = 0x8f COMMA
++    DW_OP_regx = 0x90 COMMA
++    DW_OP_fbreg = 0x91 COMMA
++    DW_OP_bregx = 0x92 COMMA
++    DW_OP_piece = 0x93 COMMA
++    DW_OP_deref_size = 0x94 COMMA
++    DW_OP_xderef_size = 0x95 COMMA
++    DW_OP_nop = 0x96 COMMA
++    /* DWARF 3 extensions.  */
++    DW_OP_push_object_address = 0x97 COMMA
++    DW_OP_call2 = 0x98 COMMA
++    DW_OP_call4 = 0x99 COMMA
++    DW_OP_call_ref = 0x9a COMMA
++    /* GNU extensions.        */
++    DW_OP_GNU_push_tls_address = 0xe0
++IF_NOT_ASM(};)
++
++#define DW_OP_lo_user 0xe0    /* Implementation-defined range start.  */
++#define DW_OP_hi_user 0xff    /* Implementation-defined range end.  */
++
++/* Type encodings.  */
++ENUM(dwarf_type)
++
++    DW_ATE_void = 0x0 COMMA
++    DW_ATE_address = 0x1 COMMA
++    DW_ATE_boolean = 0x2 COMMA
++    DW_ATE_complex_float = 0x3 COMMA
++    DW_ATE_float = 0x4 COMMA
++    DW_ATE_signed = 0x5 COMMA
++    DW_ATE_signed_char = 0x6 COMMA
++    DW_ATE_unsigned = 0x7 COMMA
++    DW_ATE_unsigned_char = 0x8 COMMA
++    /* DWARF 3.  */
++    DW_ATE_imaginary_float = 0x9
++IF_NOT_ASM(};)
++
++#define       DW_ATE_lo_user 0x80
++#define       DW_ATE_hi_user 0xff
++
++/* Array ordering names and codes.  */
++ENUM(dwarf_array_dim_ordering)
++
++    DW_ORD_row_major = 0 COMMA
++    DW_ORD_col_major = 1
++IF_NOT_ASM(};)
++
++/* Access attribute.  */
++ENUM(dwarf_access_attribute)
++
++    DW_ACCESS_public = 1 COMMA
++    DW_ACCESS_protected = 2 COMMA
++    DW_ACCESS_private = 3
++IF_NOT_ASM(};)
++
++/* Visibility.        */
++ENUM(dwarf_visibility_attribute)
++
++    DW_VIS_local = 1 COMMA
++    DW_VIS_exported = 2 COMMA
++    DW_VIS_qualified = 3
++IF_NOT_ASM(};)
++
++/* Virtuality.        */
++ENUM(dwarf_virtuality_attribute)
++
++    DW_VIRTUALITY_none = 0 COMMA
++    DW_VIRTUALITY_virtual = 1 COMMA
++    DW_VIRTUALITY_pure_virtual = 2
++IF_NOT_ASM(};)
++
++/* Case sensitivity.  */
++ENUM(dwarf_id_case)
++
++    DW_ID_case_sensitive = 0 COMMA
++    DW_ID_up_case = 1 COMMA
++    DW_ID_down_case = 2 COMMA
++    DW_ID_case_insensitive = 3
++IF_NOT_ASM(};)
++
++/* Calling convention.        */
++ENUM(dwarf_calling_convention)
++
++    DW_CC_normal = 0x1 COMMA
++    DW_CC_program = 0x2 COMMA
++    DW_CC_nocall = 0x3
++IF_NOT_ASM(};)
++
++#define DW_CC_lo_user 0x40
++#define DW_CC_hi_user 0xff
++
++/* Inline attribute.  */
++ENUM(dwarf_inline_attribute)
++
++    DW_INL_not_inlined = 0 COMMA
++    DW_INL_inlined = 1 COMMA
++    DW_INL_declared_not_inlined = 2 COMMA
++    DW_INL_declared_inlined = 3
++IF_NOT_ASM(};)
++
++/* Discriminant lists.        */
++ENUM(dwarf_discrim_list)
++
++    DW_DSC_label = 0 COMMA
++    DW_DSC_range = 1
++IF_NOT_ASM(};)
++
++/* Line number opcodes.  */
++ENUM(dwarf_line_number_ops)
++
++    DW_LNS_extended_op = 0 COMMA
++    DW_LNS_copy = 1 COMMA
++    DW_LNS_advance_pc = 2 COMMA
++    DW_LNS_advance_line = 3 COMMA
++    DW_LNS_set_file = 4 COMMA
++    DW_LNS_set_column = 5 COMMA
++    DW_LNS_negate_stmt = 6 COMMA
++    DW_LNS_set_basic_block = 7 COMMA
++    DW_LNS_const_add_pc = 8 COMMA
++    DW_LNS_fixed_advance_pc = 9 COMMA
++    /* DWARF 3.  */
++    DW_LNS_set_prologue_end = 10 COMMA
++    DW_LNS_set_epilogue_begin = 11 COMMA
++    DW_LNS_set_isa = 12
++IF_NOT_ASM(};)
++
++/* Line number extended opcodes.  */
++ENUM(dwarf_line_number_x_ops)
++
++    DW_LNE_end_sequence = 1 COMMA
++    DW_LNE_set_address = 2 COMMA
++    DW_LNE_define_file = 3
++IF_NOT_ASM(};)
++
++/* Call frame information.  */
++ENUM(dwarf_call_frame_info)
++
++    DW_CFA_advance_loc = 0x40 COMMA
++    DW_CFA_offset = 0x80 COMMA
++    DW_CFA_restore = 0xc0 COMMA
++    DW_CFA_nop = 0x00 COMMA
++    DW_CFA_set_loc = 0x01 COMMA
++    DW_CFA_advance_loc1 = 0x02 COMMA
++    DW_CFA_advance_loc2 = 0x03 COMMA
++    DW_CFA_advance_loc4 = 0x04 COMMA
++    DW_CFA_offset_extended = 0x05 COMMA
++    DW_CFA_restore_extended = 0x06 COMMA
++    DW_CFA_undefined = 0x07 COMMA
++    DW_CFA_same_value = 0x08 COMMA
++    DW_CFA_register = 0x09 COMMA
++    DW_CFA_remember_state = 0x0a COMMA
++    DW_CFA_restore_state = 0x0b COMMA
++    DW_CFA_def_cfa = 0x0c COMMA
++    DW_CFA_def_cfa_register = 0x0d COMMA
++    DW_CFA_def_cfa_offset = 0x0e COMMA
++
++    /* DWARF 3.  */
++    DW_CFA_def_cfa_expression = 0x0f COMMA
++    DW_CFA_expression = 0x10 COMMA
++    DW_CFA_offset_extended_sf = 0x11 COMMA
++    DW_CFA_def_cfa_sf = 0x12 COMMA
++    DW_CFA_def_cfa_offset_sf = 0x13 COMMA
++
++    /* SGI/MIPS specific.  */
++    DW_CFA_MIPS_advance_loc8 = 0x1d COMMA
++
++    /* GNU extensions.        */
++    DW_CFA_GNU_window_save = 0x2d COMMA
++    DW_CFA_GNU_args_size = 0x2e COMMA
++    DW_CFA_GNU_negative_offset_extended = 0x2f
++IF_NOT_ASM(};)
++
++#define DW_CIE_ID       0xffffffff
++#define DW_CIE_VERSION          1
++
++#define DW_CFA_extended   0
++#define DW_CFA_lo_user          0x1c
++#define DW_CFA_hi_user          0x3f
++
++#define DW_CHILDREN_no                     0x00
++#define DW_CHILDREN_yes                    0x01
++
++#define DW_ADDR_none          0
++
++/* Source language names and codes.  */
++ENUM(dwarf_source_language)
++
++    DW_LANG_C89 = 0x0001 COMMA
++    DW_LANG_C = 0x0002 COMMA
++    DW_LANG_Ada83 = 0x0003 COMMA
++    DW_LANG_C_plus_plus = 0x0004 COMMA
++    DW_LANG_Cobol74 = 0x0005 COMMA
++    DW_LANG_Cobol85 = 0x0006 COMMA
++    DW_LANG_Fortran77 = 0x0007 COMMA
++    DW_LANG_Fortran90 = 0x0008 COMMA
++    DW_LANG_Pascal83 = 0x0009 COMMA
++    DW_LANG_Modula2 = 0x000a COMMA
++    DW_LANG_Java = 0x000b COMMA
++    /* DWARF 3.  */
++    DW_LANG_C99 = 0x000c COMMA
++    DW_LANG_Ada95 = 0x000d COMMA
++    DW_LANG_Fortran95 = 0x000e COMMA
++    /* MIPS.  */
++    DW_LANG_Mips_Assembler = 0x8001 COMMA
++    /* UPC.  */
++    DW_LANG_Upc = 0x8765
++IF_NOT_ASM(};)
++
++#define DW_LANG_lo_user 0x8000        /* Implementation-defined range start.  */
++#define DW_LANG_hi_user 0xffff        /* Implementation-defined range start.  */
++
++/* Names and codes for macro information.  */
++ENUM(dwarf_macinfo_record_type)
++
++    DW_MACINFO_define = 1 COMMA
++    DW_MACINFO_undef = 2 COMMA
++    DW_MACINFO_start_file = 3 COMMA
++    DW_MACINFO_end_file = 4 COMMA
++    DW_MACINFO_vendor_ext = 255
++IF_NOT_ASM(};)
++\f
++/* @@@ For use with GNU frame unwind information.  */
++
++#define DW_EH_PE_absptr               0x00
++#define DW_EH_PE_omit         0xff
++
++#define DW_EH_PE_uleb128      0x01
++#define DW_EH_PE_udata2               0x02
++#define DW_EH_PE_udata4               0x03
++#define DW_EH_PE_udata8               0x04
++#define DW_EH_PE_sleb128      0x09
++#define DW_EH_PE_sdata2               0x0A
++#define DW_EH_PE_sdata4               0x0B
++#define DW_EH_PE_sdata8               0x0C
++#define DW_EH_PE_signed               0x08
++
++#define DW_EH_PE_pcrel                0x10
++#define DW_EH_PE_textrel      0x20
++#define DW_EH_PE_datarel      0x30
++#define DW_EH_PE_funcrel      0x40
++#define DW_EH_PE_aligned      0x50
++
++#define DW_EH_PE_indirect     0x80
++
++#endif /* _ELF_DWARF2_H */
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/include/linux/dwarf2-lang.h     2003-10-05 00:33:38.000000000 -0700
+@@ -0,0 +1,132 @@
++#ifndef DWARF2_LANG
++#define DWARF2_LANG
++#include <linux/dwarf2.h>
++
++/*
++ * This is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU General Public License as published by the Free
++ * Software Foundation; either version 2, or (at your option) any later
++ * version.
++ */
++/*
++ * This file defines macros that allow generation of DWARF debug records
++ * for asm files.  This file is platform independent.  Register numbers
++ * (which are about the only thing that is platform dependent) are to be
++ * supplied by a platform defined file.
++ */
++#define DWARF_preamble()      .section        .debug_frame,"",@progbits
++/*
++ * This macro starts a debug frame section.  The debug_frame describes
++ * where to find the registers that the enclosing function saved on
++ * entry.
++ *
++ * ORD is use by the label generator and should be the same as what is
++ * passed to CFI_postamble.
++ *
++ * pc,        pc register gdb ordinal.
++ *
++ * code_align this is the factor used to define locations or regions
++ * where the given definitions apply.  If you use labels to define these
++ * this should be 1.
++ *
++ * data_align this is the factor used to define register offsets.  If
++ * you use struct offset, this should be the size of the register in
++ * bytes or the negative of that.  This is how it is used: you will
++ * define a register as the reference register, say the stack pointer,
++ * then you will say where a register is located relative to this
++ * reference registers value, say 40 for register 3 (the gdb register
++ * number).  The <40> will be multiplied by <data_align> to define the
++ * byte offset of the given register (3, in this example).  So if your
++ * <40> is the byte offset and the reference register points at the
++ * begining, you would want 1 for the data_offset.  If <40> was the 40th
++ * 4-byte element in that structure you would want 4.  And if your
++ * reference register points at the end of the structure you would want
++ * a negative data_align value(and you would have to do other math as
++ * well).
++ */
++
++#define CFI_preamble(ORD, pc, code_align, data_align) \
++.section      .debug_frame,"",@progbits ;             \
++frame/**/_/**/ORD:                                            \
++      .long end/**/_/**/ORD-start/**/_/**/ORD;                        \
++start/**/_/**/ORD:                                            \
++      .long   DW_CIE_ID;                              \
++      .byte   DW_CIE_VERSION;                 \
++      .byte 0  ;                              \
++      .uleb128 code_align;                            \
++      .sleb128 data_align;                            \
++      .byte pc;
++
++/*
++ * After the above macro and prior to the CFI_postamble, you need to
++ * define the initial state.  This starts with defining the reference
++ * register and, usually the pc.  Here are some helper macros:
++ */
++
++#define CFA_define_reference(reg, offset)     \
++      .byte DW_CFA_def_cfa;                   \
++      .uleb128 reg;                           \
++      .uleb128 (offset);
++
++#define CFA_define_offset(reg, offset)                \
++      .byte (DW_CFA_offset + reg);            \
++      .uleb128 (offset);
++
++#define CFI_postamble(ORD)                    \
++      .align 4;                               \
++end/**/_/**/ORD:
++/*
++ * So now your code pushs stuff on the stack, you need a new location
++ * and the rules for what to do.  This starts a running description of
++ * the call frame.  You need to describe what changes with respect to
++ * the call registers as the location of the pc moves through the code.
++ * The following builds an FDE (fram descriptor entry?).  Like the
++ * above, it has a preamble and a postamble.  It also is tied to the CFI
++ * above.
++ * The first entry after the preamble must be the location in the code
++ * that the call frame is being described for.
++ */
++#define FDE_preamble(ORD, fde_no, initial_address, length)    \
++      .long FDE_end/**/_/**/fde_no-FDE_start/**/_/**/fde_no;          \
++FDE_start/**/_/**/fde_no:                                             \
++      .long frame/**/_/**/ORD;                                        \
++      .long initial_address;                                  \
++      .long length;
++
++#define FDE_postamble(fde_no)                 \
++      .align 4;                               \
++FDE_end/**/_/**/fde_no:
++/*
++ * That done, you can now add registers, subtract registers, move the
++ * reference and even change the reference.  You can also define a new
++ * area of code the info applies to.  For discontinuous bits you should
++ * start a new FDE.  You may have as many as you like.
++ */
++
++/*
++ * To advance the address by <bytes>
++ */
++
++#define FDE_advance(bytes)                    \
++      .byte DW_CFA_advance_loc4               \
++      .long bytes
++
++
++
++/*
++ * With the above you can define all the register locations.  But
++ * suppose the reference register moves... Takes the new offset NOT an
++ * increment.  This is how esp is tracked if it is not saved.
++ */
++
++#define CFA_define_cfa_offset(offset) \
++      .byte $DW_CFA_def_cfa_offset; \
++      .uleb128 (offset);
++/*
++ * Or suppose you want to use a different reference register...
++ */
++#define CFA_define_cfa_register(reg)          \
++      .byte DW_CFA_def_cfa_register;          \
++      .uleb128 reg;
++
++#endif
+--- linux-2.6.0-test6/include/linux/efi.h      2003-08-08 22:55:14.000000000 -0700
++++ 25/include/linux/efi.h     2003-10-05 00:36:22.000000000 -0700
+@@ -16,6 +16,8 @@
+ #include <linux/time.h>
+ #include <linux/types.h>
+ #include <linux/proc_fs.h>
++#include <linux/rtc.h>
++#include <linux/ioport.h>
+ #include <asm/page.h>
+ #include <asm/system.h>
+@@ -89,6 +91,11 @@ typedef     struct {
+ #define EFI_PAGE_SHIFT                12
++/*
++ * For current x86 implementations of EFI, there is
++ * additional padding in the mem descriptors.  This is not
++ * the case in ia64.  Need to have this fixed in the f/w.
++ */
+ typedef struct {
+       u32 type;
+       u32 pad;
+@@ -96,6 +103,9 @@ typedef struct {
+       u64 virt_addr;
+       u64 num_pages;
+       u64 attribute;
++#if defined (__i386__)
++      u64 pad1;
++#endif
+ } efi_memory_desc_t;
+ typedef int efi_freemem_callback_t (unsigned long start, unsigned long end, void *arg);
+@@ -132,6 +142,7 @@ typedef struct {
+  */
+ #define EFI_RESET_COLD 0
+ #define EFI_RESET_WARM 1
++#define EFI_RESET_SHUTDOWN 2
+ /*
+  * EFI Runtime Services table
+@@ -169,6 +180,10 @@ typedef efi_status_t efi_set_variable_t 
+ typedef efi_status_t efi_get_next_high_mono_count_t (u32 *count);
+ typedef void efi_reset_system_t (int reset_type, efi_status_t status,
+                                unsigned long data_size, efi_char16_t *data);
++typedef efi_status_t efi_set_virtual_address_map_t (unsigned long memory_map_size,
++                                              unsigned long descriptor_size,
++                                              u32 descriptor_version,
++                                              efi_memory_desc_t *virtual_map);
+ /*
+  *  EFI Configuration Table and GUID definitions
+@@ -194,6 +209,9 @@ typedef void efi_reset_system_t (int res
+ #define HCDP_TABLE_GUID       \
+     EFI_GUID(  0xf951938d, 0x620b, 0x42ef, 0x82, 0x79, 0xa8, 0x4b, 0x79, 0x61, 0x78, 0x98 )
++#define UGA_IO_PROTOCOL_GUID \
++    EFI_GUID(  0x61a4d49e, 0x6f68, 0x4f1b, 0xb9, 0x22, 0xa8, 0x6e, 0xed, 0xb, 0x7, 0xa2 )
++
+ typedef struct {
+       efi_guid_t guid;
+       unsigned long table;
+@@ -218,6 +236,13 @@ typedef struct {
+       unsigned long tables;
+ } efi_system_table_t;
++struct efi_memory_map {
++      efi_memory_desc_t *phys_map;
++      efi_memory_desc_t *map;
++      int nr_map;
++      unsigned long desc_version;
++};
++
+ /*
+  * All runtime access to EFI goes through this structure:
+  */
+@@ -230,6 +255,7 @@ extern struct efi {
+       void *sal_systab;               /* SAL system table */
+       void *boot_info;                /* boot info table */
+       void *hcdp;                     /* HCDP table */
++      void *uga;                      /* UGA table */
+       efi_get_time_t *get_time;
+       efi_set_time_t *set_time;
+       efi_get_wakeup_time_t *get_wakeup_time;
+@@ -239,6 +265,7 @@ extern struct efi {
+       efi_set_variable_t *set_variable;
+       efi_get_next_high_mono_count_t *get_next_high_mono_count;
+       efi_reset_system_t *reset_system;
++      efi_set_virtual_address_map_t *set_virtual_address_map;
+ } efi;
+ static inline int
+@@ -260,12 +287,18 @@ efi_guid_unparse(efi_guid_t *guid, char 
+ extern void efi_init (void);
+ extern void efi_map_pal_code (void);
++extern void efi_map_memmap(void);
+ extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg);
+ extern void efi_gettimeofday (struct timespec *ts);
+ extern void efi_enter_virtual_mode (void);    /* switch EFI to virtual mode, if possible */
+ extern u64 efi_get_iobase (void);
+ extern u32 efi_mem_type (unsigned long phys_addr);
+ extern u64 efi_mem_attributes (unsigned long phys_addr);
++extern void efi_initialize_iomem_resources(struct resource *code_resource,
++                                      struct resource *data_resource);
++extern efi_status_t phys_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc);
++extern struct efi_memory_map memmap;
++extern int efi_enabled;
+ /*
+  * Variable Attributes
+--- linux-2.6.0-test6/include/linux/eisa.h     2003-09-27 18:57:47.000000000 -0700
++++ 25/include/linux/eisa.h    2003-10-05 00:36:11.000000000 -0700
+@@ -4,16 +4,6 @@
+ #include <linux/ioport.h>
+ #include <linux/device.h>
+-#ifdef CONFIG_EISA
+-# ifdef CONFIG_EISA_ALWAYS
+-#  define EISA_bus 1
+-# else
+-   extern int EISA_bus;
+-# endif
+-#else
+-# define EISA_bus 0
+-#endif
+-
+ #define EISA_SIG_LEN   8
+ #define EISA_MAX_SLOTS 8
+@@ -108,4 +98,10 @@ struct eisa_root_device {
+ int eisa_root_register (struct eisa_root_device *root);
++#ifdef CONFIG_EISA
++extern int EISA_bus;
++#else
++# define EISA_bus 0
++#endif
++
+ #endif
+--- linux-2.6.0-test6/include/linux/elevator.h 2003-09-27 18:57:47.000000000 -0700
++++ 25/include/linux/elevator.h        2003-10-05 00:34:17.000000000 -0700
+@@ -94,6 +94,11 @@ extern elevator_t iosched_deadline;
+  */
+ extern elevator_t iosched_as;
++/*
++ * completely fair queueing I/O scheduler
++ */
++extern elevator_t iosched_cfq;
++
+ extern int elevator_init(request_queue_t *, elevator_t *);
+ extern void elevator_exit(request_queue_t *);
+ extern inline int elv_rq_merge_ok(struct request *, struct bio *);
+--- linux-2.6.0-test6/include/linux/elf.h      2003-09-27 18:57:47.000000000 -0700
++++ 25/include/linux/elf.h     2003-10-05 00:33:24.000000000 -0700
+@@ -395,6 +395,7 @@ typedef struct elf64_shdr {
+ #define NT_PRFPREG    2
+ #define NT_PRPSINFO   3
+ #define NT_TASKSTRUCT 4
++#define NT_AUXV               6
+ #define NT_PRXFPREG     0x46e62b7f      /* copied from gdb5.1/include/elf/common.h */
+--- linux-2.6.0-test6/include/linux/errno.h    2003-06-26 22:07:26.000000000 -0700
++++ 25/include/linux/errno.h   2003-10-05 00:36:54.000000000 -0700
+@@ -22,6 +22,7 @@
+ #define EBADTYPE      527     /* Type not supported by server */
+ #define EJUKEBOX      528     /* Request initiated, but will not complete before timeout */
+ #define EIOCBQUEUED   529     /* iocb queued, will get completion event */
++#define EIOCBRETRY    530     /* iocb queued, will trigger a retry */
+ #endif
+--- linux-2.6.0-test6/include/linux/ext3_fs_i.h        2003-07-10 18:50:32.000000000 -0700
++++ 25/include/linux/ext3_fs_i.h       2003-10-05 00:36:12.000000000 -0700
+@@ -106,7 +106,7 @@ struct ext3_inode_info {
+        * during recovery.  Hence we must fix the get_block-vs-truncate race
+        * by other means, so we have truncate_sem.
+        */
+-      struct rw_semaphore truncate_sem;
++      struct semaphore truncate_sem;
+       struct inode vfs_inode;
+ };
+--- linux-2.6.0-test6/include/linux/fb.h       2003-06-14 12:18:06.000000000 -0700
++++ 25/include/linux/fb.h      2003-10-05 00:34:22.000000000 -0700
+@@ -2,7 +2,6 @@
+ #define _LINUX_FB_H
+ #include <linux/tty.h>
+-#include <linux/workqueue.h>
+ #include <asm/types.h>
+ #include <asm/io.h>
+@@ -326,28 +325,38 @@ struct fb_cursor {
+       struct fb_image image;  /* Cursor image */
+ };
++#ifdef __KERNEL__
++
++#include <linux/fs.h>
++#include <linux/init.h>
++#include <linux/workqueue.h>
++#include <linux/devfs_fs_kernel.h>
++
++/*
++ * The purpose of this structure is to translate data
++ * from the hardwre independent format of fbdev to what
++ * format the hardware needs.
++ */
++
+ #define FB_PIXMAP_DEFAULT 1     /* used internally by fbcon */
+ #define FB_PIXMAP_SYSTEM  2     /* memory is in system RAM  */
+ #define FB_PIXMAP_IO      4     /* memory is iomapped       */
+ #define FB_PIXMAP_SYNC    256   /* set if GPU can DMA       */
+ struct fb_pixmap {
+-        __u8  *addr;                      /* pointer to memory             */  
+-      __u32 size;                       /* size of buffer in bytes       */
+-      __u32 offset;                     /* current offset to buffer      */
+-      __u32 buf_align;                  /* byte alignment of each bitmap */
+-      __u32 scan_align;                 /* alignment per scanline        */
+-      __u32 flags;                      /* see FB_PIXMAP_*               */
+-                                        /* access methods                */
+-      void (*outbuf)(u8 *dst, u8 *addr, unsigned int size); 
+-      u8   (*inbuf) (u8 *addr);
+-      spinlock_t lock;                  /* spinlock                      */
++      u8  *addr;              /* pointer to memory                    */
++      u32 size;               /* size of buffer in bytes              */
++      u32 offset;             /* current offset to buffer             */
++      u32 buf_align;          /* byte alignment of each bitmap        */
++      u32 scan_align;         /* alignment per scanline               */
++      u32 access_align;       /* alignment per read/write             */
++      u32 flags;              /* see FB_PIXMAP_*                      */
++      spinlock_t lock;        /* spinlock                             */
+       atomic_t count;
++      /* access methods */
++      void (*outbuf)(u8 *addr, u8 *dst, unsigned int size);
++      u8   (*inbuf) (u8 *addr);
+ };
+-#ifdef __KERNEL__
+-
+-#include <linux/fs.h>
+-#include <linux/init.h>
+ struct fb_info;
+ struct vm_area_struct;
+@@ -396,24 +405,24 @@ struct fb_ops {
+ };
+ struct fb_info {
+-   int node;
+-   int flags;
+-   int open;                            /* Has this been open already ? */
++      int node;
++      int flags;
+ #define FBINFO_FLAG_MODULE    1       /* Low-level driver is a module */
+-   struct fb_var_screeninfo var;        /* Current var */
+-   struct fb_fix_screeninfo fix;        /* Current fix */
+-   struct fb_monspecs monspecs;         /* Current Monitor specs */
+-   struct fb_cursor cursor;           /* Current cursor */    
+-   struct work_struct queue;          /* Framebuffer event queue */
+-   struct fb_pixmap pixmap;           /* Current pixmap */
+-   struct fb_cmap cmap;                 /* Current cmap */
+-   struct fb_ops *fbops;
+-   char *screen_base;                   /* Virtual address */
+-   struct vc_data *display_fg;                /* Console visible on this display */
+-   int currcon;                               /* Current VC. */       
+-   void *pseudo_palette;                /* Fake palette of 16 colors */ 
+-   /* From here on everything is device dependent */
+-   void *par; 
++      struct fb_var_screeninfo var;   /* Current var */
++      struct fb_fix_screeninfo fix;   /* Current fix */
++      struct fb_monspecs monspecs;    /* Current Monitor specs */
++      struct fb_cursor cursor;        /* Current cursor */
++      struct work_struct queue;       /* Framebuffer event queue */
++      struct fb_pixmap pixmap;        /* Image HW mapper */
++      struct fb_pixmap sprite;        /* Cursor HW mapper */
++      struct fb_cmap cmap;            /* Current cmap */
++      struct fb_ops *fbops;
++      char *screen_base;              /* Virtual address */
++      struct vc_data *display_fg;     /* Console visible on this display */
++      void *pseudo_palette;           /* Fake palette of 16 colors */
++      int currcon;                    /* Current VC. */
++      /* From here on everything is device dependent */
++      void *par;
+ };
+ #ifdef MODULE
+@@ -481,12 +490,12 @@ extern int register_framebuffer(struct f
+ extern int unregister_framebuffer(struct fb_info *fb_info);
+ extern int fb_prepare_logo(struct fb_info *fb_info);
+ extern int fb_show_logo(struct fb_info *fb_info);
+-extern u32 fb_get_buffer_offset(struct fb_info *info, u32 size);
+-extern void move_buf_unaligned(struct fb_info *info, u8 *dst, u8 *src, u32 d_pitch,
+-                              u32 height, u32 mask, u32 shift_high, u32 shift_low,
++extern char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size);
++extern void move_buf_unaligned(struct fb_info *info, struct fb_pixmap *buf, u8 *dst, u8 *src,
++                              u32 d_pitch, u32 height, u32 mask, u32 shift_high, u32 shift_low,
+                               u32 mod, u32 idx);
+-extern void move_buf_aligned(struct fb_info *info, u8 *dst, u8 *src, u32 d_pitch,
+-                           u32 s_pitch, u32 height);
++extern void move_buf_aligned(struct fb_info *info, struct fb_pixmap *buf, u8 *dst, u8 *src,
++                           u32 d_pitch, u32 s_pitch, u32 height);
+ extern struct fb_info *registered_fb[FB_MAX];
+ extern int num_registered_fb;
+--- linux-2.6.0-test6/include/linux/fs.h       2003-09-27 18:57:47.000000000 -0700
++++ 25/include/linux/fs.h      2003-10-05 00:37:00.000000000 -0700
+@@ -388,6 +388,7 @@ struct inode {
+       unsigned short          i_bytes;
+       spinlock_t              i_lock; /* i_blocks, i_bytes, maybe i_size */
+       struct semaphore        i_sem;
++      struct rw_semaphore     i_alloc_sem;
+       struct inode_operations *i_op;
+       struct file_operations  *i_fop; /* former ->i_op->default_file_ops */
+       struct super_block      *i_sb;
+@@ -480,6 +481,8 @@ static inline unsigned imajor(struct ino
+       return MAJOR(inode->i_rdev);
+ }
++extern struct block_device *I_BDEV(struct inode *inode);
++
+ struct fown_struct {
+       rwlock_t lock;          /* protects pid, uid, euid fields */
+       int pid;                /* pid or -pgrp where SIGIO should be sent */
+@@ -526,6 +529,7 @@ struct file {
+       /* Used by fs/eventpoll.c to link all the hooks to this file */
+       struct list_head        f_ep_links;
+       spinlock_t              f_ep_lock;
++      struct address_space    *f_mapping;
+ };
+ extern spinlock_t files_lock;
+ #define file_list_lock() spin_lock(&files_lock);
+@@ -749,6 +753,11 @@ extern int vfs_rename(struct inode *, st
+ #define DT_SOCK               12
+ #define DT_WHT                14
++#define OSYNC_METADATA        (1<<0)
++#define OSYNC_DATA    (1<<1)
++#define OSYNC_INODE   (1<<2)
++int generic_osync_inode(struct inode *, struct address_space *, int);
++
+ /*
+  * This is the "filldir" function type, used by readdir() to let
+  * the kernel specify what kind of dirent layout it wants to have.
+@@ -758,9 +767,9 @@ extern int vfs_rename(struct inode *, st
+ typedef int (*filldir_t)(void *, const char *, int, loff_t, ino_t, unsigned);
+ struct block_device_operations {
+-      int (*open) (struct inode *, struct file *);
+-      int (*release) (struct inode *, struct file *);
+-      int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);
++      int (*open) (struct block_device *, struct file *);
++      int (*release) (struct gendisk *);
++      int (*ioctl) (struct block_device *, struct file *, unsigned, unsigned long);
+       int (*media_changed) (struct gendisk *);
+       int (*revalidate_disk) (struct gendisk *);
+       struct module *owner;
+@@ -1123,11 +1132,9 @@ enum {BDEV_FILE, BDEV_SWAP, BDEV_FS, BDE
+ extern int register_blkdev(unsigned int, const char *);
+ extern int unregister_blkdev(unsigned int, const char *);
+ extern struct block_device *bdget(dev_t);
+-extern int bd_acquire(struct inode *inode);
+ extern void bd_forget(struct inode *inode);
+ extern void bdput(struct block_device *);
+ extern int blkdev_open(struct inode *, struct file *);
+-extern int blkdev_close(struct inode *, struct file *);
+ extern struct block_device *open_by_devnum(dev_t, unsigned, int);
+ extern struct file_operations def_blk_fops;
+ extern struct address_space_operations def_blk_aops;
+@@ -1135,7 +1142,7 @@ extern struct file_operations def_chr_fo
+ extern struct file_operations bad_sock_fops;
+ extern struct file_operations def_fifo_fops;
+ extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long);
+-extern int blkdev_ioctl(struct inode *, struct file *, unsigned, unsigned long);
++extern int blkdev_ioctl(struct block_device *, struct file *, unsigned, unsigned long);
+ extern int blkdev_get(struct block_device *, mode_t, unsigned, int);
+ extern int blkdev_put(struct block_device *, int);
+ extern int bd_claim(struct block_device *, void *);
+@@ -1202,6 +1209,7 @@ extern void write_inode_now(struct inode
+ extern int filemap_fdatawrite(struct address_space *);
+ extern int filemap_flush(struct address_space *);
+ extern int filemap_fdatawait(struct address_space *);
++extern int filemap_write_and_wait(struct address_space *mapping);
+ extern void sync_supers(void);
+ extern void sync_filesystems(int wait);
+ extern void emergency_sync(void);
+@@ -1295,8 +1303,7 @@ extern int generic_file_readonly_mmap(st
+ extern int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size);
+ extern int file_send_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size);
+ extern ssize_t generic_file_read(struct file *, char __user *, size_t, loff_t *);
+-int generic_write_checks(struct inode *inode, struct file *file,
+-                      loff_t *pos, size_t *count, int isblk);
++int generic_write_checks(struct file *file, loff_t *pos, size_t *count, int isblk);
+ extern ssize_t generic_file_write(struct file *, const char __user *, size_t, loff_t *);
+ extern ssize_t generic_file_aio_read(struct kiocb *, char __user *, size_t, loff_t);
+ extern ssize_t __generic_file_aio_read(struct kiocb *, const struct iovec *, unsigned long, loff_t *);
+@@ -1314,9 +1321,6 @@ 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 int blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, 
+-      struct block_device *bdev, const struct iovec *iov, loff_t offset, 
+-      unsigned long nr_segs, get_blocks_t *get_blocks, dio_iodone_t *end_io);
+ 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, 
+@@ -1330,7 +1334,7 @@ static inline void do_generic_file_read(
+                                       read_descriptor_t * desc,
+                                       read_actor_t actor)
+ {
+-      do_generic_mapping_read(filp->f_dentry->d_inode->i_mapping,
++      do_generic_mapping_read(filp->f_mapping,
+                               &filp->f_ra,
+                               filp,
+                               ppos,
+@@ -1338,6 +1342,32 @@ static inline void do_generic_file_read(
+                               actor);
+ }
++int __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
++      struct block_device *bdev, const struct iovec *iov, loff_t offset,
++      unsigned long nr_segs, get_blocks_t get_blocks, dio_iodone_t end_io,
++      int needs_special_locking);
++
++/*
++ * For filesystems which need locking between buffered and direct access
++ */
++static inline int blockdev_direct_IO(int rw, struct kiocb *iocb,
++      struct inode *inode, struct block_device *bdev, const struct iovec *iov,
++      loff_t offset, unsigned long nr_segs, get_blocks_t get_blocks,
++      dio_iodone_t end_io)
++{
++      return __blockdev_direct_IO(rw, iocb, inode, bdev, iov, offset,
++                              nr_segs, get_blocks, end_io, 1);
++}
++
++static inline int blockdev_direct_IO_no_locking(int rw, struct kiocb *iocb,
++      struct inode *inode, struct block_device *bdev, const struct iovec *iov,
++      loff_t offset, unsigned long nr_segs, get_blocks_t get_blocks,
++      dio_iodone_t end_io)
++{
++      return __blockdev_direct_IO(rw, iocb, inode, bdev, iov, offset,
++                              nr_segs, get_blocks, end_io, 0);
++}
++
+ extern struct file_operations generic_ro_fops;
+ #define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m))
+--- linux-2.6.0-test6/include/linux/ftape.h    2003-09-27 18:57:47.000000000 -0700
++++ 25/include/linux/ftape.h   2003-10-05 00:33:24.000000000 -0700
+@@ -35,7 +35,6 @@
+ #include <linux/mm.h>
+ #endif
+ #include <linux/types.h>
+-#include <linux/version.h>
+ #include <linux/config.h>
+ #include <linux/mtio.h>
+--- linux-2.6.0-test6/include/linux/hdlcdrv.h  2003-09-27 18:57:47.000000000 -0700
++++ 25/include/linux/hdlcdrv.h 2003-10-05 00:33:24.000000000 -0700
+@@ -359,11 +359,11 @@ static inline int hdlcdrv_ptt(struct hdl
+ void hdlcdrv_receiver(struct net_device *, struct hdlcdrv_state *);
+ void hdlcdrv_transmitter(struct net_device *, struct hdlcdrv_state *);
+ void hdlcdrv_arbitrate(struct net_device *, struct hdlcdrv_state *);
+-int hdlcdrv_register_hdlcdrv(struct net_device *dev, const struct hdlcdrv_ops *ops,
+-                           unsigned int privsize, char *ifname,
+-                           unsigned int baseaddr, unsigned int irq, 
+-                           unsigned int dma);
+-int hdlcdrv_unregister_hdlcdrv(struct net_device *dev);
++struct net_device *hdlcdrv_register(const struct hdlcdrv_ops *ops,
++                                  unsigned int privsize, const char *ifname,
++                                  unsigned int baseaddr, unsigned int irq, 
++                                  unsigned int dma);
++void hdlcdrv_unregister(struct net_device *dev);
+ /* -------------------------------------------------------------------- */
+--- linux-2.6.0-test6/include/linux/hfs_fs.h   2003-07-10 18:50:32.000000000 -0700
++++ 25/include/linux/hfs_fs.h  2003-10-05 00:33:24.000000000 -0700
+@@ -267,9 +267,9 @@ extern void hfs_nat_drop_dentry(struct d
+ /* file.c */
+ extern hfs_s32 hfs_do_read(struct inode *, struct hfs_fork *, hfs_u32,
+-                         char *, hfs_u32);
++                         char __user *, hfs_u32);
+ extern hfs_s32 hfs_do_write(struct inode *, struct hfs_fork *, hfs_u32,
+-                          const char *, hfs_u32);
++                          const char __user *, hfs_u32);
+ extern void hfs_file_fix_mode(struct hfs_cat_entry *entry);
+ extern struct inode_operations hfs_file_inode_operations;
+ extern struct file_operations hfs_file_operations;
+--- linux-2.6.0-test6/include/linux/highuid.h  2003-06-14 12:18:23.000000000 -0700
++++ 25/include/linux/highuid.h 2003-10-05 00:33:24.000000000 -0700
+@@ -56,6 +56,8 @@ extern int overflowgid;
+ #define SET_GID16(var, gid)   var = high2lowgid(gid)
+ #define NEW_TO_OLD_UID(uid)   high2lowuid(uid)
+ #define NEW_TO_OLD_GID(gid)   high2lowgid(gid)
++#define OLD_TO_NEW_UID(uid)   low2highuid(uid)
++#define OLD_TO_NEW_GID(gid)   low2highgid(gid)
+ /* specific to fs/stat.c */
+ #define SET_OLDSTAT_UID(stat, uid)    (stat).st_uid = high2lowuid(uid)
+@@ -69,6 +71,8 @@ extern int overflowgid;
+ #define SET_GID16(var, gid)   do { ; } while (0)
+ #define NEW_TO_OLD_UID(uid)   (uid)
+ #define NEW_TO_OLD_GID(gid)   (gid)
++#define OLD_TO_NEW_UID(uid)   (uid)
++#define OLD_TO_NEW_GID(gid)   (gid)
+ #define SET_OLDSTAT_UID(stat, uid)    (stat).st_uid = (uid)
+ #define SET_OLDSTAT_GID(stat, gid)    (stat).st_gid = (gid)
+--- linux-2.6.0-test6/include/linux/init_task.h        2003-08-22 19:23:42.000000000 -0700
++++ 25/include/linux/init_task.h       2003-10-05 00:36:54.000000000 -0700
+@@ -108,6 +108,7 @@
+       .proc_lock      = SPIN_LOCK_UNLOCKED,                           \
+       .switch_lock    = SPIN_LOCK_UNLOCKED,                           \
+       .journal_info   = NULL,                                         \
++      .io_wait        = NULL,                                         \
+ }
+--- linux-2.6.0-test6/include/linux/input.h    2003-09-27 18:57:47.000000000 -0700
++++ 25/include/linux/input.h   2003-10-05 00:34:14.000000000 -0700
+@@ -870,6 +870,7 @@ struct input_handler {
+       char *name;
+       struct input_device_id *id_table;
++      struct input_device_id *blacklist;
+       struct list_head        h_list;
+       struct list_head        node;
+--- linux-2.6.0-test6/include/linux/istallion.h        2003-06-14 12:18:01.000000000 -0700
++++ 25/include/linux/istallion.h       2003-10-05 00:33:24.000000000 -0700
+@@ -21,6 +21,8 @@
+  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+  */
++#include <linux/version.h>
++
+ /*****************************************************************************/
+ #ifndef       _ISTALLION_H
+ #define       _ISTALLION_H
+--- linux-2.6.0-test6/include/linux/linux_logo.h       2003-06-14 12:18:05.000000000 -0700
++++ 25/include/linux/linux_logo.h      2003-10-05 00:34:22.000000000 -0700
+@@ -16,13 +16,11 @@
+ #include <linux/init.h>
+-
+ #define LINUX_LOGO_MONO               1       /* monochrome black/white */
+ #define LINUX_LOGO_VGA16      2       /* 16 colors VGA text palette */
+ #define LINUX_LOGO_CLUT224    3       /* 224 colors */
+ #define LINUX_LOGO_GRAY256    4       /* 256 levels grayscale */
+-
+ struct linux_logo {
+       int type;                       /* one of LINUX_LOGO_* */
+       unsigned int width;
+@@ -32,6 +30,6 @@ struct linux_logo {
+       const unsigned char *data;
+ };
+-extern const struct linux_logo *fb_find_logo(int depth);
++extern const struct linux_logo *find_logo(int depth);
+ #endif /* _LINUX_LINUX_LOGO_H */
+--- linux-2.6.0-test6/include/linux/list.h     2003-06-26 22:07:26.000000000 -0700
++++ 25/include/linux/list.h    2003-10-05 00:36:37.000000000 -0700
+@@ -142,8 +142,11 @@ static inline void __list_del(struct lis
+  * Note: list_empty on entry does not return true after this, the entry is
+  * in an undefined state.
+  */
++#include <linux/kernel.h>     /* BUG_ON */
+ static inline void list_del(struct list_head *entry)
+ {
++      BUG_ON(entry->prev->next != entry);
++      BUG_ON(entry->next->prev != entry);
+       __list_del(entry->prev, entry->next);
+       entry->next = LIST_POISON1;
+       entry->prev = LIST_POISON2;
+@@ -325,6 +328,19 @@ static inline void list_splice_init(stru
+            pos = list_entry(pos->member.prev, typeof(*pos), member),  \
+                    prefetch(pos->member.prev))
++/**
++ * list_for_each_entry_continue -     iterate over list of given type
++ *                    continuing after existing point
++ * @pos:      the type * to use as a loop counter.
++ * @head:     the head for your list.
++ * @member:   the name of the list_struct within the struct.
++ */
++#define list_for_each_entry_continue(pos, head, member)               \
++      for (pos = list_entry(pos->member.next, typeof(*pos), member),  \
++                   prefetch(pos->member.next);                        \
++           &pos->member != (head);                                    \
++           pos = list_entry(pos->member.next, typeof(*pos), member),  \
++                   prefetch(pos->member.next))
+ /**
+  * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+@@ -436,7 +452,7 @@ static __inline__ void hlist_del(struct 
+ /**
+  * hlist_del_rcu - deletes entry from hash list without re-initialization
+- * @entry: the element to delete from the hash list.
++ * @n: the element to delete from the hash list.
+  *
+  * Note: list_unhashed() on entry does not return true after this, 
+  * the entry is in an undefined state. It is useful for RCU based
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/include/linux/lockmeter.h       2003-10-05 00:36:40.000000000 -0700
+@@ -0,0 +1,320 @@
++/*
++ *  Copyright (C) 1999-2002 Silicon Graphics, Inc.
++ *
++ *  Written by John Hawkes (hawkes@sgi.com)
++ *  Based on klstat.h by Jack Steiner (steiner@sgi.com)
++ *
++ *  Modified by Ray Bryant (raybry@us.ibm.com) Feb-Apr 2000
++ *  Changes Copyright (C) 2000 IBM, Inc.
++ *  Added save of index in spinlock_t to improve efficiency
++ *  of "hold" time reporting for spinlocks
++ *  Added support for hold time statistics for read and write
++ *  locks.
++ *  Moved machine dependent code to include/asm/lockmeter.h.
++ *
++ */
++
++#ifndef _LINUX_LOCKMETER_H
++#define _LINUX_LOCKMETER_H
++
++
++/*---------------------------------------------------
++ *    architecture-independent lockmeter.h
++ *-------------------------------------------------*/
++
++/*
++ * raybry -- version 2: added efficient hold time statistics
++ *           requires lstat recompile, so flagged as new version
++ * raybry -- version 3: added global reader lock data
++ * hawkes -- version 4: removed some unnecessary fields to simplify mips64 port
++ */
++#define LSTAT_VERSION 5
++
++int   lstat_update(void*, void*, int);
++int   lstat_update_time(void*, void*, int, uint32_t);
++
++/*
++ * Currently, the mips64 and sparc64 kernels talk to a 32-bit lockstat, so we
++ * need to force compatibility in the inter-communication data structure.
++ */
++
++#if defined(CONFIG_MIPS32_COMPAT)
++#define TIME_T                uint32_t
++#elif defined(CONFIG_SPARC) || defined(CONFIG_SPARC64)
++#define TIME_T                uint64_t
++#else
++#define TIME_T                time_t
++#endif
++
++#if defined(__KERNEL__) || (!defined(CONFIG_MIPS32_COMPAT) && !defined(CONFIG_SPARC) && !defined(CONFIG_SPARC64)) || (_MIPS_SZLONG==32)
++#define POINTER               void *
++#else
++#define       POINTER         int64_t
++#endif
++
++/*
++ * Values for the "action" parameter passed to lstat_update.
++ *    ZZZ - do we want a try-success status here???
++ */
++#define LSTAT_ACT_NO_WAIT     0
++#define LSTAT_ACT_SPIN                1
++#define LSTAT_ACT_REJECT      2
++#define LSTAT_ACT_WW_SPIN       3
++#define LSTAT_ACT_SLEPT               4 /* UNUSED */
++
++#define LSTAT_ACT_MAX_VALUES  4 /* NOTE: Increase to 5 if use ACT_SLEPT */
++
++/*
++ * Special values for the low 2 bits of an RA passed to
++ * lstat_update.
++ */
++/* we use these values to figure out what kind of lock data */
++/* is stored in the statistics table entry at index ....... */
++#define LSTAT_RA_SPIN           0  /* spin lock data */
++#define LSTAT_RA_READ           1  /* read lock statistics */
++#define LSTAT_RA_SEMA         2  /* RESERVED */
++#define LSTAT_RA_WRITE          3  /* write lock statistics*/
++
++#define LSTAT_RA(n)   \
++      ((void*)( ((unsigned long)__builtin_return_address(0) & ~3) | n) )
++
++/*
++ * Constants used for lock addresses in the lstat_directory
++ * to indicate special values of the lock address.
++ */
++#define       LSTAT_MULTI_LOCK_ADDRESS        NULL
++
++/*
++ * Maximum size of the lockstats tables. Increase this value
++ * if its not big enough. (Nothing bad happens if its not
++ * big enough although some locks will not be monitored.)
++ * We record overflows of this quantity in lstat_control.dir_overflows
++ *
++ * Note:  The max value here must fit into the field set
++ * and obtained by the macro's PUT_INDEX() and GET_INDEX().
++ * This value depends on how many bits are available in the
++ * lock word in the particular machine implementation we are on.
++ */
++#define LSTAT_MAX_STAT_INDEX          2000
++
++/*
++ * Size and mask for the hash table into the directory.
++ */
++#define LSTAT_HASH_TABLE_SIZE         4096            /* must be 2**N */
++#define LSTAT_HASH_TABLE_MASK         (LSTAT_HASH_TABLE_SIZE-1)
++
++#define DIRHASH(ra)      ((unsigned long)(ra)>>2 & LSTAT_HASH_TABLE_MASK)
++
++/*
++ *    This defines an entry in the lockstat directory. It contains
++ *    information about a lock being monitored.
++ *    A directory entry only contains the lock identification -
++ *    counts on usage of the lock are kept elsewhere in a per-cpu
++ *    data structure to minimize cache line pinging.
++ */
++typedef struct {
++      POINTER caller_ra;                /* RA of code that set lock */
++      POINTER lock_ptr;                 /* lock address */
++      ushort  next_stat_index;  /* Used to link multiple locks that have the same hash table value */
++} lstat_directory_entry_t;
++
++/*
++ *    A multi-dimensioned array used to contain counts for lock accesses.
++ *    The array is 3-dimensional:
++ *            - CPU number. Keep from thrashing cache lines between CPUs
++ *            - Directory entry index. Identifies the lock
++ *            - Action. Indicates what kind of contention occurred on an
++ *              access to the lock.
++ *
++ *    The index of an entry in the directory is the same as the 2nd index
++ *    of the entry in the counts array.
++ */
++/*
++ *  This table contains data for spin_locks, write locks, and read locks
++ *  Not all data is used for all cases.  In particular, the hold time
++ *  information is not stored here for read locks since that is a global
++ *  (e. g. cannot be separated out by return address) quantity.
++ *  See the lstat_read_lock_counts_t structure for the global read lock
++ *  hold time.
++ */
++typedef struct {
++      uint64_t    cum_wait_ticks;     /* sum of wait times               */
++                                      /* for write locks, sum of time a  */
++                                      /* writer is waiting for a reader  */
++      int64_t     cum_hold_ticks;     /* cumulative sum of holds         */
++                                      /* not used for read mode locks    */
++                                      /* must be signed. ............... */
++      uint32_t    max_wait_ticks;     /* max waiting time                */
++      uint32_t    max_hold_ticks;     /* max holding time                */
++      uint64_t    cum_wait_ww_ticks;  /* sum times writer waits on writer*/
++      uint32_t    max_wait_ww_ticks;  /* max wait time writer vs writer  */
++                                      /* prev 2 only used for write locks*/
++      uint32_t    acquire_time;       /* time lock acquired this CPU     */
++      uint32_t    count[LSTAT_ACT_MAX_VALUES];
++} lstat_lock_counts_t;
++
++typedef lstat_lock_counts_t   lstat_cpu_counts_t[LSTAT_MAX_STAT_INDEX];
++
++/*
++ * User request to:
++ *    - turn statistic collection on/off, or to reset
++ */
++#define LSTAT_OFF      0
++#define LSTAT_ON       1
++#define LSTAT_RESET      2
++#define LSTAT_RELEASE    3
++
++#define LSTAT_MAX_READ_LOCK_INDEX 1000
++typedef struct {
++      POINTER     lock_ptr;            /* address of lock for output stats */
++      uint32_t    read_lock_count;
++      int64_t     cum_hold_ticks;       /* sum of read lock hold times over */
++                                        /* all callers. ....................*/
++      uint32_t    write_index;          /* last write lock hash table index */
++      uint32_t    busy_periods;         /* count of busy periods ended this */
++      uint64_t    start_busy;           /* time this busy period started. ..*/
++      uint64_t    busy_ticks;           /* sum of busy periods this lock. ..*/
++      uint64_t    max_busy;             /* longest busy period for this lock*/
++      uint32_t    max_readers;          /* maximum number of readers ...... */
++#ifdef USER_MODE_TESTING
++      rwlock_t    entry_lock;           /* lock for this read lock entry... */
++                                        /* avoid having more than one rdr at*/
++                                        /* needed for user space testing... */
++                                        /* not needed for kernel 'cause it  */
++                                        /* is non-preemptive. ............. */
++#endif
++} lstat_read_lock_counts_t;
++typedef lstat_read_lock_counts_t      lstat_read_lock_cpu_counts_t[LSTAT_MAX_READ_LOCK_INDEX];
++
++#if defined(__KERNEL__) || defined(USER_MODE_TESTING)
++
++#ifndef USER_MODE_TESTING
++#include <asm/lockmeter.h>
++#else
++#include "asm_newlockmeter.h"
++#endif
++
++/*
++ * Size and mask for the hash table into the directory.
++ */
++#define LSTAT_HASH_TABLE_SIZE         4096            /* must be 2**N */
++#define LSTAT_HASH_TABLE_MASK         (LSTAT_HASH_TABLE_SIZE-1)
++
++#define DIRHASH(ra)      ((unsigned long)(ra)>>2 & LSTAT_HASH_TABLE_MASK)
++
++/*
++ * This version eliminates the per processor lock stack.  What we do is to
++ * store the index of the lock hash structure in unused bits in the lock
++ * itself.  Then on unlock we can find the statistics record without doing
++ * any additional hash or lock stack lookup.  This works for spin_locks.
++ * Hold time reporting is now basically as cheap as wait time reporting
++ * so we ignore the difference between LSTAT_ON_HOLD and LSTAT_ON_WAIT
++ * as in version 1.1.* of lockmeter.
++ *
++ * For rw_locks, we store the index of a global reader stats structure in
++ * the lock and the writer index is stored in the latter structure.
++ * For read mode locks we hash at the time of the lock to find an entry
++ * in the directory for reader wait time and the like.
++ * At unlock time for read mode locks, we update just the global structure
++ * so we don't need to know the reader directory index value at unlock time.
++ *
++ */
++
++/*
++ * Protocol to change lstat_control.state
++ *   This is complicated because we don't want the cum_hold_time for
++ * a rw_lock to be decremented in _read_lock_ without making sure it
++ * is incremented in _read_lock_ and vice versa.  So here is the
++ * way we change the state of lstat_control.state:
++ * I.  To Turn Statistics On
++ *     After allocating storage, set lstat_control.state non-zero.
++ * This works because we don't start updating statistics for in use
++ * locks until the reader lock count goes to zero.
++ * II. To Turn Statistics Off:
++ * (0)  Disable interrupts on this CPU
++ * (1)  Seize the lstat_control.directory_lock
++ * (2)  Obtain the current value of lstat_control.next_free_read_lock_index
++ * (3)  Store a zero in lstat_control.state.
++ * (4)  Release the lstat_control.directory_lock
++ * (5)  For each lock in the read lock list up to the saved value
++ *      (well, -1) of the next_free_read_lock_index, do the following:
++ *      (a)  Check validity of the stored lock address
++ *           by making sure that the word at the saved addr
++ *           has an index that matches this entry.  If not
++ *           valid, then skip this entry.
++ *      (b)  If there is a write lock already set on this lock,
++ *           skip to (d) below.
++ *      (c)  Set a non-metered write lock on the lock
++ *      (d)  set the cached INDEX in the lock to zero
++ *      (e)  Release the non-metered write lock.
++ * (6)  Re-enable interrupts
++ *
++ * These rules ensure that a read lock will not have its statistics
++ * partially updated even though the global lock recording state has
++ * changed.  See put_lockmeter_info() for implementation.
++ *
++ * The reason for (b) is that there may be write locks set on the
++ * syscall path to put_lockmeter_info() from user space.  If we do
++ * not do this check, then we can deadlock.  A similar problem would
++ * occur if the lock was read locked by the current CPU.  At the
++ * moment this does not appear to happen.
++ */
++
++/*
++ * Main control structure for lockstat. Used to turn statistics on/off
++ * and to maintain directory info.
++ */
++typedef struct {
++      int                             state;
++      spinlock_t              control_lock;           /* used to serialize turning statistics on/off   */
++      spinlock_t              directory_lock;         /* for serialize adding entries to directory     */
++      volatile int    next_free_dir_index;/* next free entry in the directory */
++      /* FIXME not all of these fields are used / needed .............. */
++                /* the following fields represent data since     */
++              /* first "lstat on" or most recent "lstat reset" */
++      TIME_T      first_started_time;     /* time when measurement first enabled */
++      TIME_T      started_time;           /* time when measurement last started  */
++      TIME_T      ending_time;            /* time when measurement last disabled */
++      uint64_t    started_cycles64;       /* cycles when measurement last started          */
++      uint64_t    ending_cycles64;        /* cycles when measurement last disabled         */
++      uint64_t    enabled_cycles64;       /* total cycles with measurement enabled         */
++      int         intervals;              /* number of measurement intervals recorded      */
++                                          /* i. e. number of times did lstat on;lstat off  */
++      lstat_directory_entry_t *dir;           /* directory */
++      int         dir_overflow;           /* count of times ran out of space in directory  */
++      int         rwlock_overflow;        /* count of times we couldn't allocate a rw block*/
++      ushort          *hashtab;                           /* hash table for quick dir scans */
++      lstat_cpu_counts_t      *counts[NR_CPUS];        /* Array of pointers to per-cpu stats */
++    int         next_free_read_lock_index;   /* next rwlock reader (global) stats block  */
++    lstat_read_lock_cpu_counts_t *read_lock_counts[NR_CPUS]; /* per cpu read lock stats  */
++} lstat_control_t;
++
++#endif        /* defined(__KERNEL__) || defined(USER_MODE_TESTING) */
++
++typedef struct {
++      short           lstat_version;          /* version of the data */
++      short           state;                  /* the current state is returned */
++      int             maxcpus;                /* Number of cpus present */
++      int             next_free_dir_index;    /* index of the next free directory entry */
++      TIME_T          first_started_time;     /* when measurement enabled for first time */
++      TIME_T          started_time;           /* time in secs since 1969 when stats last turned on  */
++      TIME_T          ending_time;            /* time in secs since 1969 when stats last turned off */
++      uint32_t        cycleval;               /* cycles per second */
++#ifdef notyet
++      void            *kernel_magic_addr;     /* address of kernel_magic */
++      void            *kernel_end_addr;       /* contents of kernel magic (points to "end") */
++#endif
++      int              next_free_read_lock_index; /* index of next (global) read lock stats struct */
++      uint64_t         started_cycles64;      /* cycles when measurement last started        */
++      uint64_t         ending_cycles64;       /* cycles when stats last turned off           */
++      uint64_t         enabled_cycles64;      /* total cycles with measurement enabled       */
++      int              intervals;             /* number of measurement intervals recorded      */
++                                              /* i.e. number of times we did lstat on;lstat off*/
++      int              dir_overflow;          /* number of times we wanted more space in directory */
++      int              rwlock_overflow;       /* # of times we wanted more space in read_locks_count */
++      struct new_utsname   uts;               /* info about machine where stats are measured */
++                                              /* -T option of lockstat allows data to be     */
++                                              /* moved to another machine. ................. */
++} lstat_user_request_t;
++
++#endif /* _LINUX_LOCKMETER_H */
+--- linux-2.6.0-test6/include/linux/mca.h      2003-08-22 19:23:42.000000000 -0700
++++ 25/include/linux/mca.h     2003-10-05 00:33:24.000000000 -0700
+@@ -136,10 +136,6 @@ extern void mca_unregister_driver(struct
+ /* WARNING: only called by the boot time device setup */
+ extern int mca_register_device(int bus, struct mca_device *mca_dev);
+-#ifdef CONFIG_MCA_LEGACY
+-#include <linux/mca-legacy.h>
+-#endif
+-
+ #ifdef CONFIG_MCA_PROC_FS
+ extern void mca_do_proc_init(void);
+ extern void mca_set_adapter_procfn(int slot, MCA_ProcFn, void* dev);
+--- linux-2.6.0-test6/include/linux/mca-legacy.h       2003-06-14 12:18:51.000000000 -0700
++++ 25/include/linux/mca-legacy.h      2003-10-05 00:33:24.000000000 -0700
+@@ -7,6 +7,8 @@
+ #ifndef _LINUX_MCA_LEGACY_H
+ #define _LINUX_MCA_LEGACY_H
++#include <linux/mca.h>
++
+ #warning "MCA legacy - please move your driver to the new sysfs api"
+ /* MCA_NOTFOUND is an error condition.  The other two indicate
+--- linux-2.6.0-test6/include/linux/mman.h     2003-09-08 13:58:59.000000000 -0700
++++ 25/include/linux/mman.h    2003-10-05 00:34:49.000000000 -0700
+@@ -28,8 +28,13 @@ static inline void vm_unacct_memory(long
+       vm_acct_memory(-pages);
+ }
+-/* Optimisation macro. */
+-#define _calc_vm_trans(x,bit1,bit2) \
++/*
++ * Optimisation macro.  It is equivalent to:
++ *      (x & bit1) ? bit2 : 0
++ * but this version is faster.
++ * ("bit1" and "bit2" must be single bits)
++ */
++#define _calc_vm_trans(x, bit1, bit2) \
+   ((bit1) <= (bit2) ? ((x) & (bit1)) * ((bit2) / (bit1)) \
+    : ((x) & (bit1)) / ((bit1) / (bit2)))
+--- linux-2.6.0-test6/include/linux/mm.h       2003-09-27 18:57:47.000000000 -0700
++++ 25/include/linux/mm.h      2003-10-05 00:34:41.000000000 -0700
+@@ -196,7 +196,7 @@ struct page {
+ #if defined(WANT_PAGE_VIRTUAL)
+       void *virtual;                  /* Kernel virtual address (NULL if
+                                          not kmapped, ie. highmem) */
+-#endif /* CONFIG_HIGMEM || WANT_PAGE_VIRTUAL */
++#endif /* WANT_PAGE_VIRTUAL */
+ };
+ /*
+@@ -323,7 +323,6 @@ static inline void put_page(struct page 
+  * The zone field is never updated after free_area_init_core()
+  * sets it, so none of the operations on it need to be atomic.
+  */
+-#define NODE_SHIFT 4
+ #define ZONE_SHIFT (BITS_PER_LONG - 8)
+ struct zone;
+--- linux-2.6.0-test6/include/linux/mmzone.h   2003-09-08 13:58:59.000000000 -0700
++++ 25/include/linux/mmzone.h  2003-10-05 00:34:41.000000000 -0700
+@@ -10,13 +10,8 @@
+ #include <linux/wait.h>
+ #include <linux/cache.h>
+ #include <linux/threads.h>
++#include <linux/numa.h>
+ #include <asm/atomic.h>
+-#ifdef CONFIG_DISCONTIGMEM
+-#include <asm/numnodes.h>
+-#endif
+-#ifndef MAX_NUMNODES
+-#define MAX_NUMNODES 1
+-#endif
+ /* Free memory management - zoned buddy allocator.  */
+ #ifndef CONFIG_FORCE_MAX_ZONEORDER
+@@ -303,19 +298,34 @@ extern void setup_per_zone_pages_min(voi
+ #define numa_node_id()                (cpu_to_node(smp_processor_id()))
+ #ifndef CONFIG_DISCONTIGMEM
++
+ extern struct pglist_data contig_page_data;
+ #define NODE_DATA(nid)                (&contig_page_data)
+ #define NODE_MEM_MAP(nid)     mem_map
+-#define MAX_NR_NODES          1
++#define MAX_NODES_SHIFT               0
++
+ #else /* CONFIG_DISCONTIGMEM */
+ #include <asm/mmzone.h>
+-/* page->zone is currently 8 bits ... */
+-#define MAX_NR_NODES          (255 / MAX_NR_ZONES)
++#if BITS_PER_LONG == 32
++/*
++ * with 32 bit flags field, page->zone is currently 8 bits.
++ * there are 3 zones (2 bits) and this leaves 8-2=6 bits for nodes.
++ */
++#define MAX_NODES_SHIFT               6
++#elif BITS_PER_LONG == 64
++/*
++ * with 64 bit flags field, there's plenty of room.
++ */
++#define MAX_NODES_SHIFT               10
++#endif
+ #endif /* !CONFIG_DISCONTIGMEM */
++#if NODES_SHIFT > MAX_NODES_SHIFT
++#error NODES_SHIFT > MAX_NODES_SHIFT
++#endif
+ extern DECLARE_BITMAP(node_online_map, MAX_NUMNODES);
+ extern DECLARE_BITMAP(memblk_online_map, MAX_NR_MEMBLKS);
+--- linux-2.6.0-test6/include/linux/moduleparam.h      2003-06-16 22:32:21.000000000 -0700
++++ 25/include/linux/moduleparam.h     2003-10-05 00:33:24.000000000 -0700
+@@ -3,6 +3,7 @@
+ /* (C) Copyright 2001, 2002 Rusty Russell IBM Corporation */
+ #include <linux/init.h>
+ #include <linux/stringify.h>
++#include <linux/kernel.h>
+ /* You can override this manually, but generally this should match the
+    module name. */
+@@ -33,6 +34,17 @@ struct kparam_string {
+       char *string;
+ };
++/* Special one for arrays */
++struct kparam_array
++{
++      unsigned int max;
++      unsigned int *num;
++      param_set_fn set;
++      param_get_fn get;
++      unsigned int elemsize;
++      void *elem;
++};
++
+ /* This is the fundamental function for registering boot/module
+    parameters.  perm sets the visibility in driverfs: 000 means it's
+    not there, read bits mean it's readable, write bits mean it's
+@@ -112,10 +124,16 @@ extern int param_set_invbool(const char 
+ extern int param_get_invbool(char *buffer, struct kernel_param *kp);
+ #define param_check_invbool(name, p) __param_check(name, p, int)
+-/* First two elements are the max and min array length (which don't change) */
+-extern int param_set_intarray(const char *val, struct kernel_param *kp);
+-extern int param_get_intarray(char *buffer, struct kernel_param *kp);
+-#define param_check_intarray(name, p) __param_check(name, p, int *)
++/* Comma-separated array: num is set to number they actually specified. */
++#define module_param_array(name, type, num, perm)                     \
++      static struct kparam_array __param_arr_##name                   \
++      = { ARRAY_SIZE(name), &num, param_set_##type, param_get_##type, \
++          sizeof(name[0]), name };                                    \
++      module_param_call(name, param_array_set, param_array_get,       \
++                        &__param_arr_##name, perm)
++
++extern int param_array_set(const char *val, struct kernel_param *kp);
++extern int param_array_get(char *buffer, struct kernel_param *kp);
+ extern int param_set_copystring(const char *val, struct kernel_param *kp);
+@@ -123,5 +141,6 @@ int param_array(const char *name,
+               const char *val,
+               unsigned int min, unsigned int max,
+               void *elem, int elemsize,
+-              int (*set)(const char *, struct kernel_param *kp));
++              int (*set)(const char *, struct kernel_param *kp),
++              int *num);
+ #endif /* _LINUX_MODULE_PARAM_TYPES_H */
+--- linux-2.6.0-test6/include/linux/netdevice.h        2003-09-27 18:57:47.000000000 -0700
++++ 25/include/linux/netdevice.h       2003-10-05 00:33:46.000000000 -0700
+@@ -456,6 +456,13 @@ struct net_device
+       /* bridge stuff */
+       struct net_bridge_port  *br_port;
++#ifdef CONFIG_KGDB
++      int                     kgdb_is_trapped;
++#endif
++#ifdef CONFIG_NET_POLL_CONTROLLER
++      void                    (*poll_controller)(struct net_device *);
++#endif
++
+ #ifdef CONFIG_NET_FASTROUTE
+ #define NETDEV_FASTROUTE_HMASK 0xF
+       /* Semi-private data. Keep it at the end of device struct. */
+@@ -530,6 +537,11 @@ extern int                dev_new_index(void);
+ extern struct net_device      *dev_get_by_index(int ifindex);
+ extern struct net_device      *__dev_get_by_index(int ifindex);
+ extern int            dev_restart(struct net_device *dev);
++#ifdef CONFIG_KGDB
++extern int            kgdb_eth_is_trapped(void);
++extern int            kgdb_net_interrupt(struct sk_buff *skb);
++extern void           kgdb_send_arp_request(void);
++#endif
+ typedef int gifconf_func_t(struct net_device * dev, char * bufptr, int len);
+ extern int            register_gifconf(unsigned int family, gifconf_func_t * gifconf);
+@@ -588,12 +600,22 @@ static inline void netif_start_queue(str
+ static inline void netif_wake_queue(struct net_device *dev)
+ {
++#ifdef CONFIG_KGDB
++      if (kgdb_eth_is_trapped()) {
++              return;
++      }
++#endif
+       if (test_and_clear_bit(__LINK_STATE_XOFF, &dev->state))
+               __netif_schedule(dev);
+ }
+ static inline void netif_stop_queue(struct net_device *dev)
+ {
++#ifdef CONFIG_KGDB
++      if (kgdb_eth_is_trapped()) {
++              return;
++      }
++#endif
+       set_bit(__LINK_STATE_XOFF, &dev->state);
+ }
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/include/linux/netfilter_bridge/ebt_limit.h      2003-10-05 00:33:24.000000000 -0700
+@@ -0,0 +1,23 @@
++#ifndef __LINUX_BRIDGE_EBT_LIMIT_H
++#define __LINUX_BRIDGE_EBT_LIMIT_H
++
++#define EBT_LIMIT_MATCH "limit"
++
++/* timings are in milliseconds. */
++#define EBT_LIMIT_SCALE 10000
++
++/* 1/10,000 sec period => max of 10,000/sec.  Min rate is then 429490
++   seconds, or one every 59 hours. */
++
++struct ebt_limit_info
++{
++      u_int32_t avg;    /* Average secs between packets * scale */
++      u_int32_t burst;  /* Period multiplier for upper limit. */
++
++      /* Used internally by the kernel */
++      unsigned long prev;
++      u_int32_t credit;
++      u_int32_t credit_cap, cost;
++};
++
++#endif
+--- linux-2.6.0-test6/include/linux/netfilter_ipv4/ip_conntrack_tuple.h        2003-06-14 12:18:29.000000000 -0700
++++ 25/include/linux/netfilter_ipv4/ip_conntrack_tuple.h       2003-10-05 00:33:24.000000000 -0700
+@@ -62,6 +62,14 @@ struct ip_conntrack_tuple
+       } dst;
+ };
++/* This is optimized opposed to a memset of the whole structure.  Everything we
++ * really care about is the  source/destination unions */
++#define IP_CT_TUPLE_U_BLANK(tuple)                            \
++      do {                                                    \
++              (tuple)->src.u.all = 0;                         \
++              (tuple)->dst.u.all = 0;                         \
++      } while (0)
++
+ enum ip_conntrack_dir
+ {
+       IP_CT_DIR_ORIGINAL,
+--- linux-2.6.0-test6/include/linux/netfilter_ipv4/ip_nat_rule.h       2003-06-14 12:18:33.000000000 -0700
++++ 25/include/linux/netfilter_ipv4/ip_nat_rule.h      2003-10-05 00:33:24.000000000 -0700
+@@ -14,5 +14,10 @@ extern int ip_nat_rule_find(struct sk_bu
+                           const struct net_device *out,
+                           struct ip_conntrack *ct,
+                           struct ip_nat_info *info);
++
++extern unsigned int
++alloc_null_binding(struct ip_conntrack *conntrack,
++                 struct ip_nat_info *info,
++                 unsigned int hooknum);
+ #endif
+ #endif /* _IP_NAT_RULE_H */
+--- linux-2.6.0-test6/include/linux/nfs_fs.h   2003-07-27 12:14:40.000000000 -0700
++++ 25/include/linux/nfs_fs.h  2003-10-05 00:36:42.000000000 -0700
+@@ -271,7 +271,7 @@ nfs_file_cred(struct file *file)
+ /*
+  * linux/fs/nfs/direct.c
+  */
+-extern int nfs_direct_IO(int, struct file *, const struct iovec *, loff_t,
++extern int nfs_direct_IO(int, struct kiocb *, const struct iovec *, loff_t,
+                       unsigned long);
+ /*
+--- linux-2.6.0-test6/include/linux/nfs_page.h 2003-06-26 22:07:26.000000000 -0700
++++ 25/include/linux/nfs_page.h        2003-10-05 00:36:43.000000000 -0700
+@@ -46,7 +46,6 @@ extern       struct nfs_page *nfs_create_reque
+                                           unsigned int, unsigned int);
+ extern        void nfs_clear_request(struct nfs_page *req);
+ extern        void nfs_release_request(struct nfs_page *req);
+-extern        void nfs_release_list(struct list_head *list);
+ extern        void nfs_list_add_request(struct nfs_page *, struct list_head *);
+@@ -56,7 +55,6 @@ extern       int nfs_scan_list(struct list_hea
+ extern        int nfs_coalesce_requests(struct list_head *, struct list_head *,
+                                 unsigned int);
+ extern  int nfs_wait_on_request(struct nfs_page *);
+-extern        int nfs_wait_for_reads(struct list_head *);
+ extern        spinlock_t nfs_wreq_lock;
+--- linux-2.6.0-test6/include/linux/nfs_xdr.h  2003-09-08 13:58:59.000000000 -0700
++++ 25/include/linux/nfs_xdr.h 2003-10-05 00:36:45.000000000 -0700
+@@ -591,6 +591,7 @@ struct nfs4_compound {
+ #endif /* CONFIG_NFS_V4 */
+ struct nfs_read_data {
++      int                     flags;
+       struct rpc_task         task;
+       struct inode            *inode;
+       struct rpc_cred         *cred;
+@@ -605,6 +606,7 @@ struct nfs_read_data {
+ };
+ struct nfs_write_data {
++      int                     flags;
+       struct rpc_task         task;
+       struct inode            *inode;
+       struct rpc_cred         *cred;
+@@ -634,16 +636,9 @@ struct nfs_rpc_ops {
+                           struct nfs_fh *, struct nfs_fattr *);
+       int     (*access)  (struct inode *, struct rpc_cred *, int);
+       int     (*readlink)(struct inode *, struct page *);
+-      int     (*read)    (struct inode *, struct rpc_cred *,
+-                          struct nfs_fattr *,
+-                          int, unsigned int, unsigned int,
+-                          struct page *, int *eofp);
+-      int     (*write)   (struct inode *, struct rpc_cred *,
+-                          struct nfs_fattr *,
+-                          int, unsigned int, unsigned int,
+-                          struct page *, struct nfs_writeverf *verfp);
+-      int     (*commit)  (struct inode *, struct nfs_fattr *,
+-                          unsigned long, unsigned int);
++      int     (*read)    (struct nfs_read_data *);
++      int     (*write)   (struct nfs_write_data *);
++      int     (*commit)  (struct nfs_write_data *);
+       int     (*create)  (struct inode *, struct qstr *, struct iattr *,
+                           int, struct nfs_fh *, struct nfs_fattr *);
+       int     (*remove)  (struct inode *, struct qstr *);
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/include/linux/numa.h    2003-10-05 00:34:41.000000000 -0700
+@@ -0,0 +1,16 @@
++#ifndef _LINUX_NUMA_H
++#define _LINUX_NUMA_H
++
++#include <linux/config.h>
++
++#ifdef CONFIG_DISCONTIGMEM
++#include <asm/numnodes.h>
++#endif
++
++#ifndef NODES_SHIFT
++#define NODES_SHIFT     0
++#endif
++
++#define MAX_NUMNODES    (1 << NODES_SHIFT)
++
++#endif /* _LINUX_NUMA_H */
+--- linux-2.6.0-test6/include/linux/pagemap.h  2003-08-22 19:23:42.000000000 -0700
++++ 25/include/linux/pagemap.h 2003-10-05 00:37:03.000000000 -0700
+@@ -71,7 +71,7 @@ extern struct page * find_trylock_page(s
+ extern struct page * find_or_create_page(struct address_space *mapping,
+                               unsigned long index, unsigned int gfp_mask);
+ extern unsigned int find_get_pages(struct address_space *mapping,
+-                              pgoff_t start, unsigned int nr_pages,
++                              pgoff_t *next, unsigned int nr_pages,
+                               struct page **pages);
+ /*
+@@ -153,17 +153,27 @@ static inline void ___add_to_page_cache(
+ extern void FASTCALL(__lock_page(struct page *page));
+ extern void FASTCALL(unlock_page(struct page *page));
+-static inline void lock_page(struct page *page)
++
++extern int FASTCALL(__lock_page_wq(struct page *page, wait_queue_t *wait));
++static inline int lock_page_wq(struct page *page, wait_queue_t *wait)
+ {
+       if (TestSetPageLocked(page))
+-              __lock_page(page);
++              return __lock_page_wq(page, wait);
++      else
++              return 0;
++}
++
++static inline void lock_page(struct page *page)
++{
++      lock_page_wq(page, NULL);
+ }
+       
+ /*
+  * This is exported only for wait_on_page_locked/wait_on_page_writeback.
+  * Never use this directly!
+  */
+-extern void FASTCALL(wait_on_page_bit(struct page *page, int bit_nr));
++extern int FASTCALL(wait_on_page_bit_wq(struct page *page, int bit_nr,
++      wait_queue_t *wait));
+ /* 
+  * Wait for a page to be unlocked.
+@@ -172,19 +182,33 @@ extern void FASTCALL(wait_on_page_bit(st
+  * ie with increased "page->count" so that the page won't
+  * go away during the wait..
+  */
+-static inline void wait_on_page_locked(struct page *page)
++static inline int wait_on_page_locked_wq(struct page *page, wait_queue_t *wait)
+ {
+       if (PageLocked(page))
+-              wait_on_page_bit(page, PG_locked);
++              return wait_on_page_bit_wq(page, PG_locked, wait);
++      return 0;
++}
++
++static inline int wait_on_page_writeback_wq(struct page *page,
++                                              wait_queue_t *wait)
++{
++      if (PageWriteback(page))
++              return wait_on_page_bit_wq(page, PG_writeback, wait);
++      return 0;
++}
++
++static inline void wait_on_page_locked(struct page *page)
++{
++      wait_on_page_locked_wq(page, NULL);
+ }
+ /* 
+  * Wait for a page to complete writeback
+  */
++
+ static inline void wait_on_page_writeback(struct page *page)
+ {
+-      if (PageWriteback(page))
+-              wait_on_page_bit(page, PG_writeback);
++      wait_on_page_writeback_wq(page, NULL);
+ }
+ extern void end_page_writeback(struct page *page);
+--- linux-2.6.0-test6/include/linux/pagevec.h  2003-06-14 12:18:51.000000000 -0700
++++ 25/include/linux/pagevec.h 2003-10-05 00:37:03.000000000 -0700
+@@ -23,7 +23,7 @@ void __pagevec_lru_add(struct pagevec *p
+ void __pagevec_lru_add_active(struct pagevec *pvec);
+ void pagevec_strip(struct pagevec *pvec);
+ unsigned int pagevec_lookup(struct pagevec *pvec, struct address_space *mapping,
+-              pgoff_t start, unsigned int nr_pages);
++              pgoff_t *next, unsigned int nr_pages);
+ static inline void pagevec_init(struct pagevec *pvec, int cold)
+ {
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/include/linux/parser.h  2003-10-05 00:33:24.000000000 -0700
+@@ -0,0 +1,21 @@
++struct match_token {
++      int token;
++      char *pattern;
++};
++
++typedef struct match_token match_table_t[];
++
++enum {MAX_OPT_ARGS = 3};
++
++typedef struct {
++      char *from;
++      char *to;
++} substring_t;
++
++int match_token(char *s, match_table_t table, substring_t args[]);
++
++int match_int(substring_t *, int *result);
++int match_octal(substring_t *, int *result);
++int match_hex(substring_t *, int *result);
++void match_strcpy(char *, substring_t *);
++char *match_strdup(substring_t *);
+--- linux-2.6.0-test6/include/linux/pci.h      2003-08-22 19:23:42.000000000 -0700
++++ 25/include/linux/pci.h     2003-10-05 00:36:20.000000000 -0700
+@@ -36,6 +36,7 @@
+ #define  PCI_COMMAND_WAIT     0x80    /* Enable address/data stepping */
+ #define  PCI_COMMAND_SERR     0x100   /* Enable SERR */
+ #define  PCI_COMMAND_FAST_BACK        0x200   /* Enable back-to-back writes */
++#define  PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */
+ #define PCI_STATUS            0x06    /* 16 bits */
+ #define  PCI_STATUS_CAP_LIST  0x10    /* Support Capability List */
+@@ -198,6 +199,8 @@
+ #define  PCI_CAP_ID_MSI               0x05    /* Message Signalled Interrupts */
+ #define  PCI_CAP_ID_CHSWP     0x06    /* CompactPCI HotSwap */
+ #define  PCI_CAP_ID_PCIX      0x07    /* PCI-X */
++#define  PCI_CAP_ID_EXP       0x10    /* PCI Express */
++#define  PCI_CAP_ID_MSIX      0x11    /* MSI-X */
+ #define PCI_CAP_LIST_NEXT     1       /* Next capability in the list */
+ #define PCI_CAP_FLAGS         2       /* Capability defined flags (16 bits) */
+ #define PCI_CAP_SIZEOF                4
+@@ -275,11 +278,13 @@
+ #define  PCI_MSI_FLAGS_QSIZE  0x70    /* Message queue size configured */
+ #define  PCI_MSI_FLAGS_QMASK  0x0e    /* Maximum queue size available */
+ #define  PCI_MSI_FLAGS_ENABLE 0x01    /* MSI feature enabled */
++#define  PCI_MSI_FLAGS_MASKBIT        0x100   /* 64-bit mask bits allowed */
+ #define PCI_MSI_RFU           3       /* Rest of capability flags */
+ #define PCI_MSI_ADDRESS_LO    4       /* Lower 32 bits */
+ #define PCI_MSI_ADDRESS_HI    8       /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */
+ #define PCI_MSI_DATA_32               8       /* 16 bits of data for 32-bit devices */
+ #define PCI_MSI_DATA_64               12      /* 16 bits of data for 64-bit devices */
++#define PCI_MSI_MASK_BIT      16      /* Mask bits register */
+ /* CompactPCI Hotswap Register */
+@@ -515,7 +520,6 @@ struct pci_driver {
+       const struct pci_device_id *id_table;   /* must be non-NULL for probe to be called */
+       int  (*probe)  (struct pci_dev *dev, const struct pci_device_id *id);   /* New device inserted */
+       void (*remove) (struct pci_dev *dev);   /* Device removed (NULL if not a hot-plug capable driver) */
+-      int  (*save_state) (struct pci_dev *dev, u32 state);    /* Save Device Context */
+       int  (*suspend) (struct pci_dev *dev, u32 state);       /* Device suspended */
+       int  (*resume) (struct pci_dev *dev);                   /* Device woken up */
+       int  (*enable_wake) (struct pci_dev *dev, u32 state, int enable);   /* Enable wake event */
+@@ -696,6 +700,18 @@ void pci_pool_free (struct pci_pool *poo
+ extern struct pci_dev *isa_bridge;
+ #endif
++#ifndef CONFIG_PCI_USE_VECTOR
++static inline void pci_scan_msi_device(struct pci_dev *dev) {}
++static inline int pci_enable_msi(struct pci_dev *dev) {return -1;}
++static inline void msi_remove_pci_irq_vectors(struct pci_dev *dev) {}
++#else
++extern void pci_scan_msi_device(struct pci_dev *dev);
++extern int pci_enable_msi(struct pci_dev *dev);
++extern void msi_remove_pci_irq_vectors(struct pci_dev *dev);
++extern int msi_alloc_vectors(struct pci_dev* dev, int *vector, int nvec);
++extern int msi_free_vectors(struct pci_dev* dev, int *vector, int nvec);
++#endif
++
+ #endif /* CONFIG_PCI */
+ /* Include architecture-dependent settings and functions */
+--- linux-2.6.0-test6/include/linux/pci_ids.h  2003-09-08 13:58:59.000000000 -0700
++++ 25/include/linux/pci_ids.h 2003-10-05 00:36:28.000000000 -0700
+@@ -519,6 +519,7 @@
+ #define PCI_DEVICE_ID_CT_65550                0x00e0
+ #define PCI_DEVICE_ID_CT_65554                0x00e4
+ #define PCI_DEVICE_ID_CT_65555                0x00e5
++#define PCI_DEVICE_ID_CT_69000                0x00c0
+ #define PCI_VENDOR_ID_MIRO            0x1031
+ #define PCI_DEVICE_ID_MIRO_36050      0x5601
+@@ -896,6 +897,7 @@
+ #define PCI_VENDOR_ID_SGI             0x10a9
+ #define PCI_DEVICE_ID_SGI_IOC3                0x0003
++#define PCI_DEVICE_ID_SGI_IOC4                0x100a
+ #define PCI_VENDOR_ID_SGI_LITHIUM     0x1002
+ #define PCI_VENDOR_ID_ACC             0x10aa
+@@ -1060,6 +1062,16 @@
+ #define PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL   0x0258
+ #define PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL   0x0259
+ #define PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL   0x025B
++#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800 0x0280
++#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4280 0x0281
++#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800_SE 0x0282
++#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_4200_GO 0x0286
++#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5800_U        0x0301
++#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5800  0x0302
++#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600_U        0x0311
++#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600  0x0312
++#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200_U        0x0321
++#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200  0x0322
+ #define PCI_VENDOR_ID_IMS             0x10e0
+ #define PCI_DEVICE_ID_IMS_8849                0x8849
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/include/linux/pci_msi.h 2003-10-05 00:36:20.000000000 -0700
+@@ -0,0 +1,193 @@
++/*
++ *    ../include/linux/pci_msi.h
++ *
++ */
++
++#ifndef _ASM_PCI_MSI_H
++#define _ASM_PCI_MSI_H
++
++#include <linux/pci.h>
++
++#define MSI_AUTO -1
++#define NR_REPEATS    23
++#define NR_RESERVED_VECTORS 3 /*FIRST_DEVICE_VECTOR,FIRST_SYSTEM_VECTOR,0x80 */
++
++/*
++ * Assume the maximum number of hot plug slots supported by the system is about
++ * ten. The worstcase is that each of these slots is hot-added with a device,
++ * which has two MSI/MSI-X capable functions. To avoid any MSI-X driver, which
++ * attempts to request all available vectors, NR_HP_RESERVED_VECTORS is defined
++ * as below to ensure at least one message is assigned to each detected MSI/
++ * MSI-X device function.
++ */
++#define NR_HP_RESERVED_VECTORS        20
++
++extern int vector_irq[NR_IRQS];
++extern cpumask_t pending_irq_balance_cpumask[NR_IRQS];
++extern void (*interrupt[NR_IRQS])(void);
++
++#ifdef CONFIG_SMP
++#define set_msi_irq_affinity  set_msi_affinity
++#else
++#define set_msi_irq_affinity  NULL
++static inline void move_msi(int vector) {}
++#endif
++
++#ifndef CONFIG_X86_IO_APIC
++static inline int get_ioapic_vector(struct pci_dev *dev) { return -1;}
++static inline void restore_ioapic_irq_handler(int irq) {}
++#else
++extern void restore_ioapic_irq_handler(int irq);
++#endif
++
++/*
++ * MSI-X Address Register
++ */
++#define PCI_MSIX_FLAGS_QSIZE          0x7FF
++#define PCI_MSIX_FLAGS_ENABLE         (1 << 15)
++#define PCI_MSIX_FLAGS_BIRMASK                (7 << 0)
++#define PCI_MSIX_FLAGS_BITMASK                (1 << 0)
++
++#define PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET      0
++#define PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET      4
++#define PCI_MSIX_ENTRY_DATA_OFFSET            8
++#define PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET     12
++#define PCI_MSIX_ENTRY_SIZE                   16
++
++#define msi_control_reg(base)         (base + PCI_MSI_FLAGS)
++#define msi_lower_address_reg(base)   (base + PCI_MSI_ADDRESS_LO)
++#define msi_upper_address_reg(base)   (base + PCI_MSI_ADDRESS_HI)
++#define msi_data_reg(base, is64bit)   \
++      ( (is64bit == 1) ? base+PCI_MSI_DATA_64 : base+PCI_MSI_DATA_32 )
++#define msi_mask_bits_reg(base, is64bit) \
++      ( (is64bit == 1) ? base+PCI_MSI_MASK_BIT : base+PCI_MSI_MASK_BIT-4)
++#define msi_disable(control)          control &= ~PCI_MSI_FLAGS_ENABLE
++#define multi_msi_capable(control) \
++      (1 << ((control & PCI_MSI_FLAGS_QMASK) >> 1))
++#define multi_msi_enable(control, num) \
++      control |= (((num >> 1) << 4) & PCI_MSI_FLAGS_QSIZE);
++#define is_64bit_address(control)     (control & PCI_MSI_FLAGS_64BIT)
++#define is_mask_bit_support(control)  (control & PCI_MSI_FLAGS_MASKBIT)
++#define msi_enable(control, num) multi_msi_enable(control, num); \
++      control |= PCI_MSI_FLAGS_ENABLE
++
++#define msix_control_reg              msi_control_reg
++#define msix_table_offset_reg(base)   (base + 0x04)
++#define msix_pba_offset_reg(base)     (base + 0x08)
++#define msix_enable(control)          control |= PCI_MSIX_FLAGS_ENABLE
++#define msix_disable(control)         control &= ~PCI_MSIX_FLAGS_ENABLE
++#define msix_table_size(control)      ((control & PCI_MSIX_FLAGS_QSIZE)+1)
++#define multi_msix_capable            msix_table_size
++#define msix_unmask(address)          (address & ~PCI_MSIX_FLAGS_BITMASK)
++#define msix_mask(address)            (address | PCI_MSIX_FLAGS_BITMASK)
++#define msix_is_pending(address)      (address & PCI_MSIX_FLAGS_PENDMASK)
++
++extern char __dbg_str_buf[256];
++#define _DEFINE_DBG_BUFFER    char __dbg_str_buf[256];
++#define _DBG_K_TRACE_ENTRY    ((unsigned int)0x00000001)
++#define _DBG_K_TRACE_EXIT     ((unsigned int)0x00000002)
++#define _DBG_K_INFO           ((unsigned int)0x00000004)
++#define _DBG_K_ERROR          ((unsigned int)0x00000008)
++#define _DBG_K_TRACE  (_DBG_K_TRACE_ENTRY | _DBG_K_TRACE_EXIT)
++
++#define _DEBUG_LEVEL  (_DBG_K_INFO | _DBG_K_ERROR | _DBG_K_TRACE)
++#define _DBG_PRINT( dbg_flags, args... )              \
++if ( _DEBUG_LEVEL & (dbg_flags) )                     \
++{                                                     \
++      int len;                                        \
++      len = sprintf(__dbg_str_buf, "%s:%d: %s ",      \
++              __FILE__, __LINE__, __FUNCTION__ );     \
++      sprintf(__dbg_str_buf + len, args);             \
++      printk(KERN_INFO "%s\n", __dbg_str_buf);        \
++}
++
++#define MSI_FUNCTION_TRACE_ENTER      \
++      _DBG_PRINT (_DBG_K_TRACE_ENTRY, "%s", "[Entry]");
++#define MSI_FUNCTION_TRACE_EXIT               \
++      _DBG_PRINT (_DBG_K_TRACE_EXIT, "%s", "[Entry]");
++
++/*
++ * MSI Defined Data Structures
++ */
++#define MSI_ADDRESS_HEADER            0xfee
++#define MSI_ADDRESS_HEADER_SHIFT      12
++#define MSI_ADDRESS_HEADER_MASK               0xfff000
++#define MSI_TARGET_CPU_SHIFT          4
++#define MSI_TARGET_CPU_MASK           0xff
++#define MSI_DELIVERY_MODE             0
++#define MSI_LEVEL_MODE                        1       /* Edge always assert */
++#define MSI_TRIGGER_MODE              0       /* MSI is edge sensitive */
++#define MSI_LOGICAL_MODE              1
++#define MSI_REDIRECTION_HINT_MODE     0
++#ifdef CONFIG_SMP
++#define MSI_TARGET_CPU                        logical_smp_processor_id()
++#else
++#define MSI_TARGET_CPU                        TARGET_CPUS
++#endif
++
++struct msg_data {
++#if defined(__LITTLE_ENDIAN_BITFIELD)
++      __u32   vector          :  8;
++      __u32   delivery_mode   :  3;   /* 000b: FIXED | 001b: lowest prior */
++      __u32   reserved_1      :  3;
++      __u32   level           :  1;   /* 0: deassert | 1: assert */
++      __u32   trigger         :  1;   /* 0: edge | 1: level */
++      __u32   reserved_2      : 16;
++#elif defined(__BIG_ENDIAN_BITFIELD)
++      __u32   reserved_2      : 16;
++      __u32   trigger         :  1;   /* 0: edge | 1: level */
++      __u32   level           :  1;   /* 0: deassert | 1: assert */
++      __u32   reserved_1      :  3;
++      __u32   delivery_mode   :  3;   /* 000b: FIXED | 001b: lowest prior */
++      __u32   vector          :  8;
++#else
++#error "Bitfield endianness not defined! Check your byteorder.h"
++#endif
++} __attribute__ ((packed));
++
++struct msg_address {
++      union {
++              struct {
++#if defined(__LITTLE_ENDIAN_BITFIELD)
++                      __u32   reserved_1      :  2;
++                      __u32   dest_mode       :  1;   /*0:physic | 1:logic */
++                      __u32   redirection_hint:  1;   /*0: dedicated CPU
++                                                        1: lowest priority */
++                      __u32   reserved_2      :  4;
++                      __u32   dest_id         : 24;   /* Destination ID */
++#elif defined(__BIG_ENDIAN_BITFIELD)
++                      __u32   dest_id         : 24;   /* Destination ID */
++                      __u32   reserved_2      :  4;
++                      __u32   redirection_hint:  1;   /*0: dedicated CPU
++                                                        1: lowest priority */
++                      __u32   dest_mode       :  1;   /*0:physic | 1:logic */
++                      __u32   reserved_1      :  2;
++#else
++#error "Bitfield endianness not defined! Check your byteorder.h"
++#endif
++                      }u;
++                      __u32  value;
++      }lo_address;
++      __u32   hi_address;
++} __attribute__ ((packed));
++
++struct msi_desc {
++      struct {
++              __u8    type    : 5;    /* {0: unused, 5h:MSI, 11h:MSI-X} */
++              __u8    maskbit : 1;    /* mask-pending bit supported ?   */
++              __u8    reserved: 2;    /* reserved                       */
++              __u8    entry_nr;       /* specific enabled entry         */
++              __u8    default_vector; /* default pre-assigned vector    */
++              __u8    current_cpu;    /* current destination cpu        */
++      }msi_attrib;
++
++      struct {
++              __u16   head;
++              __u16   tail;
++      }link;
++
++      unsigned long mask_base;
++      struct pci_dev *dev;
++};
++
++#endif /* _ASM_PCI_MSI_H */
+--- linux-2.6.0-test6/include/linux/raw.h      2003-06-14 12:18:25.000000000 -0700
++++ 25/include/linux/raw.h     2003-10-05 00:33:24.000000000 -0700
+@@ -13,4 +13,6 @@ struct raw_config_request 
+       __u64   block_minor;
+ };
++#define MAX_RAW_MINORS CONFIG_MAX_RAW_DEVS
++
+ #endif /* __LINUX_RAW_H */
+--- linux-2.6.0-test6/include/linux/rcupdate.h 2003-08-22 19:23:42.000000000 -0700
++++ 25/include/linux/rcupdate.h        2003-10-05 00:33:24.000000000 -0700
+@@ -15,7 +15,7 @@
+  * 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, 2001
++ * Copyright (C) IBM Corporation, 2001
+  *
+  * Author: Dipankar Sarma <dipankar@in.ibm.com>
+  * 
+--- linux-2.6.0-test6/include/linux/sched.h    2003-09-27 18:57:47.000000000 -0700
++++ 25/include/linux/sched.h   2003-10-05 00:36:54.000000000 -0700
+@@ -151,6 +151,7 @@ extern void init_idle(task_t *idle, int 
+ extern void show_state(void);
+ extern void show_regs(struct pt_regs *);
++extern void show_trace_task(task_t *tsk);
+ /*
+  * TASK is a pointer to the task whose backtrace we want to see (or NULL for current
+@@ -207,6 +208,8 @@ struct mm_struct {
+       cpumask_t cpu_vm_mask;
+       unsigned long swap_address;
++      unsigned long saved_auxv[40]; /* for /proc/PID/auxv */
++
+       unsigned dumpable:1;
+ #ifdef CONFIG_HUGETLB_PAGE
+       int used_hugetlb;
+@@ -262,6 +265,15 @@ struct signal_struct {
+       /* thread group stop support, overloads group_exit_code too */
+       int                     group_stop_count;
++
++      /* job control IDs */
++      pid_t pgrp;
++      pid_t tty_old_pgrp;
++      pid_t session;
++      /* boolean value for session group leader */
++      int leader;
++
++      struct tty_struct *tty; /* NULL if no tty */
+ };
+ /*
+@@ -364,12 +376,7 @@ struct task_struct {
+       unsigned long personality;
+       int did_exec:1;
+       pid_t pid;
+-      pid_t __pgrp;           /* Accessed via process_group() */
+-      pid_t tty_old_pgrp;
+-      pid_t session;
+       pid_t tgid;
+-      /* boolean value for session group leader */
+-      int leader;
+       /* 
+        * pointers to (original) parent process, youngest child, younger sibling,
+        * older sibling, respectively.  (p->father can be replaced with 
+@@ -413,7 +420,6 @@ struct task_struct {
+       char comm[16];
+ /* file system info */
+       int link_count, total_link_count;
+-      struct tty_struct *tty; /* NULL if no tty */
+       unsigned int locks; /* How many file locks are being held */
+ /* ipc stuff */
+       struct sysv_sem sysvsem;
+@@ -463,11 +469,33 @@ struct task_struct {
+       unsigned long ptrace_message;
+       siginfo_t *last_siginfo; /* For ptrace use.  */
++/*
++ * current io wait handle: wait queue entry to use for io waits
++ * If this thread is processing aio, this points at the waitqueue
++ * inside the currently handled kiocb. It may be NULL (i.e. default
++ * to a stack based synchronous wait) if its doing sync IO.
++ */
++      wait_queue_t *io_wait;
+ };
+ static inline pid_t process_group(struct task_struct *tsk)
+ {
+-      return tsk->group_leader->__pgrp;
++      return tsk->signal->pgrp;
++}
++
++static inline pid_t process_session(struct task_struct *tsk)
++{
++      return tsk->signal->session;
++}
++
++static inline int process_session_leader(struct task_struct *tsk)
++{
++      return tsk->signal->leader;
++}
++
++static inline struct tty_struct *process_tty(struct task_struct *tsk)
++{
++      return tsk->signal->tty;
+ }
+ extern void __put_task_struct(struct task_struct *tsk);
+--- linux-2.6.0-test6/include/linux/sctp.h     2003-09-08 13:58:59.000000000 -0700
++++ 25/include/linux/sctp.h    2003-10-05 00:33:24.000000000 -0700
+@@ -524,113 +524,4 @@ typedef struct sctp_addip_chunk {
+       sctp_addiphdr_t addip_hdr;
+ } sctp_addip_chunk_t __attribute__((packed));
+-/* FIXME:  Cleanup needs to continue below this line. */
+-
+-
+-/* ADDIP Section 3.1.1
+- *
+- * ASCONF-Request Correlation ID: 32 bits (unsigned integer)
+- *
+- * This is an opaque integer assigned by the sender to identify each
+- * request parameter. It is in host byte order and is only meaningful
+- * to the sender. The receiver of the ASCONF Chunk will copy this 32
+- * bit value into the ASCONF Correlation ID field of the
+- * ASCONF-ACK. The sender of the ASCONF can use this same value in the
+- * ASCONF-ACK to find which request the response is for.
+- *
+- * ASCONF Parameter: TLV format
+- *
+- * Each Address configuration change is represented by a TLV parameter
+- * as defined in Section 3.2. One or more requests may be present in
+- * an ASCONF Chunk.
+- */
+-typedef struct {
+-      __u32   correlation;
+-      sctp_paramhdr_t p;
+-      __u8            payload[0];
+-} sctpAsconfReq_t;
+-
+-/* ADDIP
+- * 3.1.1  Address/Stream Configuration Change Chunk (ASCONF)
+- *
+- * This chunk is used to communicate to the remote endpoint one of the
+- * configuration change requests that MUST be acknowledged.  The
+- * information carried in the ASCONF Chunk uses the form of a
+- * Tag-Length-Value (TLV), as described in "3.2.1
+- * Optional/Variable-length Parameter Format" in [RFC2960], for all
+- * variable parameters.
+- */
+-typedef struct {
+-      __u32   serial;
+-      __u8    reserved[3];
+-      __u8    addr_type;
+-      __u32   addr[4];
+-      sctpAsconfReq_t requests[0];
+-} sctpAsconf_t;
+-
+-/* ADDIP
+- * 3.1.2 Address/Stream Configuration Acknowledgment Chunk (ASCONF-ACK)
+- *
+- * ASCONF-Request Correlation ID: 32 bits (unsigned integer)
+- *
+- * This value is copied from the ASCONF Correlation ID received in the
+- * ASCONF Chunk. It is used by the receiver of the ASCONF-ACK to identify
+- * which ASCONF parameter this response is associated with.
+- *
+- * ASCONF Parameter Response : TLV format
+- *
+- * The ASCONF Parameter Response is used in the ASCONF-ACK to report
+- * status of ASCONF processing. By default, if a responding endpoint
+- * does not include any Error Cause, a success is indicated. Thus a
+- * sender of an ASCONF-ACK MAY indicate complete success of all TLVs in
+- * an ASCONF by returning only the Chunk Type, Chunk Flags, Chunk Length
+- * (set to 8) and the Serial Number.
+- */
+-typedef union {
+-      struct {
+-              __u32           correlation;
+-              sctp_paramhdr_t header; /* success report */
+-      } success;
+-      struct {
+-              __u32           correlation;
+-              sctp_paramhdr_t header; /* error cause indication */
+-              sctp_paramhdr_t errcause;
+-              uint8_t request[0];     /* original request from ASCONF */
+-      } error;
+-#define __correlation success.correlation
+-#define __header      success.header
+-#define __cause               error.errcause
+-#define __request     error.request
+-}  sctpAsconfAckRsp_t;
+-
+-/* ADDIP
+- * 3.1.2 Address/Stream Configuration Acknowledgment Chunk (ASCONF-ACK)
+- *
+- * This chunk is used by the receiver of an ASCONF Chunk to
+- * acknowledge the reception. It carries zero or more results for any
+- * ASCONF Parameters that were processed by the receiver.
+- */
+-typedef struct {
+-      __u32   serial;
+-      sctpAsconfAckRsp_t responses[0];
+-} sctpAsconfAck_t;
+-
+-/*********************************************************************
+- * Internal structures
+- *
+- * These are data structures which never go out on the wire.
+- *********************************************************************/
+-
+-/* What is this data structure for?  The TLV isn't one--it is just a
+- * value.  Perhaps this data structure ought to have a type--otherwise
+- * it is not unambigiously parseable.  --piggy
+- */
+-typedef struct {
+-      struct list_head hook;
+-      int length;     /* length of the TLV */
+-
+-      /* the actually TLV to be copied into ASCONF_ACK */
+-      sctpAsconfAckRsp_t TLV;
+-} sctpAsconfAckRspNode_t;
+-
+ #endif /* __LINUX_SCTP_H__ */
+--- linux-2.6.0-test6/include/linux/security.h 2003-07-10 18:50:32.000000000 -0700
++++ 25/include/linux/security.h        2003-10-05 00:33:24.000000000 -0700
+@@ -334,6 +334,7 @@ struct swap_info_struct;
+  *    called when the actual read/write operations are performed.
+  *    @inode contains the inode structure to check.
+  *    @mask contains the permission mask.
++ *     @nd contains the nameidata (may be NULL).
+  *    Return 0 if permission is granted.
+  * @inode_setattr:
+  *    Check permission before setting file attributes.  Note that the kernel
+@@ -1055,7 +1056,7 @@ struct security_operations {
+                                  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);
++      int (*inode_permission) (struct inode *inode, int mask, struct nameidata *nd);
+       int (*inode_setattr)    (struct dentry *dentry, struct iattr *attr);
+       int (*inode_getattr) (struct vfsmount *mnt, struct dentry *dentry);
+         void (*inode_delete) (struct inode *inode);
+@@ -1474,9 +1475,10 @@ static inline int security_inode_follow_
+       return security_ops->inode_follow_link (dentry, nd);
+ }
+-static inline int security_inode_permission (struct inode *inode, int mask)
++static inline int security_inode_permission (struct inode *inode, int mask,
++                                           struct nameidata *nd)
+ {
+-      return security_ops->inode_permission (inode, mask);
++      return security_ops->inode_permission (inode, mask, nd);
+ }
+ static inline int security_inode_setattr (struct dentry *dentry,
+@@ -2110,7 +2112,8 @@ static inline int security_inode_follow_
+       return 0;
+ }
+-static inline int security_inode_permission (struct inode *inode, int mask)
++static inline int security_inode_permission (struct inode *inode, int mask,
++                                           struct nameidata *nd)
+ {
+       return 0;
+ }
+--- linux-2.6.0-test6/include/linux/serial_core.h      2003-09-27 18:57:47.000000000 -0700
++++ 25/include/linux/serial_core.h     2003-10-05 00:33:38.000000000 -0700
+@@ -158,7 +158,9 @@ struct uart_port {
+       unsigned char           x_char;                 /* xon/xoff char */
+       unsigned char           regshift;               /* reg offset shift */
+       unsigned char           iotype;                 /* io access style */
+-
++#ifdef CONFIG_KGDB
++      int                     kgdb;                   /* in use by kgdb */
++#endif
+ #define UPIO_PORT             (0)
+ #define UPIO_HUB6             (1)
+ #define UPIO_MEM              (2)
+--- linux-2.6.0-test6/include/linux/serialP.h  2003-06-14 12:17:57.000000000 -0700
++++ 25/include/linux/serialP.h 2003-10-05 00:33:25.000000000 -0700
+@@ -19,6 +19,7 @@
+  * For definitions of the flags field, see tty.h
+  */
++#include <linux/version.h>
+ #include <linux/config.h>
+ #include <linux/termios.h>
+ #include <linux/workqueue.h>
+--- linux-2.6.0-test6/include/linux/serio.h    2003-09-27 18:57:47.000000000 -0700
++++ 25/include/linux/serio.h   2003-10-05 00:34:15.000000000 -0700
+@@ -53,6 +53,7 @@ struct serio_dev {
+       irqreturn_t (*interrupt)(struct serio *, unsigned char,
+                       unsigned int, struct pt_regs *);
+       void (*connect)(struct serio *, struct serio_dev *dev);
++      int  (*reconnect)(struct serio *);
+       void (*disconnect)(struct serio *);
+       void (*cleanup)(struct serio *);
+@@ -62,12 +63,13 @@ struct serio_dev {
+ int serio_open(struct serio *serio, struct serio_dev *dev);
+ void serio_close(struct serio *serio);
+ void serio_rescan(struct serio *serio);
++void serio_reconnect(struct serio *serio);
+ irqreturn_t serio_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs);
+ void serio_register_port(struct serio *serio);
+-void serio_register_slave_port(struct serio *serio);
++void __serio_register_port(struct serio *serio);
+ void serio_unregister_port(struct serio *serio);
+-void serio_unregister_slave_port(struct serio *serio);
++void __serio_unregister_port(struct serio *serio);
+ void serio_register_device(struct serio_dev *dev);
+ void serio_unregister_device(struct serio_dev *dev);
+--- linux-2.6.0-test6/include/linux/skbuff.h   2003-09-27 18:57:47.000000000 -0700
++++ 25/include/linux/skbuff.h  2003-10-05 00:36:10.000000000 -0700
+@@ -152,6 +152,7 @@ struct skb_shared_info {
+  *    @sk: Socket we are owned by
+  *    @stamp: Time we arrived
+  *    @dev: Device we arrived on/are leaving by
++ *      @real_dev: The real device we are using
+  *    @h: Transport layer header
+  *    @nh: Network layer header
+  *    @mac: Link layer header
+@@ -179,6 +180,7 @@ struct skb_shared_info {
+  *    @nfct: Associated connection, if any
+  *    @nf_debug: Netfilter debugging
+  *    @nf_bridge: Saved data about a bridged frame - see br_netfilter.c
++ *      @private: Data which is private to the HIPPI implementation
+  *    @tc_index: Traffic control index
+  */
+@@ -885,7 +887,7 @@ static inline char *__skb_pull(struct sk
+  */
+ static inline unsigned char *skb_pull(struct sk_buff *skb, unsigned int len)
+ {
+-      return (len > skb->len) ? NULL : __skb_pull(skb, len);
++      return unlikely(len > skb->len) ? NULL : __skb_pull(skb, len);
+ }
+ extern unsigned char *__pskb_pull_tail(struct sk_buff *skb, int delta);
+@@ -901,7 +903,7 @@ static inline char *__pskb_pull(struct s
+ static inline unsigned char *pskb_pull(struct sk_buff *skb, unsigned int len)
+ {
+-      return (len > skb->len) ? NULL : __pskb_pull(skb, len);
++      return unlikely(len > skb->len) ? NULL : __pskb_pull(skb, len);
+ }
+ static inline int pskb_may_pull(struct sk_buff *skb, unsigned int len)
+@@ -1052,7 +1054,7 @@ static inline struct sk_buff *__dev_allo
+                                             int gfp_mask)
+ {
+       struct sk_buff *skb = alloc_skb(length + 16, gfp_mask);
+-      if (skb)
++      if (likely(skb))
+               skb_reserve(skb, 16);
+       return skb;
+ }
+--- linux-2.6.0-test6/include/linux/spinlock.h 2003-07-02 14:53:18.000000000 -0700
++++ 25/include/linux/spinlock.h        2003-10-05 00:36:40.000000000 -0700
+@@ -15,6 +15,12 @@
+ #include <asm/processor.h>    /* for cpu relax */
+ #include <asm/system.h>
++#ifdef CONFIG_KGDB
++#include <asm/current.h>
++#define SET_WHO(x, him) (x)->who = him;
++#else
++#define SET_WHO(x, him)
++#endif
+ /*
+  * Must define these before including other files, inline functions need them
+@@ -55,6 +61,9 @@ typedef struct {
+       const char *module;
+       char *owner;
+       int oline;
++#ifdef CONFIG_KGDB
++      struct task_struct *who;
++#endif
+ } spinlock_t;
+ #define SPIN_LOCK_UNLOCKED (spinlock_t) { SPINLOCK_MAGIC, 0, 10, __FILE__ , NULL, 0}
+@@ -66,6 +75,7 @@ typedef struct {
+               (x)->module = __FILE__; \
+               (x)->owner = NULL; \
+               (x)->oline = 0; \
++                SET_WHO(x, NULL) \
+       } while (0)
+ #define CHECK_LOCK(x) \
+@@ -88,6 +98,7 @@ typedef struct {
+               (x)->lock = 1; \
+               (x)->owner = __FILE__; \
+               (x)->oline = __LINE__; \
++                SET_WHO(x, current)       \
+       } while (0)
+ /* without debugging, spin_is_locked on UP always says
+@@ -118,6 +129,7 @@ typedef struct {
+               (x)->lock = 1; \
+               (x)->owner = __FILE__; \
+               (x)->oline = __LINE__; \
++                SET_WHO(x, current)       \
+               1; \
+       })
+@@ -184,6 +196,17 @@ typedef struct {
+ #endif /* !SMP */
++#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_write_trylock(rwlock_t *lock);
++#endif
++
+ /*
+  * 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
+@@ -389,6 +412,141 @@ do { \
+                               _raw_spin_trylock(lock) ? 1 : \
+                               ({preempt_enable(); local_bh_enable(); 0;});})
++#ifdef CONFIG_LOCKMETER
++#undef spin_lock
++#undef spin_trylock
++#undef spin_unlock
++#undef spin_lock_irqsave
++#undef spin_lock_irq
++#undef spin_lock_bh
++#undef read_lock
++#undef read_unlock
++#undef write_lock
++#undef write_unlock
++#undef write_trylock
++#undef spin_unlock_bh
++#undef read_lock_irqsave
++#undef read_lock_irq
++#undef read_lock_bh
++#undef read_unlock_bh
++#undef write_lock_irqsave
++#undef write_lock_irq
++#undef write_lock_bh
++#undef write_unlock_bh
++
++#define spin_lock(lock) \
++do { \
++      preempt_disable(); \
++      _metered_spin_lock(lock); \
++} while(0)
++
++#define spin_trylock(lock)     ({preempt_disable(); _metered_spin_trylock(lock) ? \
++                              1 : ({preempt_enable(); 0;});})
++#define spin_unlock(lock) \
++do { \
++      _metered_spin_unlock(lock); \
++      preempt_enable(); \
++} while (0)
++
++#define spin_lock_irqsave(lock, flags) \
++do { \
++      local_irq_save(flags); \
++      preempt_disable(); \
++      _metered_spin_lock(lock); \
++} while (0)
++
++#define spin_lock_irq(lock) \
++do { \
++      local_irq_disable(); \
++      preempt_disable(); \
++      _metered_spin_lock(lock); \
++} while (0)
++
++#define spin_lock_bh(lock) \
++do { \
++      local_bh_disable(); \
++      preempt_disable(); \
++      _metered_spin_lock(lock); \
++} while (0)
++
++#define spin_unlock_bh(lock) \
++do { \
++      _metered_spin_unlock(lock); \
++      preempt_enable(); \
++      local_bh_enable(); \
++} while (0)
++
++
++#define read_lock(lock)                ({preempt_disable(); _metered_read_lock(lock);})
++#define read_unlock(lock)      ({_metered_read_unlock(lock); preempt_enable();})
++#define write_lock(lock)       ({preempt_disable(); _metered_write_lock(lock);})
++#define write_unlock(lock)     ({_metered_write_unlock(lock); preempt_enable();})
++#define write_trylock(lock)    ({preempt_disable();_metered_write_trylock(lock) ? \
++                              1 : ({preempt_enable(); 0;});})
++#define spin_unlock_no_resched(lock) \
++do { \
++      _metered_spin_unlock(lock); \
++      preempt_enable_no_resched(); \
++} while (0)
++
++#define read_lock_irqsave(lock, flags) \
++do { \
++      local_irq_save(flags); \
++      preempt_disable(); \
++      _metered_read_lock(lock); \
++} while (0)
++
++#define read_lock_irq(lock) \
++do { \
++      local_irq_disable(); \
++      preempt_disable(); \
++      _metered_read_lock(lock); \
++} while (0)
++
++#define read_lock_bh(lock) \
++do { \
++      local_bh_disable(); \
++      preempt_disable(); \
++      _metered_read_lock(lock); \
++} while (0)
++
++#define read_unlock_bh(lock) \
++do { \
++      _metered_read_unlock(lock); \
++      preempt_enable(); \
++      local_bh_enable(); \
++} while (0)
++
++#define write_lock_irqsave(lock, flags) \
++do { \
++      local_irq_save(flags); \
++      preempt_disable(); \
++      _metered_write_lock(lock); \
++} while (0)
++
++#define write_lock_irq(lock) \
++do { \
++      local_irq_disable(); \
++      preempt_disable(); \
++      _metered_write_lock(lock); \
++} while (0)
++
++#define write_lock_bh(lock) \
++do { \
++      local_bh_disable(); \
++      preempt_disable(); \
++      _metered_write_lock(lock); \
++} while (0)
++
++#define write_unlock_bh(lock) \
++do { \
++      _metered_write_unlock(lock); \
++      preempt_enable(); \
++      local_bh_enable(); \
++} while (0)
++
++#endif /* !CONFIG_LOCKMETER */
++
+ /* "lock on reference count zero" */
+ #ifndef ATOMIC_DEC_AND_LOCK
+ #include <asm/atomic.h>
+--- linux-2.6.0-test6/include/linux/stallion.h 2003-06-14 12:18:32.000000000 -0700
++++ 25/include/linux/stallion.h        2003-10-05 00:33:25.000000000 -0700
+@@ -21,6 +21,8 @@
+  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+  */
++#include <linux/version.h>
++
+ /*****************************************************************************/
+ #ifndef       _STALLION_H
+ #define       _STALLION_H
+--- linux-2.6.0-test6/include/linux/sysctl.h   2003-09-08 13:58:59.000000000 -0700
++++ 25/include/linux/sysctl.h  2003-10-05 00:33:25.000000000 -0700
+@@ -244,6 +244,7 @@ enum
+       NET_IPV4_NEIGH=17,
+       NET_IPV4_ROUTE=18,
+       NET_IPV4_FIB_HASH=19,
++      NET_IPV4_NETFILTER=20,
+       NET_IPV4_TCP_TIMESTAMPS=33,
+       NET_IPV4_TCP_WINDOW_SCALING=34,
+@@ -358,6 +359,24 @@ enum
+       NET_IPV4_CONF_NOPOLICY=16,
+ };
++/* /proc/sys/net/ipv4/netfilter */
++enum
++{
++      NET_IPV4_NF_CONNTRACK_MAX=1,
++      NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT=2,
++      NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV=3,
++      NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED=4,
++      NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT=5,
++      NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT=6,
++      NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK=7,
++      NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT=8,
++      NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE=9,
++      NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT=10,
++      NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT_STREAM=11,
++      NET_IPV4_NF_CONNTRACK_ICMP_TIMEOUT=12,
++      NET_IPV4_NF_CONNTRACK_GENERIC_TIMEOUT=13,
++};
++ 
+ /* /proc/sys/net/ipv6 */
+ enum {
+       NET_IPV6_CONF=16,
+--- linux-2.6.0-test6/include/linux/toshiba.h  2003-09-08 13:58:59.000000000 -0700
++++ 25/include/linux/toshiba.h 2003-10-05 00:33:25.000000000 -0700
+@@ -33,4 +33,13 @@ typedef struct {
+       unsigned int edi __attribute__ ((packed));
+ } SMMRegisters;
++#ifdef CONFIG_PROC_FS
++static int tosh_get_info(char *, char **, off_t, int);
++#else /* !CONFIG_PROC_FS */
++inline int tosh_get_info(char *buffer, char **start, off_t fpos, int lenght)
++{
++      return 0;
++}
++#endif /* CONFIG_PROC_FS */
++
+ #endif
+--- linux-2.6.0-test6/include/linux/usb.h      2003-09-27 18:57:47.000000000 -0700
++++ 25/include/linux/usb.h     2003-10-05 00:33:25.000000000 -0700
+@@ -1038,9 +1038,9 @@ void usb_show_string(struct usb_device *
+ #define dbg(format, arg...) do {} while (0)
+ #endif
+-#define err(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" , ## arg)
+-#define info(format, arg...) printk(KERN_INFO __FILE__ ": " format "\n" , ## arg)
+-#define warn(format, arg...) printk(KERN_WARNING __FILE__ ": " format "\n" , ## arg)
++#define err(format, arg...) printk(KERN_ERR "%s: " format "\n" , __FILE__ , ## arg)
++#define info(format, arg...) printk(KERN_INFO "%s: " format "\n" , __FILE__ , ## arg)
++#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n" , __FILE__ , ## arg)
+ #endif  /* __KERNEL__ */
+--- linux-2.6.0-test6/include/linux/wait.h     2003-09-08 13:58:59.000000000 -0700
++++ 25/include/linux/wait.h    2003-10-05 00:36:54.000000000 -0700
+@@ -80,6 +80,15 @@ static inline int waitqueue_active(wait_
+       return !list_empty(&q->task_list);
+ }
++/*
++ * Used to distinguish between sync and async io wait context:
++ * sync i/o typically specifies a NULL wait queue entry or a wait
++ * queue entry bound to a task (current task) to wake up.
++ * aio specifies a wait queue entry with an async notification
++ * callback routine, not associated with any task.
++ */
++#define is_sync_wait(wait)    (!(wait) || ((wait)->task))
++
+ extern void FASTCALL(add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait));
+ extern void FASTCALL(add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t * wait));
+ extern void FASTCALL(remove_wait_queue(wait_queue_head_t *q, wait_queue_t * wait));
+--- linux-2.6.0-test6/include/linux/writeback.h        2003-09-27 18:57:47.000000000 -0700
++++ 25/include/linux/writeback.h       2003-10-05 00:37:01.000000000 -0700
+@@ -84,9 +84,13 @@ int dirty_writeback_centisecs_handler(st
+                                     void __user *, size_t *);
+ void page_writeback_init(void);
+-void balance_dirty_pages_ratelimited(struct address_space *mapping);
++int balance_dirty_pages_ratelimited(struct address_space *mapping);
+ int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0);
+ int do_writepages(struct address_space *mapping, struct writeback_control *wbc);
++ssize_t sync_page_range(struct inode *inode, struct address_space *mapping,
++                      loff_t pos, size_t count);
++ssize_t 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
+--- linux-2.6.0-test6/include/net/irda/irda_device.h   2003-08-22 19:23:42.000000000 -0700
++++ 25/include/net/irda/irda_device.h  2003-10-05 00:33:25.000000000 -0700
+@@ -128,6 +128,7 @@ struct dongle_reg {
+       void (*close)(dongle_t *dongle);
+       int  (*reset)(struct irda_task *task);
+       int  (*change_speed)(struct irda_task *task);
++      struct module *owner;
+ };
+ /* 
+@@ -223,6 +224,7 @@ int  irda_device_set_raw_mode(struct net
+ int  irda_device_set_dtr_rts(struct net_device *dev, int dtr, int rts);
+ int  irda_device_change_speed(struct net_device *dev, __u32 speed);
+ void irda_device_setup(struct net_device *dev);
++struct net_device *alloc_irdadev(int sizeof_priv);
+ /* Dongle interface */
+ void irda_device_unregister_dongle(struct dongle_reg *dongle);
+--- linux-2.6.0-test6/include/net/pkt_sched.h  2003-08-08 22:55:14.000000000 -0700
++++ 25/include/net/pkt_sched.h 2003-10-05 00:33:25.000000000 -0700
+@@ -8,6 +8,7 @@
+ #define PSCHED_CLOCK_SOURCE   PSCHED_JIFFIES
+ #include <linux/config.h>
++#include <linux/netdevice.h>
+ #include <linux/types.h>
+ #include <linux/pkt_sched.h>
+ #include <net/pkt_cls.h>
+--- linux-2.6.0-test6/include/net/scm.h        2003-06-14 12:18:20.000000000 -0700
++++ 25/include/net/scm.h       2003-10-05 00:33:25.000000000 -0700
+@@ -39,7 +39,7 @@ static __inline__ int scm_send(struct so
+       memset(scm, 0, sizeof(*scm));
+       scm->creds.uid = current->uid;
+       scm->creds.gid = current->gid;
+-      scm->creds.pid = current->pid;
++      scm->creds.pid = current->tgid;
+       if (msg->msg_controllen <= 0)
+               return 0;
+       return __scm_send(sock, msg, scm);
+--- linux-2.6.0-test6/include/net/sctp/command.h       2003-08-08 22:55:14.000000000 -0700
++++ 25/include/net/sctp/command.h      2003-10-05 00:33:25.000000000 -0700
+@@ -1,5 +1,6 @@
+-/* SCTP kernel reference Implementation Copyright (C) 1999-2001
+- * Cisco, Motorola, and IBM
++/* SCTP kernel reference Implementation
++ * (C) Copyright IBM Corp. 2001, 2003
++ * Copyright (C) 1999-2001 Cisco, Motorola
+  *
+  * This file is part of the SCTP kernel reference Implementation
+  *
+@@ -88,6 +89,7 @@ typedef enum {
+       SCTP_CMD_PART_DELIVER,   /* Partial data delivery considerations. */
+       SCTP_CMD_RENEGE,         /* Renege data on an association. */
+       SCTP_CMD_SETUP_T4,       /* ADDIP, setup T4 RTO timer parms. */
++      SCTP_CMD_PROCESS_OPERR,  /* Process an ERROR chunk. */
+       SCTP_CMD_LAST
+ } sctp_verb_t;
+--- linux-2.6.0-test6/include/net/sctp/sctp.h  2003-09-08 13:58:59.000000000 -0700
++++ 25/include/net/sctp/sctp.h 2003-10-05 00:33:25.000000000 -0700
+@@ -116,6 +116,9 @@
+ #define SCTP_STATIC static
+ #endif
++#define MSECS_TO_JIFFIES(msec) (msec * HZ / 1000)
++#define JIFFIES_TO_MSECS(jiff) (jiff * 1000 / HZ)
++
+ /*
+  * Function declarations.
+  */
+@@ -495,22 +498,19 @@ for (err = (sctp_errhdr_t *)((void *)chu
+ #define tv_lt(s, t) \
+    (s.tv_sec < t.tv_sec || (s.tv_sec == t.tv_sec && s.tv_usec < t.tv_usec))
+-/* Stolen from net/profile.h.  Using it from there is more grief than
+- * it is worth.
+- */
+-static inline void tv_add(const struct timeval *entered, struct timeval *leaved)
+-{
+-      time_t usecs = leaved->tv_usec + entered->tv_usec;
+-      time_t secs = leaved->tv_sec + entered->tv_sec;
+-
+-      if (usecs >= 1000000) {
+-              usecs -= 1000000;
+-              secs++;
+-      }
+-      leaved->tv_sec = secs;
+-      leaved->tv_usec = usecs;
+-}
+-
++/* Add tv1 to tv2. */
++#define TIMEVAL_ADD(tv1, tv2) \
++({ \
++        suseconds_t usecs = (tv2).tv_usec + (tv1).tv_usec; \
++        time_t secs = (tv2).tv_sec + (tv1).tv_sec; \
++\
++        if (usecs >= 1000000) { \
++                usecs -= 1000000; \
++                secs++; \
++        } \
++        (tv2).tv_sec = secs; \
++        (tv2).tv_usec = usecs; \
++})
+ /* External references. */
+--- linux-2.6.0-test6/include/net/sctp/sm.h    2003-09-08 13:58:59.000000000 -0700
++++ 25/include/net/sctp/sm.h   2003-10-05 00:33:25.000000000 -0700
+@@ -265,13 +265,19 @@ struct sctp_chunk *sctp_make_op_error(co
+ struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc,
+                                   union sctp_addr *addr,
+                                   int vparam_len);
++struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *,
++                                            union sctp_addr *,
++                                            struct sockaddr *,
++                                            int, int);
++struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc,
++                                           union sctp_addr *addr);
++struct sctp_chunk *sctp_make_asconf_ack(struct sctp_association *asoc,
++                                      int serial, int vparam_len);
++
+ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
+                                      struct sctp_chunk *asconf,
+                                      int vparam_len);
+-struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc,
+-                                           union sctp_addr *addr);
+-
+ void sctp_chunk_assign_tsn(struct sctp_chunk *);
+ void sctp_chunk_assign_ssn(struct sctp_chunk *);
+--- linux-2.6.0-test6/include/net/sctp/structs.h       2003-09-08 13:58:59.000000000 -0700
++++ 25/include/net/sctp/structs.h      2003-10-05 00:33:25.000000000 -0700
+@@ -1085,6 +1085,10 @@ int sctp_add_bind_addr(struct sctp_bind_
+ int sctp_del_bind_addr(struct sctp_bind_addr *, union sctp_addr *);
+ int sctp_bind_addr_match(struct sctp_bind_addr *, const union sctp_addr *,
+                        struct sctp_opt *);
++union sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr *bp,
++                                      const union sctp_addr   *addrs,
++                                      int                     addrcnt,
++                                      struct sctp_opt         *opt);
+ union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp,
+                                        int *addrs_len, int gfp);
+ int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw, int len,
+@@ -1389,6 +1393,10 @@ struct sctp_association {
+               __u8    ipv4_address;    /* Peer understands IPv4 addresses? */
+               __u8    ipv6_address;    /* Peer understands IPv6 addresses? */
+               __u8    hostname_address;/* Peer understands DNS addresses? */
++
++              /* Does peer support ADDIP? */
++              __u8    asconf_capable;
++
+               struct sctp_inithdr i;
+               int cookie_len;
+               void *cookie;
+--- linux-2.6.0-test6/include/sound/sndmagic.h 2003-06-14 12:18:06.000000000 -0700
++++ 25/include/sound/sndmagic.h        2003-10-05 00:33:25.000000000 -0700
+@@ -198,6 +198,8 @@ static inline int _snd_magic_bad(void *o
+ #define vx_pipe_t_magic                               0xa15a4112
+ #define azf3328_t_magic                               0xa15a4200
++#define snd_card_harmony_t_magic              0xa15a4300
++
+ #else
+ #define snd_magic_kcalloc(type, extra, flags) (type *) snd_kcalloc(sizeof(type) + extra, flags)
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/include/video/epson1355.h       2003-10-05 00:34:22.000000000 -0700
+@@ -0,0 +1,64 @@
++/*
++ * include/video/epson13xx.h -- Epson 13xx frame buffer
++ *
++ * Copyright (C) Hewlett-Packard Company.  All rights reserved.
++ *
++ * Written by Christopher Hoover <ch@hpl.hp.com>
++ *
++ */
++
++#ifndef _EPSON13XX_H_
++#define _EPSON13XX_H_
++
++#define REG_REVISION_CODE              0x00
++#define REG_MEMORY_CONFIG              0x01
++#define REG_PANEL_TYPE                 0x02
++#define REG_MOD_RATE                   0x03
++#define REG_HORZ_DISP_WIDTH            0x04
++#define REG_HORZ_NONDISP_PERIOD        0x05
++#define REG_HRTC_START_POSITION        0x06
++#define REG_HRTC_PULSE_WIDTH           0x07
++#define REG_VERT_DISP_HEIGHT0          0x08
++#define REG_VERT_DISP_HEIGHT1          0x09
++#define REG_VERT_NONDISP_PERIOD        0x0A
++#define REG_VRTC_START_POSITION        0x0B
++#define REG_VRTC_PULSE_WIDTH           0x0C
++#define REG_DISPLAY_MODE               0x0D
++#define REG_SCRN1_LINE_COMPARE0        0x0E
++#define REG_SCRN1_LINE_COMPARE1        0x0F
++#define REG_SCRN1_DISP_START_ADDR0     0x10
++#define REG_SCRN1_DISP_START_ADDR1     0x11
++#define REG_SCRN1_DISP_START_ADDR2     0x12
++#define REG_SCRN2_DISP_START_ADDR0     0x13
++#define REG_SCRN2_DISP_START_ADDR1     0x14
++#define REG_SCRN2_DISP_START_ADDR2     0x15
++#define REG_MEM_ADDR_OFFSET0           0x16
++#define REG_MEM_ADDR_OFFSET1           0x17
++#define REG_PIXEL_PANNING              0x18
++#define REG_CLOCK_CONFIG               0x19
++#define REG_POWER_SAVE_CONFIG          0x1A
++#define REG_MISC                       0x1B
++#define REG_MD_CONFIG_READBACK0        0x1C
++#define REG_MD_CONFIG_READBACK1        0x1D
++#define REG_GPIO_CONFIG0               0x1E
++#define REG_GPIO_CONFIG1               0x1F
++#define REG_GPIO_CONTROL0              0x20
++#define REG_GPIO_CONTROL1              0x21
++#define REG_PERF_ENHANCEMENT0          0x22
++#define REG_PERF_ENHANCEMENT1          0x23
++#define REG_LUT_ADDR                   0x24
++#define REG_RESERVED_1                 0x25
++#define REG_LUT_DATA                   0x26
++#define REG_INK_CURSOR_CONTROL         0x27
++#define REG_CURSOR_X_POSITION0         0x28
++#define REG_CURSOR_X_POSITION1         0x29
++#define REG_CURSOR_Y_POSITION0         0x2A
++#define REG_CURSOR_Y_POSITION1         0x2B
++#define REG_INK_CURSOR_COLOR0_0        0x2C
++#define REG_INK_CURSOR_COLOR0_1        0x2D
++#define REG_INK_CURSOR_COLOR1_0        0x2E
++#define REG_INK_CURSOR_COLOR1_1        0x2F
++#define REG_INK_CURSOR_START_ADDR      0x30
++#define REG_ALTERNATE_FRM              0x31
++
++#endif
+--- linux-2.6.0-test6/include/video/neomagic.h 2003-06-14 12:18:07.000000000 -0700
++++ 25/include/video/neomagic.h        2003-10-05 00:34:22.000000000 -0700
+@@ -55,6 +55,20 @@
+ #define NEO_MODE1_X_1600        0x1c00
+ #define NEO_MODE1_BLT_ON_ADDR   0x2000
++/* These are offseted in MMIO space by par->CursorOff */
++#define NEOREG_CURSCNTL               0x00
++#define NEOREG_CURSX          0x04
++#define NEOREG_CURSY          0x08
++#define NEOREG_CURSBGCOLOR    0x0C
++#define NEOREG_CURSFGCOLOR    0x10
++#define NEOREG_CURSMEMPOS     0x14
++
++#define NEO_CURS_DISABLE      0x00000000
++#define NEO_CURS_ENABLE               0x00000001
++#define NEO_ICON64_ENABLE     0x00000008
++#define NEO_ICON128_ENABLE    0x0000000C
++#define NEO_ICON_BLANK                0x00000010
++
+ #ifdef __KERNEL__
+ #ifdef NEOFB_DEBUG
+@@ -75,45 +89,45 @@
+ struct xtimings {
+-  unsigned int pixclock;
+-  unsigned int HDisplay;
+-  unsigned int HSyncStart;
+-  unsigned int HSyncEnd;
+-  unsigned int HTotal;
+-  unsigned int VDisplay;
+-  unsigned int VSyncStart;
+-  unsigned int VSyncEnd;
+-  unsigned int VTotal;
+-  unsigned int sync;
+-  int        dblscan;
+-  int        interlaced;
++      unsigned int pixclock;
++      unsigned int HDisplay;
++      unsigned int HSyncStart;
++      unsigned int HSyncEnd;
++      unsigned int HTotal;
++      unsigned int VDisplay;
++      unsigned int VSyncStart;
++      unsigned int VSyncEnd;
++      unsigned int VTotal;
++      unsigned int sync;
++      int dblscan;
++      int interlaced;
+ };
+ /* --------------------------------------------------------------------- */
+ typedef volatile struct {
+-  __u32 bltStat;
+-  __u32 bltCntl;
+-  __u32 xpColor;
+-  __u32 fgColor;
+-  __u32 bgColor;
+-  __u32 pitch;
+-  __u32 clipLT;
+-  __u32 clipRB;
+-  __u32 srcBitOffset;
+-  __u32 srcStart;
+-  __u32 reserved0;
+-  __u32 dstStart;
+-  __u32 xyExt;
+-
+-  __u32 reserved1[19];
+-
+-  __u32 pageCntl;
+-  __u32 pageBase;
+-  __u32 postBase;
+-  __u32 postPtr;
+-  __u32 dataPtr;
++      __u32 bltStat;
++      __u32 bltCntl;
++      __u32 xpColor;
++      __u32 fgColor;
++      __u32 bgColor;
++      __u32 pitch;
++      __u32 clipLT;
++      __u32 clipRB;
++      __u32 srcBitOffset;
++      __u32 srcStart;
++      __u32 reserved0;
++      __u32 dstStart;
++      __u32 xyExt;
++
++      __u32 reserved1[19];
++
++      __u32 pageCntl;
++      __u32 pageBase;
++      __u32 postBase;
++      __u32 postPtr;
++      __u32 dataPtr;
+ } Neo2200;
+ #define NR_PALETTE    256
+@@ -124,142 +138,69 @@ typedef volatile struct {
+ #define NEO_EXT_GR_MAX 0xC7
+ struct neofb_par {
+-  
+-  unsigned char MiscOutReg;     /* Misc */
+-  unsigned char CRTC[25];       /* Crtc Controller */
+-  unsigned char Sequencer[5];   /* Video Sequencer */
+-  unsigned char Graphics[9];    /* Video Graphics */
+-  unsigned char Attribute[21];  /* Video Atribute */
+-
+-  unsigned char GeneralLockReg;
+-  unsigned char ExtCRTDispAddr;
+-  unsigned char ExtCRTOffset;
+-  unsigned char SysIfaceCntl1;
+-  unsigned char SysIfaceCntl2;
+-  unsigned char ExtColorModeSelect;
+-  unsigned char biosMode;
+-
+-  unsigned char PanelDispCntlReg1;
+-  unsigned char PanelDispCntlReg2;
+-  unsigned char PanelDispCntlReg3;
+-  unsigned char PanelVertCenterReg1;
+-  unsigned char PanelVertCenterReg2;
+-  unsigned char PanelVertCenterReg3;
+-  unsigned char PanelVertCenterReg4;
+-  unsigned char PanelVertCenterReg5;
+-  unsigned char PanelHorizCenterReg1;
+-  unsigned char PanelHorizCenterReg2;
+-  unsigned char PanelHorizCenterReg3;
+-  unsigned char PanelHorizCenterReg4;
+-  unsigned char PanelHorizCenterReg5;
+-
+-  int           ProgramVCLK;
+-  unsigned char VCLK3NumeratorLow;
+-  unsigned char VCLK3NumeratorHigh;
+-  unsigned char VCLK3Denominator;
+-  unsigned char VerticalExt;
++      struct vgastate state;
++      atomic_t ref_count;
++
++      unsigned char MiscOutReg;       /* Misc */
++      unsigned char CRTC[25];         /* Crtc Controller */
++      unsigned char Sequencer[5];     /* Video Sequencer */
++      unsigned char Graphics[9];      /* Video Graphics */
++      unsigned char Attribute[21];    /* Video Atribute */
++
++      unsigned char GeneralLockReg;
++      unsigned char ExtCRTDispAddr;
++      unsigned char ExtCRTOffset;
++      unsigned char SysIfaceCntl1;
++      unsigned char SysIfaceCntl2;
++      unsigned char ExtColorModeSelect;
++      unsigned char biosMode;
++
++      unsigned char PanelDispCntlReg1;
++      unsigned char PanelDispCntlReg2;
++      unsigned char PanelDispCntlReg3;
++      unsigned char PanelVertCenterReg1;
++      unsigned char PanelVertCenterReg2;
++      unsigned char PanelVertCenterReg3;
++      unsigned char PanelVertCenterReg4;
++      unsigned char PanelVertCenterReg5;
++      unsigned char PanelHorizCenterReg1;
++      unsigned char PanelHorizCenterReg2;
++      unsigned char PanelHorizCenterReg3;
++      unsigned char PanelHorizCenterReg4;
++      unsigned char PanelHorizCenterReg5;
++
++      int ProgramVCLK;
++      unsigned char VCLK3NumeratorLow;
++      unsigned char VCLK3NumeratorHigh;
++      unsigned char VCLK3Denominator;
++      unsigned char VerticalExt;
+ #ifdef CONFIG_MTRR
+-  int    mtrr;
++      int mtrr;
+ #endif
+-  u8    *mmio_vbase;
+-
+-  Neo2200 *neo2200;
+-
+-  /* Panels size */
+-  int NeoPanelWidth;
+-  int NeoPanelHeight;
+-
+-  int maxClock;
+-
+-  int pci_burst;
+-  int lcd_stretch;
+-  int internal_display;
+-  int external_display;
+-  int libretto;
++      u8 *mmio_vbase;
++      u8 cursorOff;
++      u8 *cursorPad;          /* Must die !! */
++
++      Neo2200 *neo2200;
++
++      /* Panels size */
++      int NeoPanelWidth;
++      int NeoPanelHeight;
++
++      int maxClock;
++
++      int pci_burst;
++      int lcd_stretch;
++      int internal_display;
++      int external_display;
++      int libretto;
+ };
+ typedef struct {
+-    int x_res;
+-    int y_res;
+-    int mode;
++      int x_res;
++      int y_res;
++      int mode;
+ } biosMode;
+-/* vga IO functions */
+-static inline u8 VGArCR (u8 index)
+-{
+-  outb (index, 0x3d4);
+-  return inb (0x3d5);
+-}
+-
+-static inline void VGAwCR (u8 index, u8 val)
+-{
+-  outb (index, 0x3d4);
+-  outb (val, 0x3d5);
+-}
+-
+-static inline u8 VGArGR (u8 index)
+-{
+-  outb (index, 0x3ce);
+-  return inb (0x3cf);
+-}
+-
+-static inline void VGAwGR (u8 index, u8 val)
+-{
+-  outb (index, 0x3ce);
+-  outb (val, 0x3cf);
+-}
+-
+-static inline u8 VGArSEQ (u8 index)
+-{
+-  outb (index, 0x3c4);
+-  return inb (0x3c5);
+-}
+-
+-static inline void VGAwSEQ (u8 index, u8 val)
+-{
+-  outb (index, 0x3c4);
+-  outb (val, 0x3c5);
+-}
+-
+-
+-static int paletteEnabled = 0;
+-
+-static inline void VGAenablePalette (void)
+-{
+-  u8 tmp;
+-
+-  tmp = inb (0x3da);
+-  outb (0x00, 0x3c0);
+-  paletteEnabled = 1;
+-}
+-
+-static inline void VGAdisablePalette (void)
+-{
+-  u8 tmp;
+-
+-  tmp = inb (0x3da);
+-  outb (0x20, 0x3c0);
+-  paletteEnabled = 0;
+-}
+-
+-static inline void VGAwATTR (u8 index, u8 value)
+-{
+-  u8 tmp;
+-
+-  if (paletteEnabled)
+-    index &= ~0x20;
+-  else
+-    index |= 0x20;
+-
+-  tmp = inb (0x3da);
+-  outb (index, 0x3c0);
+-  outb (value, 0x3c0);
+-}
+-
+-static inline void VGAwMISC (u8 value)
+-{
+-  outb (value, 0x3c2);
+-}
+ #endif
+-
+--- linux-2.6.0-test6/include/video/sisfb.h    2003-09-08 13:58:59.000000000 -0700
++++ 25/include/video/sisfb.h   2003-10-05 00:34:22.000000000 -0700
+@@ -6,6 +6,53 @@
+ #include <asm/ioctl.h>
+ #include <asm/types.h>
++/* TW: 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 CRT2_ENABLE           (CRT2_LCD | CRT2_TV | CRT2_VGA)
++#define VB_DISPTYPE_DISP2     CRT2_ENABLE
++#define VB_DISPTYPE_CRT2      CRT2_ENABLE
++#define TV_NTSC                 0x00000010
++#define TV_PAL                  0x00000020
++#define TV_HIVISION             0x00000040
++#define TV_HIVISION_LV          0x00000080
++#define TV_TYPE                 (TV_NTSC | TV_PAL | TV_HIVISION | TV_HIVISION_LV)
++#define TV_AVIDEO               0x00000100
++#define TV_SVIDEO               0x00000200
++#define TV_SCART                0x00000400
++#define TV_INTERFACE            (TV_AVIDEO | TV_SVIDEO | TV_SCART | TV_CHSCART | TV_CHHDTV)
++#define VB_USELCDA            0x00000800
++#define TV_PALM                 0x00001000
++#define TV_PALN                 0x00002000
++#define TV_CHSCART              0x00008000
++#define TV_CHHDTV               0x00010000
++#define VGA2_CONNECTED          0x00040000
++#define VB_DISPTYPE_CRT1      0x00080000      /* CRT1 connected and used */
++#define VBDISPTYPE_DISP1      VB_DISPTYPE_CRT1
++#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_TRUMPION           0x10000000
++#define VB_VIDEOBRIDGE                (VB_301|VB_301B|VB_302B|VB_301LV|VB_302LV| \
++                               VB_LVDS|VB_CHRONTEL|VB_TRUMPION)
++#define VB_SISBRIDGE            (VB_301|VB_301B|VB_302B|VB_301LV|VB_302LV)
++#define VB_SINGLE_MODE          0x20000000     /* CRT1 or CRT2; determined by VB_DISPTYPE_CRTx */
++#define VB_DISPMODE_SINGLE    VB_SINGLE_MODE
++#define VB_MIRROR_MODE                0x40000000       /* CRT1 + CRT2 identical (mirror mode) */
++#define VB_DISPMODE_MIRROR    VB_MIRROR_MODE
++#define VB_DUALVIEW_MODE      0x80000000       /* CRT1 + CRT2 independent (dual head mode) */
++#define VB_DISPMODE_DUAL      VB_DUALVIEW_MODE
++#define VB_DISPLAY_MODE         (VB_SINGLE_MODE | VB_MIRROR_MODE | VB_DUALVIEW_MODE)
++
++
++/* entries for disp_state - deprecated as of 1.6.02 */
+ #define DISPTYPE_CRT1       0x00000008L
+ #define DISPTYPE_CRT2       0x00000004L
+ #define DISPTYPE_LCD        0x00000002L
+@@ -16,6 +63,7 @@
+ #define DISPMODE_MIRROR           0x00000010L
+ #define DISPMODE_DUALVIEW   0x00000040L
++/* Deprecated as of 1.6.02 - use vbflags instead */
+ #define HASVB_NONE            0x00
+ #define HASVB_301             0x01
+ #define HASVB_LVDS            0x02
+@@ -39,6 +87,8 @@ typedef enum _SIS_CHIP_TYPE {
+       SIS_650,
+       SIS_740,
+       SIS_330,
++      SIS_660,
++      SIS_760,
+       MAX_SIS_CHIP
+ } SIS_CHIP_TYPE;
+@@ -83,13 +133,15 @@ struct ap_data {
+       struct mode_info minfo;
+       unsigned long iobase;
+       unsigned int  mem_size;
+-      unsigned long disp_state;       
++      unsigned long disp_state;  /* deprecated */
+       SIS_CHIP_TYPE chip;
+       unsigned char hasVB;
+-      SIS_TV_TYPE TV_type;
+-      SIS_TV_PLUG TV_plug;
++      SIS_TV_TYPE TV_type;       /* deprecated */
++      SIS_TV_PLUG TV_plug;       /* deprecated */
+       unsigned long version;
+-      char reserved[256];
++      unsigned long vbflags;     /* replaces deprecated entries above */
++      unsigned long currentvbflags;
++      char reserved[248];
+ };
+ struct video_info {
+@@ -114,10 +166,10 @@ struct video_info {
+       int    video_linelength;
+       unsigned int refresh_rate;
+-      unsigned long disp_state;
+-      unsigned char hasVB;
+-      unsigned char TV_type;
+-      unsigned char TV_plug;
++      unsigned long disp_state;               /* DEPRECATED */
++      unsigned char hasVB;                    /* DEPRECATED */
++      unsigned char TV_type;                  /* DEPRECATED */
++      unsigned char TV_plug;                  /* DEPRECATED */
+       SIS_CHIP_TYPE chip;
+       unsigned char revision_id;
+@@ -137,7 +189,18 @@ struct video_info {
+       unsigned short subsysvendor;
+       unsigned short subsysdevice;
+-      char reserved[236];
++      unsigned long  vbflags;                 /* Replacing deprecated stuff from above */
++      unsigned long  currentvbflags;
++
++      int    current_bpp;
++      int    current_width;
++      int    current_height;
++      int    current_htotal;
++      int    current_vtotal;
++      __u32  current_pixclock;
++      int    current_refresh_rate;
++
++      char reserved[200];
+ };
+@@ -185,7 +248,13 @@ struct _SISFB_INFO {
+       
+       unsigned char sisfb_lcda;       /* Detected status of LCDA for low res/text modes */
+-      char reserved[235];             /* for future use */
++      unsigned long sisfb_vbflags;
++      unsigned long sisfb_currentvbflags;
++
++      int sisfb_scalelcd;
++      unsigned long sisfb_specialtiming;
++
++      char reserved[219];             /* for future use */
+ };
+ #ifdef __KERNEL__
+--- linux-2.6.0-test6/init/do_mounts.h 2003-09-27 18:57:47.000000000 -0700
++++ 25/init/do_mounts.h        2003-10-05 00:33:25.000000000 -0700
+@@ -104,4 +104,3 @@ void md_run_setup(void);
+ static inline void md_run_setup(void) {}
+ #endif
+-
+--- linux-2.6.0-test6/init/do_mounts_initrd.c  2003-09-27 18:57:47.000000000 -0700
++++ 25/init/do_mounts_initrd.c 2003-10-05 00:33:53.000000000 -0700
+@@ -9,6 +9,8 @@
+ #include "do_mounts.h"
++unsigned long initrd_start, initrd_end;
++int initrd_below_start_ok;
+ unsigned int real_root_dev;   /* do_proc_dointvec cannot handle kdev_t */
+ static int __initdata old_fd, root_fd;
+ static int __initdata mount_initrd = 1;
+@@ -99,18 +101,20 @@ static void __init handle_initrd(void)
+ int __init initrd_load(void)
+ {
+-      if (!mount_initrd)
+-              return 0;
+-
+-      create_dev("/dev/ram", MKDEV(RAMDISK_MAJOR, 0), NULL);
+-      create_dev("/dev/initrd", MKDEV(RAMDISK_MAJOR, INITRD_MINOR), NULL);
+-      /* Load the initrd data into /dev/ram0. Execute it as initrd unless
+-       * /dev/ram0 is supposed to be our actual root device, in
+-       * that case the ram disk is just set up here, and gets
+-       * mounted in the normal path. */
+-      if (rd_load_image("/dev/initrd") && ROOT_DEV != Root_RAM0) {
+-              handle_initrd();
+-              return 1;
++      if (mount_initrd) {
++              create_dev("/dev/ram", Root_RAM0, NULL);
++              /*
++               * Load the initrd data into /dev/ram0. Execute it as initrd
++               * unless /dev/ram0 is supposed to be our actual root device,
++               * in that case the ram disk is just set up here, and gets
++               * mounted in the normal path.
++               */
++              if (rd_load_image("/dev/initrd") && ROOT_DEV != Root_RAM0) {
++                      sys_unlink("/dev/initrd");
++                      handle_initrd();
++                      return 1;
++              }
+       }
++      sys_unlink("/dev/initrd");
+       return 0;
+ }
+--- linux-2.6.0-test6/init/initramfs.c 2003-09-27 18:57:47.000000000 -0700
++++ 25/init/initramfs.c        2003-10-05 00:33:53.000000000 -0700
+@@ -8,9 +8,11 @@
+ #include <linux/delay.h>
+ #include <linux/string.h>
++static __initdata char *message;
+ static void __init error(char *x)
+ {
+-      panic("populate_root: %s\n", x);
++      if (!message)
++              message = x;
+ }
+ static void __init *malloc(int size)
+@@ -63,7 +65,7 @@ static char __init *find_link(int major,
+       }
+       q = (struct hash *)malloc(sizeof(struct hash));
+       if (!q)
+-              error("can't allocate link hash entry");
++              panic("can't allocate link hash entry");
+       q->ino = ino;
+       q->minor = minor;
+       q->major = major;
+@@ -119,7 +121,7 @@ static void __init parse_header(char *s)
+ /* FSM */
+-enum state {
++static __initdata enum state {
+       Start,
+       Collect,
+       GotHeader,
+@@ -130,9 +132,11 @@ enum state {
+       Reset
+ } state, next_state;
+-char *victim;
+-unsigned count;
+-loff_t this_header, next_header;
++static __initdata char *victim;
++static __initdata unsigned count;
++static __initdata loff_t this_header, next_header;
++
++static __initdata int dry_run;
+ static inline void eat(unsigned n)
+ {
+@@ -185,23 +189,30 @@ static int __init do_collect(void)
+ static int __init do_header(void)
+ {
++      if (memcmp(collected, "070701", 6)) {
++              error("no cpio magic");
++              return 1;
++      }
+       parse_header(collected);
+       next_header = this_header + N_ALIGN(name_len) + body_len;
+       next_header = (next_header + 3) & ~3;
++      if (dry_run) {
++              read_into(name_buf, N_ALIGN(name_len), GotName);
++              return 0;
++      }
++      state = SkipIt;
+       if (name_len <= 0 || name_len > PATH_MAX)
+-              state = SkipIt;
+-      else if (S_ISLNK(mode)) {
++              return 0;
++      if (S_ISLNK(mode)) {
+               if (body_len > PATH_MAX)
+-                      state = SkipIt;
+-              else {
+-                      collect = collected = symlink_buf;
+-                      remains = N_ALIGN(name_len) + body_len;
+-                      next_state = GotSymlink;
+-                      state = Collect;
+-              }
+-      } else if (body_len && !S_ISREG(mode))
+-              state = SkipIt;
+-      else
++                      return 0;
++              collect = collected = symlink_buf;
++              remains = N_ALIGN(name_len) + body_len;
++              next_state = GotSymlink;
++              state = Collect;
++              return 0;
++      }
++      if (S_ISREG(mode) || !body_len)
+               read_into(name_buf, N_ALIGN(name_len), GotName);
+       return 0;
+ }
+@@ -248,6 +259,8 @@ static int __init do_name(void)
+               next_state = Reset;
+               return 0;
+       }
++      if (dry_run)
++              return 0;
+       if (S_ISREG(mode)) {
+               if (maybe_link() >= 0) {
+                       wfd = sys_open(collected, O_WRONLY|O_CREAT, mode);
+@@ -268,8 +281,7 @@ static int __init do_name(void)
+                       sys_chown(collected, uid, gid);
+                       sys_chmod(collected, mode);
+               }
+-      } else
+-              panic("populate_root: bogus mode: %o\n", mode);
++      }
+       return 0;
+ }
+@@ -323,13 +335,14 @@ static int __init write_buffer(char *buf
+ static void __init flush_buffer(char *buf, unsigned len)
+ {
+       int written;
+-      while ((written = write_buffer(buf, len)) < len) {
++      if (message)
++              return;
++      while ((written = write_buffer(buf, len)) < len && !message) {
+               char c = buf[written];
+               if (c == '0') {
+                       buf += written;
+                       len -= written;
+                       state = Start;
+-                      continue;
+               } else
+                       error("junk in compressed archive");
+       }
+@@ -408,18 +421,20 @@ static void __init flush_window(void)
+       outcnt = 0;
+ }
+-static void __init unpack_to_rootfs(char *buf, unsigned len)
++char * __init unpack_to_rootfs(char *buf, unsigned len, int check_only)
+ {
+       int written;
++      dry_run = check_only;
+       header_buf = malloc(110);
+       symlink_buf = malloc(PATH_MAX + N_ALIGN(PATH_MAX) + 1);
+       name_buf = malloc(N_ALIGN(PATH_MAX));
+       window = malloc(WSIZE);
+       if (!window || !header_buf || !symlink_buf || !name_buf)
+-              error("can't allocate buffers");
++              panic("can't allocate buffers");
+       state = Start;
+       this_header = 0;
+-      while (len) {
++      message = NULL;
++      while (!message && len) {
+               loff_t saved_offset = this_header;
+               if (*buf == '0' && !(this_header & 3)) {
+                       state = Start;
+@@ -427,7 +442,8 @@ static void __init unpack_to_rootfs(char
+                       buf += written;
+                       len -= written;
+                       continue;
+-              } else if (!*buf) {
++              }
++              if (!*buf) {
+                       buf++;
+                       len--;
+                       this_header++;
+@@ -442,7 +458,7 @@ static void __init unpack_to_rootfs(char
+               crc = (ulg)0xffffffffL; /* shift register contents */
+               makecrc();
+               if (gunzip())
+-                      error("ungzip failed");
++                      message = "ungzip failed";
+               if (state != Reset)
+                       error("junk in gzipped archive");
+               this_header = saved_offset + inptr;
+@@ -453,12 +469,41 @@ static void __init unpack_to_rootfs(char
+       free(name_buf);
+       free(symlink_buf);
+       free(header_buf);
++      return message;
+ }
+ extern char __initramfs_start, __initramfs_end;
++#ifdef CONFIG_BLK_DEV_INITRD
++#include <linux/initrd.h>
++#endif
+ void __init populate_rootfs(void)
+ {
+-      unpack_to_rootfs(&__initramfs_start,
+-                       &__initramfs_end - &__initramfs_start);
++      char *err = unpack_to_rootfs(&__initramfs_start,
++                       &__initramfs_end - &__initramfs_start, 0);
++      if (err)
++              panic(err);
++#ifdef CONFIG_BLK_DEV_INITRD
++      if (initrd_start) {
++              int fd;
++              printk(KERN_INFO "checking if image is initramfs...");
++              err = unpack_to_rootfs((char *)initrd_start,
++                      initrd_end - initrd_start, 1);
++              if (!err) {
++                      printk(" it is\n");
++                      unpack_to_rootfs((char *)initrd_start,
++                              initrd_end - initrd_start, 0);
++                      free_initrd_mem(initrd_start, initrd_end);
++                      return;
++              }
++              printk("it isn't (%s); looks like an initrd\n", err);
++              fd = sys_open("/dev/initrd", O_WRONLY|O_CREAT, 700);
++              if (fd >= 0) {
++                      sys_write(fd, (char *)initrd_start,
++                                      initrd_end - initrd_start);
++                      sys_close(fd);
++                      free_initrd_mem(initrd_start, initrd_end);
++              }
++      }
++#endif
+ }
+--- linux-2.6.0-test6/init/main.c      2003-09-27 18:57:47.000000000 -0700
++++ 25/init/main.c     2003-10-05 00:36:25.000000000 -0700
+@@ -37,6 +37,7 @@
+ #include <linux/moduleparam.h>
+ #include <linux/writeback.h>
+ #include <linux/cpu.h>
++#include <linux/efi.h>
+ #include <asm/io.h>
+ #include <asm/bugs.h>
+@@ -436,6 +437,10 @@ asmlinkage void __init start_kernel(void
+       pidmap_init();
+       pgtable_cache_init();
+       pte_chain_init();
++#ifdef CONFIG_X86
++      if (efi_enabled)
++              efi_enter_virtual_mode();
++#endif
+       fork_init(num_physpages);
+       proc_caches_init();
+       buffer_init();
+--- linux-2.6.0-test6/kernel/acct.c    2003-09-27 18:57:47.000000000 -0700
++++ 25/kernel/acct.c   2003-10-05 00:36:15.000000000 -0700
+@@ -343,7 +343,7 @@ static void do_acct_process(long exitcod
+       /* we really need to bite the bullet and change layout */
+       ac.ac_uid = current->uid;
+       ac.ac_gid = current->gid;
+-      ac.ac_tty = current->tty ? old_encode_dev(tty_devnum(current->tty)) : 0;
++      ac.ac_tty = process_tty(current) ? old_encode_dev(tty_devnum(process_tty(current))) : 0;
+       ac.ac_flag = 0;
+       if (current->flags & PF_FORKNOEXEC)
+--- linux-2.6.0-test6/kernel/exit.c    2003-09-27 18:57:47.000000000 -0700
++++ 25/kernel/exit.c   2003-10-05 00:36:15.000000000 -0700
+@@ -119,13 +119,13 @@ int session_of_pgrp(int pgrp)
+       read_lock(&tasklist_lock);
+       for_each_task_pid(pgrp, PIDTYPE_PGID, p, l, pid)
+-              if (p->session > 0) {
+-                      sid = p->session;
++              if (process_session(p) > 0) {
++                      sid = process_session(p);
+                       goto out;
+               }
+       p = find_task_by_pid(pgrp);
+       if (p)
+-              sid = p->session;
++              sid = process_session(p);
+ out:
+       read_unlock(&tasklist_lock);
+       
+@@ -153,7 +153,7 @@ static int will_become_orphaned_pgrp(int
+                               || p->real_parent->pid == 1)
+                       continue;
+               if (process_group(p->real_parent) != pgrp
+-                          && p->real_parent->session == p->session) {
++                          && process_session(p->real_parent) == process_session(p)) {
+                       ret = 0;
+                       break;
+               }
+@@ -242,14 +242,14 @@ void __set_special_pids(pid_t session, p
+ {
+       struct task_struct *curr = current;
+-      if (curr->session != session) {
++      if (process_session(curr) != session) {
+               detach_pid(curr, PIDTYPE_SID);
+-              curr->session = session;
++              curr->signal->session = session;
+               attach_pid(curr, PIDTYPE_SID, session);
+       }
+       if (process_group(curr) != pgrp) {
+               detach_pid(curr, PIDTYPE_PGID);
+-              curr->group_leader->__pgrp = pgrp;
++              curr->signal->pgrp = pgrp;
+               attach_pid(curr, PIDTYPE_PGID, pgrp);
+       }
+ }
+@@ -303,7 +303,7 @@ void daemonize(const char *name, ...)
+       exit_mm(current);
+       set_special_pids(1, 1);
+-      current->tty = NULL;
++      current->signal->tty = NULL;
+       /* Block and flush all signals */
+       sigfillset(&blocked);
+@@ -509,7 +509,7 @@ static inline void reparent_thread(task_
+        * outside, so the child pgrp is now orphaned.
+        */
+       if ((process_group(p) != process_group(father)) &&
+-          (p->session == father->session)) {
++          (process_session(p) == process_session(father))) {
+               int pgrp = process_group(p);
+               if (will_become_orphaned_pgrp(pgrp, NULL) && has_stopped_jobs(pgrp)) {
+@@ -619,7 +619,7 @@ static void exit_notify(struct task_stru
+       t = tsk->real_parent;
+       
+       if ((process_group(t) != process_group(tsk)) &&
+-          (t->session == tsk->session) &&
++          (process_session(t) == process_session(tsk)) &&
+           will_become_orphaned_pgrp(process_group(tsk), tsk) &&
+           has_stopped_jobs(process_group(tsk))) {
+               __kill_pg_info(SIGHUP, (void *)1, process_group(tsk));
+@@ -714,7 +714,7 @@ NORET_TYPE void do_exit(long code)
+       exit_itimers(tsk);
+       exit_thread();
+-      if (tsk->leader)
++      if (process_session_leader(tsk))
+               disassociate_ctty(1);
+       module_put(tsk->thread_info->exec_domain->module);
+--- linux-2.6.0-test6/kernel/fork.c    2003-09-27 18:57:47.000000000 -0700
++++ 25/kernel/fork.c   2003-10-05 00:36:54.000000000 -0700
+@@ -121,7 +121,12 @@ void prepare_to_wait(wait_queue_head_t *
+ {
+       unsigned long flags;
+-      __set_current_state(state);
++      /*
++       * don't alter the task state if this is just going to
++       * queue an async wait queue callback
++       */
++      if (is_sync_wait(wait))
++              __set_current_state(state);
+       wait->flags &= ~WQ_FLAG_EXCLUSIVE;
+       spin_lock_irqsave(&q->lock, flags);
+       if (list_empty(&wait->task_list))
+@@ -134,7 +139,12 @@ prepare_to_wait_exclusive(wait_queue_hea
+ {
+       unsigned long flags;
+-      __set_current_state(state);
++      /*
++       * don't alter the task state if this is just going to
++       * queue an async wait queue callback
++       */
++      if (is_sync_wait(wait))
++              __set_current_state(state);
+       wait->flags |= WQ_FLAG_EXCLUSIVE;
+       spin_lock_irqsave(&q->lock, flags);
+       if (list_empty(&wait->task_list))
+@@ -274,9 +284,9 @@ static inline int dup_mmap(struct mm_str
+                               atomic_dec(&inode->i_writecount);
+       
+                       /* insert tmp into the share list, just after mpnt */
+-                      down(&inode->i_mapping->i_shared_sem);
++                      down(&file->f_mapping->i_shared_sem);
+                       list_add_tail(&tmp->shared, &mpnt->shared);
+-                      up(&inode->i_mapping->i_shared_sem);
++                      up(&file->f_mapping->i_shared_sem);
+               }
+               /*
+@@ -725,6 +735,12 @@ static inline int copy_signal(unsigned l
+       sig->curr_target = NULL;
+       init_sigpending(&sig->shared_pending);
++      sig->tty = process_tty(current);
++      sig->pgrp = process_group(current);
++      sig->session = process_session(current);
++      sig->leader = 0;        /* session leadership doesn't inherit */
++      sig->tty_old_pgrp = 0;
++
+       return 0;
+ }
+@@ -771,7 +787,9 @@ struct task_struct *copy_process(unsigne
+        * Thread groups must share signals as well, and detached threads
+        * can only be started up within the thread group.
+        */
+-      if ((clone_flags & CLONE_THREAD) && !(clone_flags & CLONE_SIGHAND))
++      if ((clone_flags & CLONE_THREAD) &&
++              (clone_flags & (CLONE_SIGHAND|CLONE_DETACHED)) !=
++                      (CLONE_SIGHAND|CLONE_DETACHED))
+               return ERR_PTR(-EINVAL);
+       /*
+@@ -876,8 +894,6 @@ struct task_struct *copy_process(unsigne
+       init_timer(&p->real_timer);
+       p->real_timer.data = (unsigned long) p;
+-      p->leader = 0;          /* session leadership doesn't inherit */
+-      p->tty_old_pgrp = 0;
+       p->utime = p->stime = 0;
+       p->cutime = p->cstime = 0;
+       p->array = NULL;
+@@ -885,6 +901,7 @@ struct task_struct *copy_process(unsigne
+       p->start_time = get_jiffies_64();
+       p->security = NULL;
+       p->io_context = NULL;
++      p->io_wait = NULL;
+       retval = -ENOMEM;
+       if ((retval = security_task_alloc(p)))
+@@ -1022,7 +1039,7 @@ struct task_struct *copy_process(unsigne
+       if (thread_group_leader(p)) {
+               attach_pid(p, PIDTYPE_TGID, p->tgid);
+               attach_pid(p, PIDTYPE_PGID, process_group(p));
+-              attach_pid(p, PIDTYPE_SID, p->session);
++              attach_pid(p, PIDTYPE_SID, process_session(p));
+               if (p->pid)
+                       __get_cpu_var(process_counts)++;
+       } else
+--- linux-2.6.0-test6/kernel/futex.c   2003-09-27 18:57:47.000000000 -0700
++++ 25/kernel/futex.c  2003-10-05 00:34:38.000000000 -0700
+@@ -45,6 +45,9 @@
+  * Futexes are matched on equal values of this key.
+  * The key type depends on whether it's a shared or private mapping.
+  * Don't rearrange members without looking at hash_futex().
++ *
++ * offset is aligned to a multiple of sizeof(u32) (== 4) by definition.
++ * We set bit 0 to indicate if it's an inode-based key.
+  */
+ union futex_key {
+       struct {
+@@ -66,12 +69,20 @@ union futex_key {
+ /*
+  * We use this hashed waitqueue instead of a normal wait_queue_t, so
+- * we can wake only the relevant ones (hashed queues may be shared):
++ * we can wake only the relevant ones (hashed queues may be shared).
++ *
++ * A futex_q has a woken state, just like tasks have TASK_RUNNING.
++ * It is considered woken when list_empty(&q->list) || q->lock_ptr == 0.
++ * The order of wakup is always to make the first condition true, then
++ * wake up q->waiters, then make the second condition true.
+  */
+ struct futex_q {
+       struct list_head list;
+       wait_queue_head_t waiters;
++      /* Which hash list lock to use. */
++      spinlock_t *lock_ptr;
++
+       /* Key which the futex is hashed on. */
+       union futex_key key;
+@@ -124,8 +135,7 @@ static inline int match_futex(union fute
+  * Returns: 0, or negative error code.
+  * The key words are stored in *key on success.
+  *
+- * Should be called with &current->mm->mmap_sem,
+- * but NOT &futex_lock or &current->mm->page_table_lock.
++ * Should be called with &current->mm->mmap_sem but NOT any spinlocks.
+  */
+ static int get_futex_key(unsigned long uaddr, union futex_key *key)
+ {
+@@ -172,9 +182,10 @@ static int get_futex_key(unsigned long u
+       }
+       /*
+-       * Linear mappings are also simple.
++       * Linear file mappings are also simple.
+        */
+       key->shared.inode = vma->vm_file->f_dentry->d_inode;
++      key->both.offset++; /* Bit 0 of offset indicates inode-based key. */
+       if (likely(!(vma->vm_flags & VM_NONLINEAR))) {
+               key->shared.pgoff = (((uaddr - vma->vm_start) >> PAGE_SHIFT)
+                                    + vma->vm_pgoff);
+@@ -214,16 +225,68 @@ static int get_futex_key(unsigned long u
+       return err;
+ }
++/*
++ * Take a reference to the resource addressed by a key.
++ * Can be called while holding spinlocks.
++ *
++ * NOTE: mmap_sem MUST be held between get_futex_key() and calling this
++ * function, if it is called at all.  mmap_sem keeps key->shared.inode valid.
++ */
++static inline void get_key_refs(union futex_key *key)
++{
++      if (key->both.ptr != 0) {
++              if (key->both.offset & 1)
++                      atomic_inc(&key->shared.inode->i_count);
++              else
++                      atomic_inc(&key->private.mm->mm_count);
++      }
++}
++
++/*
++ * Drop a reference to the resource addressed by a key.
++ * The hash bucket spinlock must not be held.
++ */
++static void drop_key_refs(union futex_key *key)
++{
++      if (key->both.ptr != 0) {
++              if (key->both.offset & 1)
++                      iput(key->shared.inode);
++              else
++                      mmdrop(key->private.mm);
++      }
++}
++
++/*
++ * The hash bucket lock must be held when this is called.
++ * Afterwards, the futex_q must not be accessed.
++ */
++static void wake_futex(struct futex_q *q)
++{
++      list_del_init(&q->list);
++      if (q->filp)
++              send_sigio(&q->filp->f_owner, q->fd, POLL_IN);
++      /*
++       * The lock in wake_up_all() is a crucial memory barrier after the
++       * list_del_init() and also before assigning to q->lock_ptr.
++       */
++      wake_up_all(&q->waiters);
++      /*
++       * The waiting task can free the futex_q as soon as this is written,
++       * without taking any locks.  This must come last.
++       */
++      q->lock_ptr = 0;
++}
+ /*
+  * Wake up all waiters hashed on the physical page that is mapped
+  * to this virtual address:
+  */
+-static int futex_wake(unsigned long uaddr, int num)
++static int futex_wake(unsigned long uaddr, int nr_wake)
+ {
+-      struct list_head *i, *next, *head;
+-      struct futex_hash_bucket *bh;
+       union futex_key key;
++      struct futex_hash_bucket *bh;
++      struct list_head *head;
++      struct futex_q *this, *next;
+       int ret;
+       down_read(&current->mm->mmap_sem);
+@@ -236,21 +299,15 @@ static int futex_wake(unsigned long uadd
+       spin_lock(&bh->lock);
+       head = &bh->chain;
+-      list_for_each_safe(i, next, head) {
+-              struct futex_q *this = list_entry(i, struct futex_q, list);
+-
++      list_for_each_entry_safe(this, next, head, list) {
+               if (match_futex (&this->key, &key)) {
+-                      list_del_init(i);
+-                      wake_up_all(&this->waiters);
+-                      if (this->filp)
+-                              send_sigio(&this->filp->f_owner, this->fd, POLL_IN);
+-                      ret++;
+-                      if (ret >= num)
++                      wake_futex(this);
++                      if (++ret >= nr_wake)
+                               break;
+               }
+       }
+-      spin_unlock(&bh->lock);
++      spin_unlock(&bh->lock);
+ out:
+       up_read(&current->mm->mmap_sem);
+       return ret;
+@@ -263,10 +320,11 @@ out:
+ static int futex_requeue(unsigned long uaddr1, unsigned long uaddr2,
+                               int nr_wake, int nr_requeue)
+ {
+-      struct list_head *i, *next, *head1, *head2;
+-      struct futex_hash_bucket *bh1, *bh2;
+       union futex_key key1, key2;
+-      int ret;
++      struct futex_hash_bucket *bh1, *bh2;
++      struct list_head *head1;
++      struct futex_q *this, *next;
++      int ret, drop_count = 0;
+       down_read(&current->mm->mmap_sem);
+@@ -279,78 +337,107 @@ static int futex_requeue(unsigned long u
+       bh1 = hash_futex(&key1);
+       bh2 = hash_futex(&key2);
+-      if (bh1 < bh2) {
++
++      if (bh1 < bh2)
++              spin_lock(&bh1->lock);
++      spin_lock(&bh2->lock);
++      if (bh1 > bh2)
+               spin_lock(&bh1->lock);
+-              spin_lock(&bh2->lock);
+-      } else {
+-              spin_lock(&bh2->lock);
+-              if (bh1 > bh2)
+-                      spin_lock(&bh1->lock);
+-      }
+-      head1 = &bh1->chain;
+-      head2 = &bh2->chain;
+-      list_for_each_safe(i, next, head1) {
+-              struct futex_q *this = list_entry(i, struct futex_q, list);
++      head1 = &bh1->chain;
++      list_for_each_entry_safe(this, next, head1, list) {
++              if (!match_futex (&this->key, &key1))
++                      continue;
++              if (++ret <= nr_wake) {
++                      wake_futex(this);
++              } else {
++                      list_move_tail(&this->list, &bh2->chain);
++                      this->lock_ptr = &bh2->lock;
++                      this->key = key2;
++                      get_key_refs(&key2);
++                      drop_count++;
+-              if (match_futex (&this->key, &key1)) {
+-                      list_del_init(i);
+-                      if (++ret <= nr_wake) {
+-                              wake_up_all(&this->waiters);
+-                              if (this->filp)
+-                                      send_sigio(&this->filp->f_owner,
+-                                                      this->fd, POLL_IN);
+-                      } else {
+-                              list_add_tail(i, head2);
+-                              this->key = key2;
+-                              if (ret - nr_wake >= nr_requeue)
+-                                      break;
+-                              /* Make sure to stop if key1 == key2 */
+-                              if (head1 == head2 && head1 != next)
+-                                      head1 = i;
+-                      }
++                      if (ret - nr_wake >= nr_requeue)
++                              break;
++                      /* Make sure to stop if key1 == key2 */
++                      if (head1 == &bh2->chain && head1 != &next->list)
++                              head1 = &this->list;
+               }
+       }
+-      if (bh1 < bh2) {
+-              spin_unlock(&bh2->lock);
+-              spin_unlock(&bh1->lock);
+-      } else {
+-              if (bh1 > bh2)
+-                      spin_unlock(&bh1->lock);
++
++      spin_unlock(&bh1->lock);
++      if (bh1 != bh2)
+               spin_unlock(&bh2->lock);
+-      }
++
++      /* drop_key_refs() must be called outside the spinlocks. */
++      while (--drop_count >= 0)
++              drop_key_refs(&key1);
++
+ out:
+       up_read(&current->mm->mmap_sem);
+       return ret;
+ }
+-static inline void queue_me(struct futex_q *q, union futex_key *key,
+-                          int fd, struct file *filp)
++/*
++ * queue_me and unqueue_me must be called as a pair, each
++ * exactly once.  They are called with the hashed spinlock held.
++ */
++
++/* The key must be already stored in q->key. */
++static void queue_me(struct futex_q *q, int fd, struct file *filp)
+ {
+-      struct futex_hash_bucket *bh = hash_futex(key);
+-      struct list_head *head = &bh->chain;
++      struct futex_hash_bucket *bh;
+-      q->key = *key;
+       q->fd = fd;
+       q->filp = filp;
++      init_waitqueue_head(&q->waiters);
++
++      get_key_refs(&q->key);
++      bh = hash_futex(&q->key);
++      q->lock_ptr = &bh->lock;
++
+       spin_lock(&bh->lock);
+-      list_add_tail(&q->list, head);
++      list_add_tail(&q->list, &bh->chain);
+       spin_unlock(&bh->lock);
+ }
+ /* Return 1 if we were still queued (ie. 0 means we were woken) */
+-static inline int unqueue_me(struct futex_q *q)
++static int unqueue_me(struct futex_q *q)
+ {
+-      struct futex_hash_bucket *bh = hash_futex(&q->key);
+       int ret = 0;
++      spinlock_t *lock_ptr;
+-      spin_lock(&bh->lock);
+-      if (!list_empty(&q->list)) {
+-              list_del(&q->list);
+-              ret = 1;
++      /* In the common case we don't take the spinlock, which is nice. */
++ retry:
++      lock_ptr = q->lock_ptr;
++      if (lock_ptr != 0) {
++              spin_lock(lock_ptr);
++              /*
++               * q->lock_ptr can change between reading it and
++               * spin_lock(), causing us to take the wrong lock.  This
++               * corrects the race condition.
++               *
++               * Reasoning goes like this: if we have the wrong lock,
++               * q->lock_ptr must have changed (maybe several times)
++               * between reading it and the spin_lock().  It can
++               * change again after the spin_lock() but only if it was
++               * already changed before the spin_lock().  It cannot,
++               * however, change back to the original value.  Therefore
++               * we can detect whether we acquired the correct lock.
++               */
++              if (unlikely(lock_ptr != q->lock_ptr)) {
++                      spin_unlock(lock_ptr);
++                      goto retry;
++              }
++              if (likely(!list_empty(&q->list))) {
++                      list_del(&q->list);
++                      ret = 1;
++              }
++              spin_unlock(lock_ptr);
+       }
+-      spin_unlock(&bh->lock);
++
++      drop_key_refs(&q->key);
+       return ret;
+ }
+@@ -358,19 +445,15 @@ static int futex_wait(unsigned long uadd
+ {
+       DECLARE_WAITQUEUE(wait, current);
+       int ret, curval;
+-      union futex_key key;
+       struct futex_q q;
+-      struct futex_hash_bucket *bh = NULL;
+-
+-      init_waitqueue_head(&q.waiters);
+       down_read(&current->mm->mmap_sem);
+-      ret = get_futex_key(uaddr, &key);
++      ret = get_futex_key(uaddr, &q.key);
+       if (unlikely(ret != 0))
+               goto out_release_sem;
+-      queue_me(&q, &key, -1, NULL);
++      queue_me(&q, -1, NULL);
+       /*
+        * Access the page after the futex is queued.
+@@ -400,23 +483,17 @@ static int futex_wait(unsigned long uadd
+        * rely on the futex_wake() code removing us from hash when it
+        * wakes us up.
+        */
+-      add_wait_queue(&q.waiters, &wait);
+-      bh = hash_futex(&key);
+-      spin_lock(&bh->lock);
+-      set_current_state(TASK_INTERRUPTIBLE);
+-
+-      if (unlikely(list_empty(&q.list))) {
+-              /*
+-               * We were woken already.
+-               */
+-              spin_unlock(&bh->lock);
+-              set_current_state(TASK_RUNNING);
+-              return 0;
+-      }
+-      spin_unlock(&bh->lock);
+-      time = schedule_timeout(time);
+-      set_current_state(TASK_RUNNING);
++      /* add_wait_queue is the barrier after __set_current_state. */
++      __set_current_state(TASK_INTERRUPTIBLE);
++      add_wait_queue(&q.waiters, &wait);
++      /*
++       * !list_empty() is safe here without any lock.
++       * q.lock_ptr != 0 is not safe, because of ordering against wakeup.
++       */
++      if (likely(!list_empty(&q.list)))
++              time = schedule_timeout(time);
++      __set_current_state(TASK_RUNNING);
+       /*
+        * NOTE: we don't remove ourselves from the waitqueue because
+@@ -446,7 +523,7 @@ static int futex_close(struct inode *ino
+       struct futex_q *q = filp->private_data;
+       unqueue_me(q);
+-      kfree(filp->private_data);
++      kfree(q);
+       return 0;
+ }
+@@ -455,14 +532,16 @@ static unsigned int futex_poll(struct fi
+                              struct poll_table_struct *wait)
+ {
+       struct futex_q *q = filp->private_data;
+-      struct futex_hash_bucket *bh = hash_futex(&q->key);
+       int ret = 0;
+       poll_wait(filp, &q->waiters, wait);
+-      spin_lock(&bh->lock);
++
++      /*
++       * list_empty() is safe here without any lock.
++       * q->lock_ptr != 0 is not safe, because of ordering against wakeup.
++       */
+       if (list_empty(&q->list))
+               ret = POLLIN | POLLRDNORM;
+-      spin_unlock(&bh->lock);
+       return ret;
+ }
+@@ -472,12 +551,13 @@ static struct file_operations futex_fops
+       .poll           = futex_poll,
+ };
+-/* Signal allows caller to avoid the race which would occur if they
+-   set the sigio stuff up afterwards. */
++/*
++ * Signal allows caller to avoid the race which would occur if they
++ * set the sigio stuff up afterwards.
++ */
+ static int futex_fd(unsigned long uaddr, int signal)
+ {
+       struct futex_q *q;
+-      union futex_key key;
+       struct file *filp;
+       int ret, err;
+@@ -497,6 +577,7 @@ static int futex_fd(unsigned long uaddr,
+       filp->f_op = &futex_fops;
+       filp->f_vfsmnt = mntget(futex_mnt);
+       filp->f_dentry = dget(futex_mnt->mnt_root);
++      filp->f_mapping = filp->f_dentry->d_inode->i_mapping;
+       if (signal) {
+               int err;
+@@ -519,20 +600,24 @@ static int futex_fd(unsigned long uaddr,
+       }
+       down_read(&current->mm->mmap_sem);
+-      err = get_futex_key(uaddr, &key);
+-      up_read(&current->mm->mmap_sem);
++      err = get_futex_key(uaddr, &q->key);
+       if (unlikely(err != 0)) {
++              up_read(&current->mm->mmap_sem);
+               put_unused_fd(ret);
+               put_filp(filp);
+               kfree(q);
+               return err;
+       }
+-      init_waitqueue_head(&q->waiters);
++      /*
++       * queue_me() must be called before releasing mmap_sem, because
++       * key->shared.inode needs to be referenced while holding it.
++       */
+       filp->private_data = q;
+-      queue_me(q, &key, ret, filp);
++      queue_me(q, ret, filp);
++      up_read(&current->mm->mmap_sem);
+       /* Now we map fd to filp, so userspace can access it */
+       fd_install(ret, filp);
+--- linux-2.6.0-test6/kernel/kmod.c    2003-09-08 13:58:59.000000000 -0700
++++ 25/kernel/kmod.c   2003-10-05 00:36:10.000000000 -0700
+@@ -47,7 +47,8 @@ char modprobe_path[256] = "/sbin/modprob
+ /**
+  * request_module - try to load a kernel module
+- * @module_name: Name of module
++ * @fmt:     printf style format string for the name of the module
++ * @varargs: arguements as specified in the format string
+  *
+  * Load a module using the user mode module loader. The function returns
+  * zero on success or a negative errno code on failure. Note that a
+@@ -184,14 +185,19 @@ static int wait_for_helper(void *data)
+       sub_info->retval = 0;
+       pid = kernel_thread(____call_usermodehelper, sub_info, SIGCHLD);
+-      if (pid < 0)
++      if (pid < 0) {
+               sub_info->retval = pid;
+-      else
++      } else {
+               /* We don't have a SIGCHLD signal handler, so this
+                * always returns -ECHILD, but the important thing is
+                * that it blocks. */
+-              sys_wait4(pid, NULL, 0, NULL);
++              mm_segment_t fs;
++              fs = get_fs();
++              set_fs(KERNEL_DS);
++              sys_wait4(pid, &sub_info->retval, 0, NULL);
++              set_fs(fs);
++      }
+       complete(sub_info->complete);
+       return 0;
+ }
+@@ -209,7 +215,7 @@ static void __call_usermodehelper(void *
+        * until that is done.  */
+       if (sub_info->wait)
+               pid = kernel_thread(wait_for_helper, sub_info,
+-                                  CLONE_KERNEL | SIGCHLD);
++                                  CLONE_FS | CLONE_FILES | SIGCHLD);
+       else
+               pid = kernel_thread(____call_usermodehelper, sub_info,
+                                   CLONE_VFORK | SIGCHLD);
+--- linux-2.6.0-test6/kernel/ksyms.c   2003-09-27 18:57:47.000000000 -0700
++++ 25/kernel/ksyms.c  2003-10-05 00:36:58.000000000 -0700
+@@ -45,8 +45,6 @@
+ #include <linux/uio.h>
+ #include <linux/tty.h>
+ #include <linux/in6.h>
+-#include <linux/completion.h>
+-#include <linux/seq_file.h>
+ #include <linux/binfmts.h>
+ #include <linux/namei.h>
+ #include <linux/buffer_head.h>
+@@ -126,11 +124,11 @@ EXPORT_SYMBOL(get_unmapped_area);
+ EXPORT_SYMBOL(init_mm);
+ EXPORT_SYMBOL(blk_queue_bounce);
+ EXPORT_SYMBOL(blk_congestion_wait);
++EXPORT_SYMBOL(blk_congestion_wait_wq);
+ #ifdef CONFIG_HIGHMEM
+ EXPORT_SYMBOL(kmap_high);
+ EXPORT_SYMBOL(kunmap_high);
+ EXPORT_SYMBOL(highmem_start_page);
+-EXPORT_SYMBOL(kmap_prot);
+ EXPORT_SYMBOL(kmap_pte);
+ #endif
+ #ifdef HASHED_PAGE_VIRTUAL
+@@ -139,49 +137,12 @@ EXPORT_SYMBOL(page_address);
+ EXPORT_SYMBOL(get_user_pages);
+ /* filesystem internal functions */
+-EXPORT_SYMBOL(def_blk_fops);
+-EXPORT_SYMBOL(update_atime);
+ EXPORT_SYMBOL(get_fs_type);
+-EXPORT_SYMBOL(user_get_super);
+-EXPORT_SYMBOL(get_super);
+-EXPORT_SYMBOL(drop_super);
+-EXPORT_SYMBOL(getname);
+-EXPORT_SYMBOL(names_cachep);
+ EXPORT_SYMBOL(fput);
+ EXPORT_SYMBOL(fget);
+-EXPORT_SYMBOL(igrab);
+-EXPORT_SYMBOL(iunique);
+-EXPORT_SYMBOL(iput);
+-EXPORT_SYMBOL(inode_init_once);
+-EXPORT_SYMBOL(follow_up);
+-EXPORT_SYMBOL(follow_down);
+ EXPORT_SYMBOL(lookup_mnt);
+-EXPORT_SYMBOL(lookup_create);
+-EXPORT_SYMBOL(path_lookup);
+-EXPORT_SYMBOL(path_walk);
+-EXPORT_SYMBOL(path_release);
+-EXPORT_SYMBOL(__user_walk);
+-EXPORT_SYMBOL(lookup_one_len);
+-EXPORT_SYMBOL(lookup_hash);
+ EXPORT_SYMBOL(sys_close);
+ EXPORT_SYMBOL(dcache_lock);
+-EXPORT_SYMBOL(d_alloc_root);
+-EXPORT_SYMBOL(d_delete);
+-EXPORT_SYMBOL(dget_locked);
+-EXPORT_SYMBOL(d_validate);
+-EXPORT_SYMBOL(d_rehash);
+-EXPORT_SYMBOL(d_invalidate);  /* May be it will be better in dcache.h? */
+-EXPORT_SYMBOL(d_move);
+-EXPORT_SYMBOL(d_instantiate);
+-EXPORT_SYMBOL(d_alloc);
+-EXPORT_SYMBOL(d_alloc_anon);
+-EXPORT_SYMBOL(d_splice_alias);
+-EXPORT_SYMBOL(d_lookup);
+-EXPORT_SYMBOL(d_path);
+-EXPORT_SYMBOL(mark_buffer_dirty);
+-EXPORT_SYMBOL(end_buffer_read_sync);
+-EXPORT_SYMBOL(end_buffer_write_sync);
+-EXPORT_SYMBOL(end_buffer_async_write);
+ EXPORT_SYMBOL(__mark_inode_dirty);
+ EXPORT_SYMBOL(get_empty_filp);
+ EXPORT_SYMBOL(open_private_file);
+@@ -190,79 +151,20 @@ EXPORT_SYMBOL(filp_open);
+ EXPORT_SYMBOL(filp_close);
+ EXPORT_SYMBOL(put_filp);
+ EXPORT_SYMBOL(files_lock);
+-EXPORT_SYMBOL(check_disk_change);
+-EXPORT_SYMBOL(invalidate_bdev);
+-EXPORT_SYMBOL(invalidate_inodes);
+-EXPORT_SYMBOL(__invalidate_device);
+ EXPORT_SYMBOL(invalidate_inode_pages);
+ EXPORT_SYMBOL_GPL(invalidate_inode_pages2);
+ EXPORT_SYMBOL(truncate_inode_pages);
+-EXPORT_SYMBOL(fsync_bdev);
+-EXPORT_SYMBOL(permission);
+-EXPORT_SYMBOL(vfs_permission);
+ EXPORT_SYMBOL(inode_setattr);
+ EXPORT_SYMBOL(inode_change_ok);
+ EXPORT_SYMBOL(write_inode_now);
+ EXPORT_SYMBOL(notify_change);
+-EXPORT_SYMBOL(set_blocksize);
+-EXPORT_SYMBOL(sb_set_blocksize);
+-EXPORT_SYMBOL(sb_min_blocksize);
+-EXPORT_SYMBOL(bdget);
+-EXPORT_SYMBOL(bdput);
+-EXPORT_SYMBOL(bd_claim);
+-EXPORT_SYMBOL(bd_release);
+-EXPORT_SYMBOL(open_bdev_excl);
+-EXPORT_SYMBOL(close_bdev_excl);
+-EXPORT_SYMBOL(open_by_devnum);
+-EXPORT_SYMBOL(__brelse);
+-EXPORT_SYMBOL(__bforget);
+-EXPORT_SYMBOL(ll_rw_block);
+-EXPORT_SYMBOL(sync_dirty_buffer);
+-EXPORT_SYMBOL(submit_bh);
+-EXPORT_SYMBOL(unlock_buffer);
+-EXPORT_SYMBOL(__wait_on_buffer);
+-EXPORT_SYMBOL(blockdev_direct_IO);
+-EXPORT_SYMBOL(block_write_full_page);
+-EXPORT_SYMBOL(block_read_full_page);
+-EXPORT_SYMBOL(block_prepare_write);
+-EXPORT_SYMBOL(block_sync_page);
+-EXPORT_SYMBOL(generic_cont_expand);
+-EXPORT_SYMBOL(cont_prepare_write);
+-EXPORT_SYMBOL(generic_commit_write);
+-EXPORT_SYMBOL(block_commit_write);
+-EXPORT_SYMBOL(block_truncate_page);
+-EXPORT_SYMBOL(generic_block_bmap);
+-EXPORT_SYMBOL(generic_file_read);
+-EXPORT_SYMBOL(generic_file_sendfile);
+-EXPORT_SYMBOL(do_generic_mapping_read);
+ EXPORT_SYMBOL(file_ra_state_init);
+-EXPORT_SYMBOL(generic_file_write);
+-EXPORT_SYMBOL(generic_file_write_nolock);
+-EXPORT_SYMBOL(generic_file_mmap);
+-EXPORT_SYMBOL(generic_file_readonly_mmap);
+ EXPORT_SYMBOL(generic_ro_fops);
+-EXPORT_SYMBOL(dput);
+-EXPORT_SYMBOL(have_submounts);
+-EXPORT_SYMBOL(d_find_alias);
+-EXPORT_SYMBOL(d_prune_aliases);
+-EXPORT_SYMBOL(shrink_dcache_sb);
+-EXPORT_SYMBOL(shrink_dcache_parent);
+-EXPORT_SYMBOL(shrink_dcache_anon);
+-EXPORT_SYMBOL(find_inode_number);
+-EXPORT_SYMBOL(is_subdir);
+ EXPORT_SYMBOL(get_unused_fd);
+ EXPORT_SYMBOL(vfs_read);
+ EXPORT_SYMBOL(vfs_readv);
+ EXPORT_SYMBOL(vfs_write);
+ EXPORT_SYMBOL(vfs_writev);
+-EXPORT_SYMBOL(vfs_create);
+-EXPORT_SYMBOL(vfs_mkdir);
+-EXPORT_SYMBOL(vfs_mknod);
+-EXPORT_SYMBOL(vfs_symlink);
+-EXPORT_SYMBOL(vfs_link);
+-EXPORT_SYMBOL(vfs_rmdir);
+-EXPORT_SYMBOL(vfs_unlink);
+-EXPORT_SYMBOL(vfs_rename);
+ EXPORT_SYMBOL(vfs_statfs);
+ EXPORT_SYMBOL(vfs_fstat);
+ EXPORT_SYMBOL(vfs_stat);
+@@ -272,9 +174,6 @@ EXPORT_SYMBOL(inode_add_bytes);
+ EXPORT_SYMBOL(inode_sub_bytes);
+ EXPORT_SYMBOL(inode_get_bytes);
+ EXPORT_SYMBOL(inode_set_bytes);
+-EXPORT_SYMBOL(lock_rename);
+-EXPORT_SYMBOL(unlock_rename);
+-EXPORT_SYMBOL(generic_read_dir);
+ EXPORT_SYMBOL(generic_fillattr);
+ EXPORT_SYMBOL(generic_file_llseek);
+ EXPORT_SYMBOL(remote_llseek);
+@@ -282,70 +181,21 @@ EXPORT_SYMBOL(no_llseek);
+ EXPORT_SYMBOL(poll_initwait);
+ EXPORT_SYMBOL(poll_freewait);
+ EXPORT_SYMBOL(ROOT_DEV);
+-EXPORT_SYMBOL(find_get_page);
+-EXPORT_SYMBOL(find_lock_page);
+-EXPORT_SYMBOL(find_trylock_page);
+-EXPORT_SYMBOL(find_or_create_page);
+-EXPORT_SYMBOL(grab_cache_page_nowait);
+-EXPORT_SYMBOL(read_cache_page);
+ EXPORT_SYMBOL(read_cache_pages);
+ EXPORT_SYMBOL(mark_page_accessed);
+-EXPORT_SYMBOL(vfs_readlink);
+-EXPORT_SYMBOL(vfs_follow_link);
+-EXPORT_SYMBOL(page_readlink);
+-EXPORT_SYMBOL(page_follow_link);
+-EXPORT_SYMBOL(page_symlink_inode_operations);
+-EXPORT_SYMBOL(page_symlink);
+ EXPORT_SYMBOL(vfs_readdir);
+ EXPORT_SYMBOL(__break_lease);
+ EXPORT_SYMBOL(lease_get_mtime);
+ EXPORT_SYMBOL(lock_may_read);
+ EXPORT_SYMBOL(lock_may_write);
+-EXPORT_SYMBOL(dcache_dir_open);
+-EXPORT_SYMBOL(dcache_dir_close);
+-EXPORT_SYMBOL(dcache_dir_lseek);
+-EXPORT_SYMBOL(dcache_readdir);
+-EXPORT_SYMBOL(simple_getattr);
+-EXPORT_SYMBOL(simple_statfs);
+-EXPORT_SYMBOL(simple_lookup);
+-EXPORT_SYMBOL(simple_dir_operations);
+-EXPORT_SYMBOL(simple_dir_inode_operations);
+-EXPORT_SYMBOL(simple_link);
+-EXPORT_SYMBOL(simple_unlink);
+-EXPORT_SYMBOL(simple_rmdir);
+-EXPORT_SYMBOL(simple_rename);
+-EXPORT_SYMBOL(simple_sync_file);
+-EXPORT_SYMBOL(simple_readpage);
+-EXPORT_SYMBOL(simple_prepare_write);
+-EXPORT_SYMBOL(simple_commit_write);
+-EXPORT_SYMBOL(simple_empty);
+-EXPORT_SYMBOL(simple_fill_super);
+-EXPORT_SYMBOL(simple_pin_fs);
+-EXPORT_SYMBOL(simple_release_fs);
+ EXPORT_SYMBOL(fd_install);
+ EXPORT_SYMBOL(put_unused_fd);
+-EXPORT_SYMBOL(get_sb_bdev);
+-EXPORT_SYMBOL(kill_block_super);
+-EXPORT_SYMBOL(get_sb_nodev);
+-EXPORT_SYMBOL(get_sb_single);
+-EXPORT_SYMBOL(kill_anon_super);
+-EXPORT_SYMBOL(kill_litter_super);
+-EXPORT_SYMBOL(generic_shutdown_super);
+-EXPORT_SYMBOL(deactivate_super);
+-EXPORT_SYMBOL(sget);
+-EXPORT_SYMBOL(set_anon_super);
+ EXPORT_SYMBOL(do_select);
+ /* for stackable file systems (lofs, wrapfs, cryptfs, etc.) */
+ EXPORT_SYMBOL(default_llseek);
+ EXPORT_SYMBOL(dentry_open);
+-#ifdef CONFIG_MMU
+-EXPORT_SYMBOL(filemap_nopage);
+-#endif
+-EXPORT_SYMBOL(filemap_fdatawrite);
+-EXPORT_SYMBOL(filemap_fdatawait);
+ EXPORT_SYMBOL(lock_page);
+-EXPORT_SYMBOL(unlock_page);
+ /* device registration */
+ EXPORT_SYMBOL(register_blkdev);
+@@ -355,16 +205,7 @@ EXPORT_SYMBOL(tty_unregister_driver);
+ EXPORT_SYMBOL(tty_std_termios);
+ /* block device driver support */
+-EXPORT_SYMBOL(bmap);
+-EXPORT_SYMBOL(blkdev_open);
+-EXPORT_SYMBOL(blkdev_get);
+-EXPORT_SYMBOL(blkdev_put);
+-EXPORT_SYMBOL(ioctl_by_bdev);
+ EXPORT_SYMBOL(read_dev_sector);
+-EXPORT_SYMBOL(init_buffer);
+-EXPORT_SYMBOL_GPL(generic_file_direct_IO);
+-EXPORT_SYMBOL(generic_file_readv);
+-EXPORT_SYMBOL(generic_file_writev);
+ EXPORT_SYMBOL(iov_shorten);
+ EXPORT_SYMBOL_GPL(default_backing_dev_info);
+@@ -375,32 +216,9 @@ EXPORT_SYMBOL(tty_flip_buffer_push);
+ /* filesystem registration */
+ EXPORT_SYMBOL(register_filesystem);
+ EXPORT_SYMBOL(unregister_filesystem);
+-EXPORT_SYMBOL(kern_mount);
+ EXPORT_SYMBOL(__mntput);
+ EXPORT_SYMBOL(may_umount);
+-/* executable format registration */
+-EXPORT_SYMBOL(register_binfmt);
+-EXPORT_SYMBOL(unregister_binfmt);
+-EXPORT_SYMBOL(search_binary_handler);
+-EXPORT_SYMBOL(prepare_binprm);
+-EXPORT_SYMBOL(compute_creds);
+-EXPORT_SYMBOL(remove_arg_zero);
+-EXPORT_SYMBOL(set_binfmt);
+-
+-/* sysctl table registration */
+-EXPORT_SYMBOL(register_sysctl_table);
+-EXPORT_SYMBOL(unregister_sysctl_table);
+-EXPORT_SYMBOL(sysctl_string);
+-EXPORT_SYMBOL(sysctl_intvec);
+-EXPORT_SYMBOL(sysctl_jiffies);
+-EXPORT_SYMBOL(proc_dostring);
+-EXPORT_SYMBOL(proc_dointvec);
+-EXPORT_SYMBOL(proc_dointvec_jiffies);
+-EXPORT_SYMBOL(proc_dointvec_minmax);
+-EXPORT_SYMBOL(proc_doulongvec_ms_jiffies_minmax);
+-EXPORT_SYMBOL(proc_doulongvec_minmax);
+-
+ /* interrupt handling */
+ EXPORT_SYMBOL(request_irq);
+ EXPORT_SYMBOL(free_irq);
+@@ -414,10 +232,6 @@ EXPORT_SYMBOL(prepare_to_wait_exclusive)
+ EXPORT_SYMBOL(finish_wait);
+ EXPORT_SYMBOL(autoremove_wake_function);
+-/* completion handling */
+-EXPORT_SYMBOL(wait_for_completion);
+-EXPORT_SYMBOL(complete);
+-
+ /* The notion of irq probe/assignment is foreign to S/390 */
+ #if !defined(CONFIG_ARCH_S390)
+@@ -449,30 +263,11 @@ EXPORT_SYMBOL(iomem_resource);
+ /* process management */
+ EXPORT_SYMBOL(complete_and_exit);
+-EXPORT_SYMBOL(default_wake_function);
+-EXPORT_SYMBOL(__wake_up);
+ #ifdef CONFIG_SMP
+ EXPORT_SYMBOL_GPL(__wake_up_sync); /* internal use only */
+ #endif
+-EXPORT_SYMBOL(wake_up_process);
+-EXPORT_SYMBOL(sleep_on);
+-EXPORT_SYMBOL(sleep_on_timeout);
+-EXPORT_SYMBOL(interruptible_sleep_on);
+-EXPORT_SYMBOL(interruptible_sleep_on_timeout);
+-EXPORT_SYMBOL(schedule);
+-#ifdef CONFIG_PREEMPT
+-EXPORT_SYMBOL(preempt_schedule);
+-#endif
+ EXPORT_SYMBOL(schedule_timeout);
+-EXPORT_SYMBOL(yield);
+-EXPORT_SYMBOL(io_schedule);
+-EXPORT_SYMBOL(__cond_resched);
+-EXPORT_SYMBOL(set_user_nice);
+-EXPORT_SYMBOL(task_nice);
+ EXPORT_SYMBOL_GPL(idle_cpu);
+-#ifdef CONFIG_SMP
+-EXPORT_SYMBOL_GPL(set_cpus_allowed);
+-#endif
+ #if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
+ EXPORT_SYMBOL(kernel_flag);
+ #endif
+@@ -485,18 +280,10 @@ EXPORT_SYMBOL(do_settimeofday);
+ #if (BITS_PER_LONG < 64)
+ EXPORT_SYMBOL(get_jiffies_64);
+ #endif
+-#ifdef CONFIG_DEBUG_SPINLOCK_SLEEP
+-EXPORT_SYMBOL(__might_sleep);
+-#endif
+-#if defined(CONFIG_SMP) && defined(CONFIG_PREEMPT)
+-EXPORT_SYMBOL(__preempt_spin_lock);
+-EXPORT_SYMBOL(__preempt_write_lock);
+-#endif
+ #if !defined(__ia64__)
+ EXPORT_SYMBOL(loops_per_jiffy);
+ #endif
+-
+ /* misc */
+ EXPORT_SYMBOL(panic);
+ EXPORT_SYMBOL(panic_notifier_list);
+@@ -524,45 +311,16 @@ EXPORT_SYMBOL(securebits);
+ EXPORT_SYMBOL(cap_bset);
+ EXPORT_SYMBOL(daemonize);
+ EXPORT_SYMBOL(csum_partial); /* for networking and md */
+-EXPORT_SYMBOL(seq_escape);
+-EXPORT_SYMBOL(seq_printf);
+-EXPORT_SYMBOL(seq_path);
+-EXPORT_SYMBOL(seq_open);
+-EXPORT_SYMBOL(seq_release);
+-EXPORT_SYMBOL(seq_read);
+-EXPORT_SYMBOL(seq_lseek);
+-EXPORT_SYMBOL(single_open);
+-EXPORT_SYMBOL(single_release);
+-EXPORT_SYMBOL(seq_release_private);
+-
+-/* Program loader interfaces */
+-#ifdef CONFIG_MMU
+-EXPORT_SYMBOL(setup_arg_pages);
+-#endif
+-EXPORT_SYMBOL(copy_strings_kernel);
+-EXPORT_SYMBOL(do_execve);
+-EXPORT_SYMBOL(flush_old_exec);
+-EXPORT_SYMBOL(kernel_read);
+-EXPORT_SYMBOL(open_exec);
+ /* Miscellaneous access points */
+ EXPORT_SYMBOL(si_meminfo);
+ /* Added to make file system as module */
+ EXPORT_SYMBOL(sys_tz);
+-EXPORT_SYMBOL(file_fsync);
+-EXPORT_SYMBOL(fsync_buffers_list);
+-EXPORT_SYMBOL(clear_inode);
+-EXPORT_SYMBOL(init_special_inode);
+-EXPORT_SYMBOL(new_inode);
+-EXPORT_SYMBOL(__insert_inode_hash);
+-EXPORT_SYMBOL(remove_inode_hash);
+-EXPORT_SYMBOL(buffer_insert_list);
+ EXPORT_SYMBOL(make_bad_inode);
+ EXPORT_SYMBOL(is_bad_inode);
+ EXPORT_SYMBOL(__inode_dir_notify);
+ EXPORT_SYMBOL(generic_osync_inode);
+-EXPORT_SYMBOL(remove_suid);
+ #ifdef CONFIG_UID16
+ EXPORT_SYMBOL(overflowuid);
+@@ -575,9 +333,6 @@ EXPORT_SYMBOL(fs_overflowgid);
+ EXPORT_SYMBOL(fasync_helper);
+ EXPORT_SYMBOL(kill_fasync);
+-/* binfmt_aout */
+-EXPORT_SYMBOL(get_write_access);
+-
+ /* library functions */
+ EXPORT_SYMBOL(strnicmp);
+ EXPORT_SYMBOL(strspn);
+@@ -607,6 +362,16 @@ EXPORT_SYMBOL(__per_cpu_offset);
+ EXPORT_SYMBOL(set_fs_pwd);
+ EXPORT_SYMBOL(set_fs_root);
++#if defined(CONFIG_LOCKMETER)
++EXPORT_SYMBOL(_metered_spin_lock);
++EXPORT_SYMBOL(_metered_spin_unlock);
++EXPORT_SYMBOL(_metered_spin_trylock);
++EXPORT_SYMBOL(_metered_read_lock);
++EXPORT_SYMBOL(_metered_read_unlock);
++EXPORT_SYMBOL(_metered_write_lock);
++EXPORT_SYMBOL(_metered_write_unlock);
++#endif
++
+ /* debug */
+ EXPORT_SYMBOL(dump_stack);
+ EXPORT_SYMBOL(ptrace_notify);
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/kernel/lockmeter.c      2003-10-05 00:36:40.000000000 -0700
+@@ -0,0 +1,1169 @@
++/*
++ *  Copyright (C) 1999,2000 Silicon Graphics, Inc.
++ *
++ *  Written by John Hawkes (hawkes@sgi.com)
++ *  Based on klstat.c by Jack Steiner (steiner@sgi.com)
++ *
++ *  Modified by Ray Bryant (raybry@us.ibm.com)
++ *  Changes Copyright (C) 2000 IBM, Inc.
++ *  Added save of index in spinlock_t to improve efficiency
++ *  of "hold" time reporting for spinlocks
++ *  Added support for hold time statistics for read and write
++ *  locks.
++ */
++
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/sched.h>
++#include <linux/smp.h>
++#include <linux/threads.h>
++#include <linux/version.h>
++#include <linux/vmalloc.h>
++#include <linux/spinlock.h>
++#include <linux/utsname.h>
++#include <asm/system.h>
++#include <asm/uaccess.h>
++
++#include <linux/lockmeter.h>
++
++#define ASSERT(cond)
++#define bzero(loc,size)               memset(loc,0,size)
++
++/*<---------------------------------------------------*/
++/*              lockmeter.c                           */
++/*>---------------------------------------------------*/
++
++static lstat_control_t lstat_control __cacheline_aligned =
++      { LSTAT_OFF, SPIN_LOCK_UNLOCKED, SPIN_LOCK_UNLOCKED,
++        19 * 0, NR_CPUS * 0, 0, NR_CPUS * 0 };
++
++static ushort lstat_make_dir_entry(void *, void *);
++
++/*
++ * lstat_lookup
++ *
++ * Given a RA, locate the directory entry for the lock.
++ */
++static ushort
++lstat_lookup(void *lock_ptr, void *caller_ra)
++{
++      ushort index;
++      lstat_directory_entry_t *dirp;
++
++      dirp = lstat_control.dir;
++
++      index = lstat_control.hashtab[DIRHASH(caller_ra)];
++      while (dirp[index].caller_ra != caller_ra) {
++              if (index == 0) {
++                      return lstat_make_dir_entry(lock_ptr, caller_ra);
++              }
++              index = dirp[index].next_stat_index;
++      }
++
++      if (dirp[index].lock_ptr != NULL && dirp[index].lock_ptr != lock_ptr) {
++              dirp[index].lock_ptr = NULL;
++      }
++
++      return index;
++}
++
++/*
++ * lstat_make_dir_entry
++ * Called to add a new lock to the lock directory.
++ */
++static ushort
++lstat_make_dir_entry(void *lock_ptr, void *caller_ra)
++{
++      lstat_directory_entry_t *dirp;
++      ushort index, hindex;
++      unsigned long flags;
++
++      /* lock the table without recursively reentering this metering code */
++      local_irq_save(flags);
++      _raw_spin_lock(&lstat_control.directory_lock);
++
++      hindex = DIRHASH(caller_ra);
++      index = lstat_control.hashtab[hindex];
++      dirp = lstat_control.dir;
++      while (index && dirp[index].caller_ra != caller_ra)
++              index = dirp[index].next_stat_index;
++
++      if (index == 0) {
++              if (lstat_control.next_free_dir_index < LSTAT_MAX_STAT_INDEX) {
++                      index = lstat_control.next_free_dir_index++;
++                      lstat_control.dir[index].caller_ra = caller_ra;
++                      lstat_control.dir[index].lock_ptr = lock_ptr;
++                      lstat_control.dir[index].next_stat_index =
++                              lstat_control.hashtab[hindex];
++                      lstat_control.hashtab[hindex] = index;
++              } else {
++                      lstat_control.dir_overflow++;
++              }
++      }
++      _raw_spin_unlock(&lstat_control.directory_lock);
++      local_irq_restore(flags);
++      return index;
++}
++
++int
++lstat_update(void *lock_ptr, void *caller_ra, int action)
++{
++      int index;
++      int cpu;
++
++      ASSERT(action < LSTAT_ACT_MAX_VALUES);
++
++      if (lstat_control.state == LSTAT_OFF)
++              return 0;
++
++      index = lstat_lookup(lock_ptr, caller_ra);
++      cpu = THIS_CPU_NUMBER;
++      (*lstat_control.counts[cpu])[index].count[action]++;
++      (*lstat_control.counts[cpu])[index].acquire_time = get_cycles();
++
++      return index;
++}
++
++int
++lstat_update_time(void *lock_ptr, void *caller_ra, int action, uint32_t ticks)
++{
++      ushort index;
++      int cpu;
++
++      ASSERT(action < LSTAT_ACT_MAX_VALUES);
++
++      if (lstat_control.state == LSTAT_OFF)
++              return 0;
++
++      index = lstat_lookup(lock_ptr, caller_ra);
++      cpu = THIS_CPU_NUMBER;
++      (*lstat_control.counts[cpu])[index].count[action]++;
++      (*lstat_control.counts[cpu])[index].cum_wait_ticks += (uint64_t) ticks;
++      if ((*lstat_control.counts[cpu])[index].max_wait_ticks < ticks)
++              (*lstat_control.counts[cpu])[index].max_wait_ticks = ticks;
++
++      (*lstat_control.counts[cpu])[index].acquire_time = get_cycles();
++
++      return index;
++}
++
++void
++_metered_spin_lock(spinlock_t * lock_ptr)
++{
++      if (lstat_control.state == LSTAT_OFF) {
++              _raw_spin_lock(lock_ptr);       /* do the real lock */
++              PUT_INDEX(lock_ptr, 0); /* clean index in case lockmetering  */
++              /* gets turned on before unlock */
++      } else {
++              void *this_pc = LSTAT_RA(LSTAT_RA_SPIN);
++              int index;
++
++              if (_raw_spin_trylock(lock_ptr)) {
++                      index = lstat_update(lock_ptr, this_pc,
++                                              LSTAT_ACT_NO_WAIT);
++              } else {
++                      uint32_t start_cycles = get_cycles();
++                      _raw_spin_lock(lock_ptr);       /* do the real lock */
++                      index = lstat_update_time(lock_ptr, this_pc,
++                              LSTAT_ACT_SPIN, get_cycles() - start_cycles);
++              }
++              /* save the index in the lock itself for use in spin unlock */
++              PUT_INDEX(lock_ptr, index);
++      }
++}
++
++int
++_metered_spin_trylock(spinlock_t * lock_ptr)
++{
++      if (lstat_control.state == LSTAT_OFF) {
++              return _raw_spin_trylock(lock_ptr);
++      } else {
++              int retval;
++              void *this_pc = LSTAT_RA(LSTAT_RA_SPIN);
++
++              if ((retval = _raw_spin_trylock(lock_ptr))) {
++                      int index = lstat_update(lock_ptr, this_pc,
++                                              LSTAT_ACT_NO_WAIT);
++                      /*
++                       * save the index in the lock itself for use in spin
++                       * unlock
++                       */
++                      PUT_INDEX(lock_ptr, index);
++              } else {
++                      lstat_update(lock_ptr, this_pc, LSTAT_ACT_REJECT);
++              }
++
++              return retval;
++      }
++}
++
++void
++_metered_spin_unlock(spinlock_t * lock_ptr)
++{
++      int index = -1;
++
++      if (lstat_control.state != LSTAT_OFF) {
++              index = GET_INDEX(lock_ptr);
++              /*
++               * If statistics were turned off when we set the lock,
++               * then the index can be zero.  If that is the case,
++               * then collect no stats on this call.
++               */
++              if (index > 0) {
++                      uint32_t hold_time;
++                      int cpu = THIS_CPU_NUMBER;
++                      hold_time = get_cycles() -
++                       (*lstat_control.counts[cpu])[index].acquire_time;
++                      (*lstat_control.counts[cpu])[index].cum_hold_ticks +=
++                              (uint64_t) hold_time;
++                      if ((*lstat_control.counts[cpu])[index].max_hold_ticks <
++                          hold_time)
++                              (*lstat_control.counts[cpu])[index].
++                                  max_hold_ticks = hold_time;
++              }
++      }
++
++      /* make sure we don't have a stale index value saved */
++      PUT_INDEX(lock_ptr, 0);
++      _raw_spin_unlock(lock_ptr);     /* do the real unlock */
++}
++
++/*
++ * allocate the next global read lock structure and store its index
++ * in the rwlock at "lock_ptr".
++ */
++uint32_t
++alloc_rwlock_struct(rwlock_t * rwlock_ptr)
++{
++      int index;
++      unsigned long flags;
++      int cpu = THIS_CPU_NUMBER;
++
++      /* If we've already overflowed, then do a quick exit */
++      if (lstat_control.next_free_read_lock_index >
++                      LSTAT_MAX_READ_LOCK_INDEX) {
++              lstat_control.rwlock_overflow++;
++              return 0;
++      }
++
++      local_irq_save(flags);
++      _raw_spin_lock(&lstat_control.directory_lock);
++
++      /* It is possible this changed while we were waiting for the directory_lock */
++      if (lstat_control.state == LSTAT_OFF) {
++              index = 0;
++              goto unlock;
++      }
++
++      /* It is possible someone else got here first and set the index */
++      if ((index = GET_RWINDEX(rwlock_ptr)) == 0) {
++              /*
++               * we can't turn on read stats for this lock while there are
++               * readers (this would mess up the running hold time sum at
++               * unlock time)
++               */
++              if (RWLOCK_READERS(rwlock_ptr) != 0) {
++                      index = 0;
++                      goto unlock;
++              }
++
++              /*
++               * if stats are turned on after being off, we may need to
++               * return an old index from when the statistics were on last
++               * time.
++               */
++              for (index = 1; index < lstat_control.next_free_read_lock_index;
++                              index++)
++                      if ((*lstat_control.read_lock_counts[cpu])[index].
++                                      lock_ptr == rwlock_ptr)
++                              goto put_index_and_unlock;
++
++              /* allocate the next global read lock structure */
++              if (lstat_control.next_free_read_lock_index >=
++                  LSTAT_MAX_READ_LOCK_INDEX) {
++                      lstat_control.rwlock_overflow++;
++                      index = 0;
++                      goto unlock;
++              }
++              index = lstat_control.next_free_read_lock_index++;
++
++              /*
++               * initialize the global read stats data structure for each
++               * cpu
++               */
++              for (cpu = 0; cpu < num_online_cpus(); cpu++) {
++                      (*lstat_control.read_lock_counts[cpu])[index].lock_ptr =
++                              rwlock_ptr;
++              }
++put_index_and_unlock:
++              /* store the index for the read lock structure into the lock */
++              PUT_RWINDEX(rwlock_ptr, index);
++      }
++
++unlock:
++      _raw_spin_unlock(&lstat_control.directory_lock);
++      local_irq_restore(flags);
++      return index;
++}
++
++void
++_metered_read_lock(rwlock_t * rwlock_ptr)
++{
++      void *this_pc;
++      uint32_t start_cycles;
++      int index;
++      int cpu;
++      unsigned long flags;
++      int readers_before, readers_after;
++      uint64_t cycles64;
++
++      if (lstat_control.state == LSTAT_OFF) {
++              _raw_read_lock(rwlock_ptr);
++              /* clean index in case lockmetering turns on before an unlock */
++              PUT_RWINDEX(rwlock_ptr, 0);
++              return;
++      }
++
++      this_pc = LSTAT_RA(LSTAT_RA_READ);
++      cpu = THIS_CPU_NUMBER;
++      index = GET_RWINDEX(rwlock_ptr);
++
++      /* allocate the global stats entry for this lock, if needed */
++      if (index == 0)
++              index = alloc_rwlock_struct(rwlock_ptr);
++
++      readers_before = RWLOCK_READERS(rwlock_ptr);
++      if (_raw_read_trylock(rwlock_ptr)) {
++              /*
++               * We have decremented the lock to count a new reader,
++               * and have confirmed that no writer has it locked.
++               */
++              /* update statistics if enabled */
++              if (index > 0) {
++                      local_irq_save(flags);
++                      lstat_update((void *) rwlock_ptr, this_pc,
++                                      LSTAT_ACT_NO_WAIT);
++                      /* preserve value of TSC so cum_hold_ticks and start_busy use same value */
++                      cycles64 = get_cycles64();
++                      (*lstat_control.read_lock_counts[cpu])[index].
++                              cum_hold_ticks -= cycles64;
++
++                      /* record time and cpu of start of busy period */
++                      /* this is not perfect (some race conditions are possible) */
++                      if (readers_before == 0) {
++                              (*lstat_control.read_lock_counts[cpu])[index].
++                                      start_busy = cycles64;
++                              PUT_RW_CPU(rwlock_ptr, cpu);
++                      }
++                      readers_after = RWLOCK_READERS(rwlock_ptr);
++                      if (readers_after >
++                              (*lstat_control.read_lock_counts[cpu])[index].
++                                      max_readers)
++                              (*lstat_control.read_lock_counts[cpu])[index].
++                                      max_readers = readers_after;
++                      local_irq_restore(flags);
++              }
++
++              return;
++      }
++      /* If we get here, then we could not quickly grab the read lock */
++
++      start_cycles = get_cycles();    /* start counting the wait time */
++
++      /* Now spin until read_lock is successful */
++      _raw_read_lock(rwlock_ptr);
++
++      lstat_update_time((void *) rwlock_ptr, this_pc, LSTAT_ACT_SPIN,
++                        get_cycles() - start_cycles);
++
++      /* update statistics if they are enabled for this lock */
++      if (index > 0) {
++              local_irq_save(flags);
++              cycles64 = get_cycles64();
++              (*lstat_control.read_lock_counts[cpu])[index].cum_hold_ticks -=
++                              cycles64;
++
++              /* this is not perfect (some race conditions are possible) */
++              if (readers_before == 0) {
++                      (*lstat_control.read_lock_counts[cpu])[index].
++                              start_busy = cycles64;
++                      PUT_RW_CPU(rwlock_ptr, cpu);
++              }
++              readers_after = RWLOCK_READERS(rwlock_ptr);
++              if (readers_after >
++                  (*lstat_control.read_lock_counts[cpu])[index].max_readers)
++                      (*lstat_control.read_lock_counts[cpu])[index].
++                              max_readers = readers_after;
++              local_irq_restore(flags);
++      }
++}
++
++void
++_metered_read_unlock(rwlock_t * rwlock_ptr)
++{
++      int index;
++      int cpu;
++      unsigned long flags;
++      uint64_t busy_length;
++      uint64_t cycles64;
++
++      if (lstat_control.state == LSTAT_OFF) {
++              _raw_read_unlock(rwlock_ptr);
++              return;
++      }
++
++      index = GET_RWINDEX(rwlock_ptr);
++      cpu = THIS_CPU_NUMBER;
++
++      if (index > 0) {
++              local_irq_save(flags);
++              /*
++               * preserve value of TSC so cum_hold_ticks and busy_ticks are
++               * consistent.
++               */
++              cycles64 = get_cycles64();
++              (*lstat_control.read_lock_counts[cpu])[index].cum_hold_ticks +=
++                      cycles64;
++              (*lstat_control.read_lock_counts[cpu])[index].read_lock_count++;
++
++              /*
++               * once again, this is not perfect (some race conditions are
++               * possible)
++               */
++              if (RWLOCK_READERS(rwlock_ptr) == 1) {
++                      int cpu1 = GET_RW_CPU(rwlock_ptr);
++                      uint64_t last_start_busy =
++                              (*lstat_control.read_lock_counts[cpu1])[index].
++                                      start_busy;
++                      (*lstat_control.read_lock_counts[cpu])[index].
++                              busy_periods++;
++                      if (cycles64 > last_start_busy) {
++                              busy_length = cycles64 - last_start_busy;
++                              (*lstat_control.read_lock_counts[cpu])[index].
++                                      busy_ticks += busy_length;
++                              if (busy_length >
++                                      (*lstat_control.
++                                              read_lock_counts[cpu])[index].
++                                                      max_busy)
++                                      (*lstat_control.
++                                       read_lock_counts[cpu])[index].
++                                              max_busy = busy_length;
++                      }
++              }
++              local_irq_restore(flags);
++      }
++      _raw_read_unlock(rwlock_ptr);
++}
++
++void
++_metered_write_lock(rwlock_t * rwlock_ptr)
++{
++      uint32_t start_cycles;
++      void *this_pc;
++      uint32_t spin_ticks = 0; /* in anticipation of a potential wait */
++      int index;
++      int write_index = 0;
++      int cpu;
++      enum {
++              writer_writer_conflict,
++              writer_reader_conflict
++      } why_wait = writer_writer_conflict;
++
++      if (lstat_control.state == LSTAT_OFF) {
++              _raw_write_lock(rwlock_ptr);
++              /* clean index in case lockmetering turns on before an unlock */
++              PUT_RWINDEX(rwlock_ptr, 0);
++              return;
++      }
++
++      this_pc = LSTAT_RA(LSTAT_RA_WRITE);
++      cpu = THIS_CPU_NUMBER;
++      index = GET_RWINDEX(rwlock_ptr);
++
++      /* allocate the global stats entry for this lock, if needed */
++      if (index == 0) {
++              index = alloc_rwlock_struct(rwlock_ptr);
++      }
++
++      if (_raw_write_trylock(rwlock_ptr)) {
++              /* We acquired the lock on the first try */
++              write_index = lstat_update((void *) rwlock_ptr, this_pc,
++                                      LSTAT_ACT_NO_WAIT);
++              /* save the write_index for use in unlock if stats enabled */
++              if (index > 0)
++                      (*lstat_control.read_lock_counts[cpu])[index].
++                              write_index = write_index;
++              return;
++      }
++
++      /* If we get here, then we could not quickly grab the write lock */
++      start_cycles = get_cycles();    /* start counting the wait time */
++
++      why_wait = RWLOCK_READERS(rwlock_ptr) ?
++                      writer_reader_conflict : writer_writer_conflict;
++
++      /* Now set the lock and wait for conflicts to disappear */
++      _raw_write_lock(rwlock_ptr);
++
++      spin_ticks = get_cycles() - start_cycles;
++
++      /* update stats -- if enabled */
++      if (index > 0 && spin_ticks) {
++              if (why_wait == writer_reader_conflict) {
++                      /* waited due to a reader holding the lock */
++                      write_index = lstat_update_time((void *)rwlock_ptr,
++                                      this_pc, LSTAT_ACT_SPIN, spin_ticks);
++              } else {
++                      /*
++                       * waited due to another writer holding the lock
++                       */
++                      write_index = lstat_update_time((void *)rwlock_ptr,
++                              this_pc, LSTAT_ACT_WW_SPIN, spin_ticks);
++                      (*lstat_control.counts[cpu])[write_index].
++                              cum_wait_ww_ticks += spin_ticks;
++                      if (spin_ticks >
++                              (*lstat_control.counts[cpu])[write_index].
++                                      max_wait_ww_ticks) {
++                              (*lstat_control.counts[cpu])[write_index].
++                                      max_wait_ww_ticks = spin_ticks;
++                      }
++              }
++
++              /* save the directory index for use on write_unlock */
++              (*lstat_control.read_lock_counts[cpu])[index].
++                      write_index = write_index;
++      }
++}
++
++void
++_metered_write_unlock(rwlock_t * rwlock_ptr)
++{
++      int index;
++      int cpu;
++      int write_index;
++      uint32_t hold_time;
++
++      if (lstat_control.state == LSTAT_OFF) {
++              _raw_write_unlock(rwlock_ptr);
++              return;
++      }
++
++      cpu = THIS_CPU_NUMBER;
++      index = GET_RWINDEX(rwlock_ptr);
++
++      /* update statistics if stats enabled for this lock */
++      if (index > 0) {
++              write_index =
++                  (*lstat_control.read_lock_counts[cpu])[index].write_index;
++
++              hold_time = get_cycles() -
++                      (*lstat_control.counts[cpu])[write_index].acquire_time;
++              (*lstat_control.counts[cpu])[write_index].cum_hold_ticks +=
++                      (uint64_t) hold_time;
++              if ((*lstat_control.counts[cpu])[write_index].max_hold_ticks <
++                              hold_time)
++                      (*lstat_control.counts[cpu])[write_index].
++                              max_hold_ticks = hold_time;
++      }
++      _raw_write_unlock(rwlock_ptr);
++}
++
++int
++_metered_write_trylock(rwlock_t * rwlock_ptr)
++{
++      int retval;
++      void *this_pc = LSTAT_RA(LSTAT_RA_WRITE);
++
++      if ((retval = _raw_write_trylock(rwlock_ptr))) {
++              lstat_update(rwlock_ptr, this_pc, LSTAT_ACT_NO_WAIT);
++      } else {
++              lstat_update(rwlock_ptr, this_pc, LSTAT_ACT_REJECT);
++      }
++
++      return retval;
++}
++
++static void
++init_control_space(void)
++{
++      /* Set all control space pointers to null and indices to "empty" */
++      int cpu;
++
++      /*
++       * Access CPU_CYCLE_FREQUENCY at the outset, which in some
++       * architectures may trigger a runtime calculation that uses a
++       * spinlock.  Let's do this before lockmetering is turned on.
++       */
++      if (CPU_CYCLE_FREQUENCY == 0)
++              BUG();
++
++      lstat_control.hashtab = NULL;
++      lstat_control.dir = NULL;
++      for (cpu = 0; cpu < NR_CPUS; cpu++) {
++              lstat_control.counts[cpu] = NULL;
++              lstat_control.read_lock_counts[cpu] = NULL;
++      }
++}
++
++static int
++reset_lstat_data(void)
++{
++      int cpu, flags;
++
++      flags = 0;
++      lstat_control.next_free_dir_index = 1;  /* 0 is for overflows */
++      lstat_control.next_free_read_lock_index = 1;
++      lstat_control.dir_overflow = 0;
++      lstat_control.rwlock_overflow = 0;
++
++      lstat_control.started_cycles64 = 0;
++      lstat_control.ending_cycles64 = 0;
++      lstat_control.enabled_cycles64 = 0;
++      lstat_control.first_started_time = 0;
++      lstat_control.started_time = 0;
++      lstat_control.ending_time = 0;
++      lstat_control.intervals = 0;
++
++      /*
++       * paranoia -- in case someone does a "lockstat reset" before
++       * "lockstat on"
++       */
++      if (lstat_control.hashtab) {
++              bzero(lstat_control.hashtab,
++                      LSTAT_HASH_TABLE_SIZE * sizeof (short));
++              bzero(lstat_control.dir, LSTAT_MAX_STAT_INDEX *
++                              sizeof (lstat_directory_entry_t));
++
++              for (cpu = 0; cpu < num_online_cpus(); cpu++) {
++                      bzero(lstat_control.counts[cpu],
++                              sizeof (lstat_cpu_counts_t));
++                      bzero(lstat_control.read_lock_counts[cpu],
++                              sizeof (lstat_read_lock_cpu_counts_t));
++              }
++      }
++#ifdef NOTDEF
++      _raw_spin_unlock(&lstat_control.directory_lock);
++      local_irq_restore(flags);
++#endif
++      return 1;
++}
++
++static void
++release_control_space(void)
++{
++      /*
++       * Called when either (1) allocation of kmem
++       * or (2) when user writes LSTAT_RELEASE to /pro/lockmeter.
++       * Assume that all pointers have been initialized to zero,
++       * i.e., nonzero pointers are valid addresses.
++       */
++      int cpu;
++
++      if (lstat_control.hashtab) {
++              kfree(lstat_control.hashtab);
++              lstat_control.hashtab = NULL;
++      }
++
++      if (lstat_control.dir) {
++              vfree(lstat_control.dir);
++              lstat_control.dir = NULL;
++      }
++
++      for (cpu = 0; cpu < NR_CPUS; cpu++) {
++              if (lstat_control.counts[cpu]) {
++                      vfree(lstat_control.counts[cpu]);
++                      lstat_control.counts[cpu] = NULL;
++              }
++              if (lstat_control.read_lock_counts[cpu]) {
++                      kfree(lstat_control.read_lock_counts[cpu]);
++                      lstat_control.read_lock_counts[cpu] = NULL;
++              }
++      }
++}
++
++int
++get_lockmeter_info_size(void)
++{
++      return sizeof (lstat_user_request_t)
++              + num_online_cpus() * sizeof (lstat_cpu_counts_t)
++              + num_online_cpus() * sizeof (lstat_read_lock_cpu_counts_t)
++              + (LSTAT_MAX_STAT_INDEX * sizeof (lstat_directory_entry_t));
++}
++
++ssize_t
++get_lockmeter_info(char *buffer, size_t max_len, loff_t * last_index)
++{
++      lstat_user_request_t req;
++      struct timeval tv;
++      ssize_t next_ret_bcount;
++      ssize_t actual_ret_bcount = 0;
++      int cpu;
++
++      *last_index = 0;        /* a one-shot read */
++
++      req.lstat_version = LSTAT_VERSION;
++      req.state = lstat_control.state;
++      req.maxcpus = num_online_cpus();
++      req.cycleval = CPU_CYCLE_FREQUENCY;
++#ifdef notyet
++      req.kernel_magic_addr = (void *) &_etext;
++      req.kernel_end_addr = (void *) &_etext;
++#endif
++      req.uts = system_utsname;
++      req.intervals = lstat_control.intervals;
++
++      req.first_started_time = lstat_control.first_started_time;
++      req.started_time = lstat_control.started_time;
++      req.started_cycles64 = lstat_control.started_cycles64;
++
++      req.next_free_dir_index = lstat_control.next_free_dir_index;
++      req.next_free_read_lock_index = lstat_control.next_free_read_lock_index;
++      req.dir_overflow = lstat_control.dir_overflow;
++      req.rwlock_overflow = lstat_control.rwlock_overflow;
++
++      if (lstat_control.state == LSTAT_OFF) {
++              if (req.intervals == 0) {
++                      /* mesasurement is off and no valid data present */
++                      next_ret_bcount = sizeof (lstat_user_request_t);
++                      req.enabled_cycles64 = 0;
++
++                      if ((actual_ret_bcount + next_ret_bcount) > max_len)
++                              return actual_ret_bcount;
++
++                      copy_to_user(buffer, (void *) &req, next_ret_bcount);
++                      actual_ret_bcount += next_ret_bcount;
++                      return actual_ret_bcount;
++              } else {
++                      /*
++                       * measurement is off but valid data present
++                       * fetch time info from lstat_control
++                       */
++                      req.ending_time = lstat_control.ending_time;
++                      req.ending_cycles64 = lstat_control.ending_cycles64;
++                      req.enabled_cycles64 = lstat_control.enabled_cycles64;
++              }
++      } else {
++              /*
++               * this must be a read while data active--use current time,
++               * etc
++               */
++              do_gettimeofday(&tv);
++              req.ending_time = tv.tv_sec;
++              req.ending_cycles64 = get_cycles64();
++              req.enabled_cycles64 = req.ending_cycles64 -
++                      req.started_cycles64 + lstat_control.enabled_cycles64;
++      }
++
++      next_ret_bcount = sizeof (lstat_user_request_t);
++      if ((actual_ret_bcount + next_ret_bcount) > max_len)
++              return actual_ret_bcount;
++
++      copy_to_user(buffer, (void *) &req, next_ret_bcount);
++      actual_ret_bcount += next_ret_bcount;
++
++      if (!lstat_control.counts[0])   /* not initialized? */
++              return actual_ret_bcount;
++
++      next_ret_bcount = sizeof (lstat_cpu_counts_t);
++      for (cpu = 0; cpu < num_online_cpus(); cpu++) {
++              if ((actual_ret_bcount + next_ret_bcount) > max_len)
++                      return actual_ret_bcount;       /* leave early */
++              copy_to_user(buffer + actual_ret_bcount,
++                              lstat_control.counts[cpu], next_ret_bcount);
++              actual_ret_bcount += next_ret_bcount;
++      }
++
++      next_ret_bcount = LSTAT_MAX_STAT_INDEX *
++                      sizeof (lstat_directory_entry_t);
++      if (((actual_ret_bcount + next_ret_bcount) > max_len)
++                      || !lstat_control.dir)
++              return actual_ret_bcount;       /* leave early */
++
++      copy_to_user(buffer + actual_ret_bcount, lstat_control.dir,
++                      next_ret_bcount);
++      actual_ret_bcount += next_ret_bcount;
++
++      next_ret_bcount = sizeof (lstat_read_lock_cpu_counts_t);
++      for (cpu = 0; cpu < num_online_cpus(); cpu++) {
++              if (actual_ret_bcount + next_ret_bcount > max_len)
++                      return actual_ret_bcount;
++              copy_to_user(buffer + actual_ret_bcount,
++                              lstat_control.read_lock_counts[cpu],
++                              next_ret_bcount);
++              actual_ret_bcount += next_ret_bcount;
++      }
++
++      return actual_ret_bcount;
++}
++
++/*
++ *  Writing to the /proc lockmeter node enables or disables metering.
++ *  based upon the first byte of the "written" data.
++ *  The following values are defined:
++ *  LSTAT_ON: 1st call: allocates storage, intializes and turns on measurement
++ *            subsequent calls just turn on measurement
++ *  LSTAT_OFF: turns off measurement
++ *  LSTAT_RESET: resets statistics
++ *  LSTAT_RELEASE: releases statistics storage
++ *
++ *  This allows one to accumulate statistics over several lockstat runs:
++ *
++ *  lockstat on
++ *  lockstat off
++ *  ...repeat above as desired...
++ *  lockstat get
++ *  ...now start a new set of measurements...
++ *  lockstat reset
++ *  lockstat on
++ *  ...
++ *
++ */
++ssize_t
++put_lockmeter_info(const char *buffer, size_t len)
++{
++      int error = 0;
++      int dirsize, countsize, read_lock_countsize, hashsize;
++      int cpu;
++      char put_char;
++      int i, read_lock_blocks;
++      unsigned long flags;
++      rwlock_t *lock_ptr;
++      struct timeval tv;
++
++      if (len <= 0)
++              return -EINVAL;
++
++      _raw_spin_lock(&lstat_control.control_lock);
++
++      get_user(put_char, buffer);
++      switch (put_char) {
++
++      case LSTAT_OFF:
++              if (lstat_control.state != LSTAT_OFF) {
++                      /*
++                       * To avoid seeing read lock hold times in an
++                       * inconsisent state, we have to follow this protocol
++                       * to turn off statistics
++                       */
++                      local_irq_save(flags);
++                      /*
++                       * getting this lock will stop any read lock block
++                       * allocations
++                       */
++                      _raw_spin_lock(&lstat_control.directory_lock);
++                      /*
++                       * keep any more read lock blocks from being
++                       * allocated
++                       */
++                      lstat_control.state = LSTAT_OFF;
++                      /* record how may read lock blocks there are */
++                      read_lock_blocks =
++                              lstat_control.next_free_read_lock_index;
++                      _raw_spin_unlock(&lstat_control.directory_lock);
++                      /* now go through the list of read locks */
++                      cpu = THIS_CPU_NUMBER;
++                      for (i = 1; i < read_lock_blocks; i++) {
++                              lock_ptr =
++                                  (*lstat_control.read_lock_counts[cpu])[i].
++                                  lock_ptr;
++                              /* is this saved lock address still valid? */
++                              if (GET_RWINDEX(lock_ptr) == i) {
++                                      /*
++                                       * lock address appears to still be
++                                       * valid because we only hold one lock
++                                       * at a time, this can't cause a
++                                       * deadlock unless this is a lock held
++                                       * as part of the current system call
++                                       * path. At the moment there
++                                       * are no READ mode locks held to get
++                                       * here from user space, so we solve
++                                       * this by skipping locks held in
++                                       * write mode.
++                                       */
++                                      if (RWLOCK_IS_WRITE_LOCKED(lock_ptr)) {
++                                              PUT_RWINDEX(lock_ptr, 0);
++                                              continue;
++                                      }
++                                      /*
++                                       * now we know there are no read
++                                       * holders of this lock! stop
++                                       * statistics collection for this
++                                       * lock
++                                       */
++                                      _raw_write_lock(lock_ptr);
++                                      PUT_RWINDEX(lock_ptr, 0);
++                                      _raw_write_unlock(lock_ptr);
++                              }
++                              /*
++                               * it may still be possible for the hold time
++                               * sum to be negative e.g. if a lock is
++                               * reallocated while "busy" we will have to fix
++                               * this up in the data reduction program.
++                               */
++                      }
++                      local_irq_restore(flags);
++                      lstat_control.intervals++;
++                      lstat_control.ending_cycles64 = get_cycles64();
++                      lstat_control.enabled_cycles64 +=
++                              lstat_control.ending_cycles64 -
++                              lstat_control.started_cycles64;
++                      do_gettimeofday(&tv);
++                      lstat_control.ending_time = tv.tv_sec;
++                      /*
++                       * don't deallocate the structures -- we may do a
++                       * lockstat on to add to the data that is already
++                       * there. Use LSTAT_RELEASE to release storage
++                       */
++              } else {
++                      error = -EBUSY; /* already OFF */
++              }
++              break;
++
++      case LSTAT_ON:
++              if (lstat_control.state == LSTAT_OFF) {
++#ifdef DEBUG_LOCKMETER
++                      printk("put_lockmeter_info(cpu=%d): LSTAT_ON\n",
++                              THIS_CPU_NUMBER);
++#endif
++                      lstat_control.next_free_dir_index = 1;  /* 0 is for overflows */
++
++                      dirsize = LSTAT_MAX_STAT_INDEX *
++                                      sizeof (lstat_directory_entry_t);
++                      hashsize =
++                              (1 + LSTAT_HASH_TABLE_SIZE) * sizeof (ushort);
++                      countsize = sizeof (lstat_cpu_counts_t);
++                      read_lock_countsize =
++                              sizeof (lstat_read_lock_cpu_counts_t);
++#ifdef DEBUG_LOCKMETER
++                      printk(" dirsize:%d", dirsize);
++                      printk(" hashsize:%d", hashsize);
++                      printk(" countsize:%d", countsize);
++                      printk(" read_lock_countsize:%d\n",
++                              read_lock_countsize);
++#endif
++#ifdef DEBUG_LOCKMETER
++                      {
++                              int secs;
++                              unsigned long cycles;
++                              uint64_t cycles64;
++
++                              do_gettimeofday(&tv);
++                              secs = tv.tv_sec;
++                              do {
++                                      do_gettimeofday(&tv);
++                              } while (secs == tv.tv_sec);
++                              cycles = get_cycles();
++                              cycles64 = get_cycles64();
++                              secs = tv.tv_sec;
++                              do {
++                                      do_gettimeofday(&tv);
++                              } while (secs == tv.tv_sec);
++                              cycles = get_cycles() - cycles;
++                              cycles64 = get_cycles64() - cycles;
++                              printk("lockmeter: cycleFrequency:%d "
++                                      "cycles:%d cycles64:%d\n",
++                                      CPU_CYCLE_FREQUENCY, cycles, cycles64);
++                      }
++#endif
++
++                      /*
++                       * if this is the first call, allocate storage and
++                       * initialize
++                       */
++                      if (!lstat_control.hashtab) {
++
++                              spin_lock_init(&lstat_control.directory_lock);
++
++                              /* guarantee all pointers at zero */
++                              init_control_space();
++
++                              lstat_control.hashtab =
++                                  kmalloc(hashsize, GFP_KERNEL);
++                              if (!lstat_control.hashtab) {
++                                      error = -ENOSPC;
++#ifdef DEBUG_LOCKMETER
++                                      printk("!!error kmalloc of hashtab\n");
++#endif
++                              }
++                              lstat_control.dir = vmalloc(dirsize);
++                              if (!lstat_control.dir) {
++                                      error = -ENOSPC;
++#ifdef DEBUG_LOCKMETER
++                                      printk("!!error kmalloc of dir\n");
++#endif
++                              }
++
++                              for (cpu = 0; cpu < num_online_cpus(); cpu++) {
++                                      lstat_control.counts[cpu] =
++                                              vmalloc(countsize);
++                                      if (!lstat_control.counts[cpu]) {
++                                              error = -ENOSPC;
++#ifdef DEBUG_LOCKMETER
++                                              printk("!!error vmalloc of "
++                                                      "counts[%d]\n", cpu);
++#endif
++                                      }
++                                      lstat_control.read_lock_counts[cpu] =
++                                              (lstat_read_lock_cpu_counts_t *)
++                                              kmalloc(read_lock_countsize,
++                                                      GFP_KERNEL);
++                                      if (!lstat_control.
++                                                      read_lock_counts[cpu]) {
++                                              error = -ENOSPC;
++#ifdef DEBUG_LOCKMETER
++                                              printk("!!error kmalloc of "
++                                                "read_lock_counts[%d]\n",
++                                                      cpu);
++#endif
++                                      }
++                              }
++                      }
++
++                      if (error) {
++                              /*
++                               * One or more kmalloc failures -- free
++                               * everything
++                               */
++                              release_control_space();
++                      } else {
++
++                              if (!reset_lstat_data()) {
++                                      error = -EINVAL;
++                                      break;
++                              };
++
++                              /*
++                               * record starting and ending times and the
++                               * like
++                               */
++                              if (lstat_control.intervals == 0) {
++                                      do_gettimeofday(&tv);
++                                      lstat_control.first_started_time =
++                                              tv.tv_sec;
++                              }
++                              lstat_control.started_cycles64 = get_cycles64();
++                              do_gettimeofday(&tv);
++                              lstat_control.started_time = tv.tv_sec;
++
++                              lstat_control.state = LSTAT_ON;
++                      }
++              } else {
++                      error = -EBUSY; /* already ON */
++              }
++              break;
++
++      case LSTAT_RESET:
++              if (lstat_control.state == LSTAT_OFF) {
++                      if (!reset_lstat_data())
++                              error = -EINVAL;
++              } else {
++                      error = -EBUSY; /* still on; can't reset */
++              }
++              break;
++
++      case LSTAT_RELEASE:
++              if (lstat_control.state == LSTAT_OFF) {
++                      release_control_space();
++                      lstat_control.intervals = 0;
++                      lstat_control.enabled_cycles64 = 0;
++              } else {
++                      error = -EBUSY;
++              }
++              break;
++
++      default:
++              error = -EINVAL;
++      }                       /* switch */
++
++      _raw_spin_unlock(&lstat_control.control_lock);
++      return error ? error : len;
++}
++
++#ifdef USER_MODE_TESTING
++/* following used for user mode testing */
++void
++lockmeter_init()
++{
++      int dirsize, hashsize, countsize, read_lock_countsize, cpu;
++
++      printf("lstat_control is at %x size=%d\n", &lstat_control,
++              sizeof (lstat_control));
++      printf("sizeof(spinlock_t)=%d\n", sizeof (spinlock_t));
++      lstat_control.state = LSTAT_ON;
++
++      lstat_control.directory_lock = SPIN_LOCK_UNLOCKED;
++      lstat_control.next_free_dir_index = 1;  /* 0 is for overflows */
++      lstat_control.next_free_read_lock_index = 1;
++
++      dirsize = LSTAT_MAX_STAT_INDEX * sizeof (lstat_directory_entry_t);
++      hashsize = (1 + LSTAT_HASH_TABLE_SIZE) * sizeof (ushort);
++      countsize = sizeof (lstat_cpu_counts_t);
++      read_lock_countsize = sizeof (lstat_read_lock_cpu_counts_t);
++
++      lstat_control.hashtab = (ushort *) malloc(hashsize);
++
++      if (lstat_control.hashtab == 0) {
++              printf("malloc failure for at line %d in lockmeter.c\n",
++                      __LINE__);
++              exit(0);
++      }
++
++      lstat_control.dir = (lstat_directory_entry_t *) malloc(dirsize);
++
++      if (lstat_control.dir == 0) {
++              printf("malloc failure for at line %d in lockmeter.c\n", cpu,
++                      __LINE__);
++              exit(0);
++      }
++
++      for (cpu = 0; cpu < num_online_cpus(); cpu++) {
++              int j, k;
++              j = (int) (lstat_control.counts[cpu] =
++                         (lstat_cpu_counts_t *) malloc(countsize));
++              k = (int) (lstat_control.read_lock_counts[cpu] =
++                         (lstat_read_lock_cpu_counts_t *)
++                         malloc(read_lock_countsize));
++              if (j * k == 0) {
++                      printf("malloc failure for cpu=%d at line %d in "
++                              "lockmeter.c\n", cpu, __LINE__);
++                      exit(0);
++              }
++      }
++
++      memset(lstat_control.hashtab, 0, hashsize);
++      memset(lstat_control.dir, 0, dirsize);
++
++      for (cpu = 0; cpu < num_online_cpus(); cpu++) {
++              memset(lstat_control.counts[cpu], 0, countsize);
++              memset(lstat_control.read_lock_counts[cpu], 0,
++                      read_lock_countsize);
++      }
++}
++
++asm(" \
++.align        4 \
++.globl        __write_lock_failed \
++__write_lock_failed: \
++      " LOCK "addl    $" RW_LOCK_BIAS_STR ",(%eax) \
++1:    cmpl    $" RW_LOCK_BIAS_STR ",(%eax) \
++      jne     1b \
++\
++      " LOCK "subl    $" RW_LOCK_BIAS_STR ",(%eax) \
++      jnz     __write_lock_failed \
++      ret \
++\
++\
++.align        4 \
++.globl        __read_lock_failed \
++__read_lock_failed: \
++      lock ; incl     (%eax) \
++1:    cmpl    $1,(%eax) \
++      js      1b \
++\
++      lock ; decl     (%eax) \
++      js      __read_lock_failed \
++      ret \
++");
++#endif
+--- linux-2.6.0-test6/kernel/Makefile  2003-09-27 18:57:47.000000000 -0700
++++ 25/kernel/Makefile 2003-10-05 00:36:40.000000000 -0700
+@@ -11,6 +11,7 @@ obj-y     = sched.o fork.o exec_domain.o
+ obj-$(CONFIG_FUTEX) += futex.o
+ obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
+ obj-$(CONFIG_SMP) += cpu.o
++obj-$(CONFIG_LOCKMETER) += lockmeter.o
+ obj-$(CONFIG_UID16) += uid16.o
+ obj-$(CONFIG_MODULES) += ksyms.o module.o
+ obj-$(CONFIG_KALLSYMS) += kallsyms.o
+--- linux-2.6.0-test6/kernel/module.c  2003-09-08 13:58:59.000000000 -0700
++++ 25/kernel/module.c 2003-10-05 00:33:25.000000000 -0700
+@@ -844,6 +844,7 @@ int set_obsolete(const char *val, struct
+ {
+       unsigned int min, max;
+       unsigned int size, maxsize;
++      int dummy;
+       char *endp;
+       const char *p;
+       struct obsolete_modparm *obsparm = kp->arg;
+@@ -866,19 +867,19 @@ int set_obsolete(const char *val, struct
+       switch (*endp) {
+       case 'b':
+               return param_array(kp->name, val, min, max, obsparm->addr,
+-                                 1, param_set_byte);
++                                 1, param_set_byte, &dummy);
+       case 'h':
+               return param_array(kp->name, val, min, max, obsparm->addr,
+-                                 sizeof(short), param_set_short);
++                                 sizeof(short), param_set_short, &dummy);
+       case 'i':
+               return param_array(kp->name, val, min, max, obsparm->addr,
+-                                 sizeof(int), param_set_int);
++                                 sizeof(int), param_set_int, &dummy);
+       case 'l':
+               return param_array(kp->name, val, min, max, obsparm->addr,
+-                                 sizeof(long), param_set_long);
++                                 sizeof(long), param_set_long, &dummy);
+       case 's':
+               return param_array(kp->name, val, min, max, obsparm->addr,
+-                                 sizeof(char *), param_set_charp);
++                                 sizeof(char *), param_set_charp, &dummy);
+       case 'c':
+               /* Undocumented: 1-5c50 means 1-5 strings of up to 49 chars,
+@@ -895,7 +896,7 @@ int set_obsolete(const char *val, struct
+               if (size >= maxsize) 
+                       goto oversize;
+               return param_array(kp->name, val, min, max, obsparm->addr,
+-                                 maxsize, obsparm_copy_string);
++                                 maxsize, obsparm_copy_string, &dummy);
+       }
+       printk(KERN_ERR "Unknown obsolete parameter type %s\n", obsparm->type);
+       return -EINVAL;
+--- linux-2.6.0-test6/kernel/params.c  2003-08-22 19:23:42.000000000 -0700
++++ 25/kernel/params.c 2003-10-05 00:33:25.000000000 -0700
+@@ -242,10 +242,10 @@ int param_array(const char *name,
+               const char *val,
+               unsigned int min, unsigned int max,
+               void *elem, int elemsize,
+-              int (*set)(const char *, struct kernel_param *kp))
++              int (*set)(const char *, struct kernel_param *kp),
++              int *num)
+ {
+       int ret;
+-      unsigned int count = 0;
+       struct kernel_param kp;
+       char save;
+@@ -259,11 +259,12 @@ int param_array(const char *name,
+               return -EINVAL;
+       }
++      *num = 0;
+       /* We expect a comma-separated list of values. */
+       do {
+               int len;
+-              if (count > max) {
++              if (*num == max) {
+                       printk(KERN_ERR "%s: can only take %i arguments\n",
+                              name, max);
+                       return -EINVAL;
+@@ -279,10 +280,10 @@ int param_array(const char *name,
+                       return ret;
+               kp.arg += elemsize;
+               val += len+1;
+-              count++;
++              (*num)++;
+       } while (save == ',');
+-      if (count < min) {
++      if (*num < min) {
+               printk(KERN_ERR "%s: needs at least %i arguments\n",
+                      name, min);
+               return -EINVAL;
+@@ -290,29 +291,32 @@ int param_array(const char *name,
+       return 0;
+ }
+-/* First two elements are the max and min array length (which don't change) */
+-int param_set_intarray(const char *val, struct kernel_param *kp)
++int param_array_set(const char *val, struct kernel_param *kp)
+ {
+-      int *array;
++      struct kparam_array *arr = kp->arg;
+-      /* Grab min and max as first two elements */
+-      array = kp->arg;
+-      return param_array(kp->name, val, array[0], array[1], &array[2],
+-                         sizeof(int), param_set_int);
++      return param_array(kp->name, val, 1, arr->max, arr->elem,
++                         arr->elemsize, arr->set, arr->num);
+ }
+-int param_get_intarray(char *buffer, struct kernel_param *kp)
++int param_array_get(char *buffer, struct kernel_param *kp)
+ {
+-      int max;
+-      int *array;
+-      unsigned int i;
+-
+-      array = kp->arg;
+-      max = array[1];
+-
+-      for (i = 2; i < max + 2; i++)
+-              sprintf(buffer, "%s%i", i > 2 ? "," : "", array[i]);
+-      return strlen(buffer);
++      int i, off, ret;
++      struct kparam_array *arr = kp->arg;
++      struct kernel_param p;
++
++      p = *kp;
++      for (i = off = 0; i < *arr->num; i++) {
++              if (i)
++                      buffer[off++] = ',';
++              p.arg = arr->elem + arr->elemsize * i;
++              ret = arr->get(buffer + off, &p);
++              if (ret < 0)
++                      return ret;
++              off += ret;
++      }
++      buffer[off] = '\0';
++      return off;
+ }
+ int param_set_copystring(const char *val, struct kernel_param *kp)
+@@ -346,6 +350,6 @@ EXPORT_SYMBOL(param_set_bool);
+ EXPORT_SYMBOL(param_get_bool);
+ EXPORT_SYMBOL(param_set_invbool);
+ EXPORT_SYMBOL(param_get_invbool);
+-EXPORT_SYMBOL(param_set_intarray);
+-EXPORT_SYMBOL(param_get_intarray);
++EXPORT_SYMBOL(param_array_set);
++EXPORT_SYMBOL(param_array_get);
+ EXPORT_SYMBOL(param_set_copystring);
+--- linux-2.6.0-test6/kernel/pid.c     2003-09-27 18:57:47.000000000 -0700
++++ 25/kernel/pid.c    2003-10-05 00:36:15.000000000 -0700
+@@ -250,14 +250,14 @@ void switch_exec_pids(task_t *leader, ta
+       attach_pid(thread, PIDTYPE_PID, thread->pid);
+       attach_pid(thread, PIDTYPE_TGID, thread->tgid);
+-      attach_pid(thread, PIDTYPE_PGID, leader->__pgrp);
+-      attach_pid(thread, PIDTYPE_SID, thread->session);
++      attach_pid(thread, PIDTYPE_PGID, thread->signal->pgrp);
++      attach_pid(thread, PIDTYPE_SID, thread->signal->session);
+       list_add_tail(&thread->tasks, &init_task.tasks);
+       attach_pid(leader, PIDTYPE_PID, leader->pid);
+       attach_pid(leader, PIDTYPE_TGID, leader->tgid);
+-      attach_pid(leader, PIDTYPE_PGID, leader->__pgrp);
+-      attach_pid(leader, PIDTYPE_SID, leader->session);
++      attach_pid(leader, PIDTYPE_PGID, leader->signal->pgrp);
++      attach_pid(leader, PIDTYPE_SID, leader->signal->session);
+ }
+ /*
+@@ -265,6 +265,9 @@ void switch_exec_pids(task_t *leader, ta
+  * machine.  From a minimum of 16 slots up to 4096 slots at one gigabyte or
+  * more.
+  */
++#ifdef CONFIG_KGDB
++int kgdb_pid_init_done; /* so we don't call prior to... */
++#endif
+ void __init pidhash_init(void)
+ {
+       int i, j, pidhash_size;
+@@ -286,6 +289,9 @@ void __init pidhash_init(void)
+               for (j = 0; j < pidhash_size; j++)
+                       INIT_LIST_HEAD(&pid_hash[i][j]);
+       }
++#ifdef CONFIG_KGDB
++      kgdb_pid_init_done++;
++#endif
+ }
+ void __init pidmap_init(void)
+--- linux-2.6.0-test6/kernel/printk.c  2003-07-02 14:53:18.000000000 -0700
++++ 25/kernel/printk.c 2003-10-05 00:36:41.000000000 -0700
+@@ -29,11 +29,11 @@
+ #include <linux/delay.h>
+ #include <linux/smp.h>
+ #include <linux/security.h>
++#include <linux/bootmem.h>
+ #include <asm/uaccess.h>
+-#define LOG_BUF_LEN   (1 << CONFIG_LOG_BUF_SHIFT)
+-#define LOG_BUF_MASK  (LOG_BUF_LEN-1)
++#define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT)
+ /* printk's without a loglevel use this.. */
+ #define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */
+@@ -68,17 +68,21 @@ struct console *console_drivers;
+  */
+ static spinlock_t logbuf_lock = SPIN_LOCK_UNLOCKED;
+-static char log_buf[LOG_BUF_LEN];
++static char __log_buf[__LOG_BUF_LEN];
++static char *log_buf = __log_buf;
++static int log_buf_len = __LOG_BUF_LEN;
++
++#define LOG_BUF_MASK  (log_buf_len-1)
+ #define LOG_BUF(idx) (log_buf[(idx) & LOG_BUF_MASK])
+ /*
+- * The indices into log_buf are not constrained to LOG_BUF_LEN - they
++ * The indices into log_buf are not constrained to log_buf_len - they
+  * must be masked before subscripting
+  */
+-static unsigned long log_start;                       /* Index into log_buf: next char to be read by syslog() */
+-static unsigned long con_start;                       /* Index into log_buf: next char to be sent to consoles */
+-static unsigned long log_end;                 /* Index into log_buf: most-recently-written-char + 1 */
+-static unsigned long logged_chars;            /* Number of chars produced since last read+clear operation */
++static unsigned long log_start;       /* Index into log_buf: next char to be read by syslog() */
++static unsigned long con_start;       /* Index into log_buf: next char to be sent to consoles */
++static unsigned long log_end; /* Index into log_buf: most-recently-written-char + 1 */
++static unsigned long logged_chars; /* Number of chars produced since last read+clear operation */
+ struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES];
+ static int preferred_console = -1;
+@@ -141,6 +145,45 @@ static int __init console_setup(char *st
+ __setup("console=", console_setup);
++static int __init log_buf_len_setup(char *str)
++{
++      unsigned long size = memparse(str, &str);
++
++      if (size > log_buf_len) {
++              unsigned long start, dest_idx, offset;
++              char * new_log_buf;
++
++              new_log_buf = alloc_bootmem(size);
++              if (!new_log_buf) {
++                      printk("log_buf_len: allocation failed\n");
++                      goto out;
++              }
++
++              spin_lock_irq(&logbuf_lock);
++              log_buf_len = size;
++              log_buf = new_log_buf;
++
++              offset = start = min(con_start, log_start);
++              dest_idx = 0;
++              while (start != log_end) {
++                      log_buf[dest_idx] = __log_buf[start & (__LOG_BUF_LEN - 1)];
++                      start++;
++                      dest_idx++;
++              }
++              log_start -= offset;
++              con_start -= offset;
++              log_end -= offset;
++              spin_unlock_irq(&logbuf_lock);
++
++              printk("log_buf_len: %d\n", log_buf_len);
++      }
++out:
++
++      return 1;
++}
++
++__setup("log_buf_len=", log_buf_len_setup);
++
+ /*
+  * Commands to do_syslog:
+  *
+@@ -213,8 +256,8 @@ int do_syslog(int type, char __user * bu
+               if (error)
+                       goto out;
+               count = len;
+-              if (count > LOG_BUF_LEN)
+-                      count = LOG_BUF_LEN;
++              if (count > log_buf_len)
++                      count = log_buf_len;
+               spin_lock_irq(&logbuf_lock);
+               if (count > logged_chars)
+                       count = logged_chars;
+@@ -229,7 +272,7 @@ int do_syslog(int type, char __user * bu
+                */
+               for(i = 0; i < count && !error; i++) {
+                       j = limit-1-i;
+-                      if (j+LOG_BUF_LEN < log_end)
++                      if (j + log_buf_len < log_end)
+                               break;
+                       c = LOG_BUF(j);
+                       spin_unlock_irq(&logbuf_lock);
+@@ -302,12 +345,15 @@ static void __call_console_drivers(unsig
+ /*
+  * Write out chars from start to end - 1 inclusive
+  */
+-static void _call_console_drivers(unsigned long start, unsigned long end, int msg_log_level)
++static void _call_console_drivers(unsigned long start,
++                              unsigned long end, int msg_log_level)
+ {
+-      if (msg_log_level < console_loglevel && console_drivers && start != end) {
++      if (msg_log_level < console_loglevel &&
++                      console_drivers && start != end) {
+               if ((start & LOG_BUF_MASK) > (end & LOG_BUF_MASK)) {
+                       /* wrapped write */
+-                      __call_console_drivers(start & LOG_BUF_MASK, LOG_BUF_LEN);
++                      __call_console_drivers(start & LOG_BUF_MASK,
++                                              log_buf_len);
+                       __call_console_drivers(0, end & LOG_BUF_MASK);
+               } else {
+                       __call_console_drivers(start, end);
+@@ -370,11 +416,11 @@ static void emit_log_char(char c)
+ {
+       LOG_BUF(log_end) = c;
+       log_end++;
+-      if (log_end - log_start > LOG_BUF_LEN)
+-              log_start = log_end - LOG_BUF_LEN;
+-      if (log_end - con_start > LOG_BUF_LEN)
+-              con_start = log_end - LOG_BUF_LEN;
+-      if (logged_chars < LOG_BUF_LEN)
++      if (log_end - log_start > log_buf_len)
++              log_start = log_end - log_buf_len;
++      if (log_end - con_start > log_buf_len)
++              con_start = log_end - log_buf_len;
++      if (logged_chars < log_buf_len)
+               logged_chars++;
+ }
+@@ -399,9 +445,13 @@ asmlinkage int printk(const char *fmt, .
+       char *p;
+       static char printk_buf[1024];
+       static int log_level_unknown = 1;
++      static int printk_cpu = -1;
+-      if (oops_in_progress) {
+-              /* If a crash is occurring, make sure we can't deadlock */
++      if (oops_in_progress && printk_cpu == smp_processor_id()) {
++              /*
++               * If a crash is occurring during printk() on this CPU, make
++               * sure we can't deadlock
++               */
+               spin_lock_init(&logbuf_lock);
+               /* And make sure that we print immediately */
+               init_MUTEX(&console_sem);
+@@ -409,6 +459,7 @@ asmlinkage int printk(const char *fmt, .
+       /* This stops the holder of console_sem just where we want him */
+       spin_lock_irqsave(&logbuf_lock, flags);
++      printk_cpu = smp_processor_id();
+       /* Emit the output into the temporary buffer */
+       va_start(args, fmt);
+--- linux-2.6.0-test6/kernel/ptrace.c  2003-08-22 19:23:42.000000000 -0700
++++ 25/kernel/ptrace.c 2003-10-05 00:33:25.000000000 -0700
+@@ -179,19 +179,14 @@ int access_process_vm(struct task_struct
+               flush_cache_page(vma, addr);
+-              /*
+-               * FIXME!  We used to have flush_page_to_ram() in here, but
+-               * that was wrong.  davem says we need a new per-arch primitive
+-               * to handle this correctly.
+-               */
+-
+               maddr = kmap(page);
+               if (write) {
+-                      memcpy(maddr + offset, buf, bytes);
+-                      flush_icache_user_range(vma, page, addr, bytes);
++                      copy_to_user_page(vma, page, addr,
++                                        maddr + offset, buf, bytes);
+                       set_page_dirty_lock(page);
+               } else {
+-                      memcpy(buf, maddr + offset, bytes);
++                      copy_from_user_page(vma, page, addr,
++                                          buf, maddr + offset, bytes);
+               }
+               kunmap(page);
+               page_cache_release(page);
+--- linux-2.6.0-test6/kernel/rcupdate.c        2003-08-22 19:23:42.000000000 -0700
++++ 25/kernel/rcupdate.c       2003-10-05 00:33:25.000000000 -0700
+@@ -15,7 +15,7 @@
+  * 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, 2001
++ * Copyright (C) IBM Corporation, 2001
+  *
+  * Author: Dipankar Sarma <dipankar@in.ibm.com>
+  * 
+--- linux-2.6.0-test6/kernel/sched.c   2003-09-27 18:57:47.000000000 -0700
++++ 25/kernel/sched.c  2003-10-05 00:36:39.000000000 -0700
+@@ -18,6 +18,7 @@
+  */
+ #include <linux/mm.h>
++#include <linux/module.h>
+ #include <linux/nmi.h>
+ #include <linux/init.h>
+ #include <asm/uaccess.h>
+@@ -642,6 +643,8 @@ int wake_up_process(task_t * p)
+       return try_to_wake_up(p, TASK_STOPPED | TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE, 0, 0);
+ }
++EXPORT_SYMBOL(wake_up_process);
++
+ int wake_up_process_kick(task_t * p)
+ {
+       return try_to_wake_up(p, TASK_STOPPED | TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE, 0, 1);
+@@ -1585,6 +1588,8 @@ switch_tasks:
+               goto need_resched;
+ }
++EXPORT_SYMBOL(schedule);
++
+ #ifdef CONFIG_PREEMPT
+ /*
+  * this is is the entry point to schedule() from in-kernel preemption
+@@ -1612,6 +1617,8 @@ need_resched:
+       if (unlikely(test_thread_flag(TIF_NEED_RESCHED)))
+               goto need_resched;
+ }
++
++EXPORT_SYMBOL(preempt_schedule);
+ #endif /* CONFIG_PREEMPT */
+ int default_wake_function(wait_queue_t *curr, unsigned mode, int sync)
+@@ -1620,6 +1627,8 @@ int default_wake_function(wait_queue_t *
+       return try_to_wake_up(p, mode, sync, 0);
+ }
++EXPORT_SYMBOL(default_wake_function);
++
+ /*
+  * The core wakeup function.  Non-exclusive wakeups (nr_exclusive == 0) just
+  * wake everything up.  If it's an exclusive wakeup (nr_exclusive == small +ve
+@@ -1660,6 +1669,8 @@ void __wake_up(wait_queue_head_t *q, uns
+       spin_unlock_irqrestore(&q->lock, flags);
+ }
++EXPORT_SYMBOL(__wake_up);
++
+ /*
+  * Same as __wake_up but called with the spinlock in wait_queue_head_t held.
+  */
+@@ -1696,6 +1707,8 @@ void __wake_up_sync(wait_queue_head_t *q
+       spin_unlock_irqrestore(&q->lock, flags);
+ }
++EXPORT_SYMBOL(__wake_up_sync);
++
+ void complete(struct completion *x)
+ {
+       unsigned long flags;
+@@ -1706,6 +1719,8 @@ void complete(struct completion *x)
+       spin_unlock_irqrestore(&x->wait.lock, flags);
+ }
++EXPORT_SYMBOL(complete);
++
+ void complete_all(struct completion *x)
+ {
+       unsigned long flags;
+@@ -1737,6 +1752,8 @@ void wait_for_completion(struct completi
+       spin_unlock_irq(&x->wait.lock);
+ }
++EXPORT_SYMBOL(wait_for_completion);
++
+ #define       SLEEP_ON_VAR                            \
+       unsigned long flags;                    \
+       wait_queue_t wait;                      \
+@@ -1763,6 +1780,8 @@ void interruptible_sleep_on(wait_queue_h
+       SLEEP_ON_TAIL
+ }
++EXPORT_SYMBOL(interruptible_sleep_on);
++
+ long interruptible_sleep_on_timeout(wait_queue_head_t *q, long timeout)
+ {
+       SLEEP_ON_VAR
+@@ -1776,6 +1795,8 @@ long interruptible_sleep_on_timeout(wait
+       return timeout;
+ }
++EXPORT_SYMBOL(interruptible_sleep_on_timeout);
++
+ void sleep_on(wait_queue_head_t *q)
+ {
+       SLEEP_ON_VAR
+@@ -1787,6 +1808,8 @@ void sleep_on(wait_queue_head_t *q)
+       SLEEP_ON_TAIL
+ }
++EXPORT_SYMBOL(sleep_on);
++
+ long sleep_on_timeout(wait_queue_head_t *q, long timeout)
+ {
+       SLEEP_ON_VAR
+@@ -1800,6 +1823,8 @@ long sleep_on_timeout(wait_queue_head_t 
+       return timeout;
+ }
++EXPORT_SYMBOL(sleep_on_timeout);
++
+ void scheduling_functions_end_here(void) { }
+ void set_user_nice(task_t *p, long nice)
+@@ -1849,6 +1874,15 @@ out_unlock:
+       task_rq_unlock(rq, &flags);
+ }
++EXPORT_SYMBOL(set_user_nice);
++
++#if defined( CONFIG_KGDB)
++struct task_struct * kgdb_get_idle(int this_cpu)
++{
++        return cpu_rq(this_cpu)->idle;
++}
++#endif
++
+ #ifndef __alpha__
+ /*
+@@ -1915,6 +1949,8 @@ int task_nice(task_t *p)
+       return TASK_NICE(p);
+ }
++EXPORT_SYMBOL(task_nice);
++
+ /**
+  * task_curr - is this task currently executing on a CPU?
+  * @p: the task in question.
+@@ -1933,6 +1969,8 @@ int idle_cpu(int cpu)
+       return cpu_curr(cpu) == cpu_rq(cpu)->idle;
+ }
++EXPORT_SYMBOL(idle_cpu);
++
+ /**
+  * find_process_by_pid - find a process with a matching PID value.
+  * @pid: the pid in question.
+@@ -2260,6 +2298,8 @@ void __cond_resched(void)
+       schedule();
+ }
++EXPORT_SYMBOL(__cond_resched);
++
+ /**
+  * yield - yield the current processor to other threads.
+  *
+@@ -2272,6 +2312,8 @@ void yield(void)
+       sys_sched_yield();
+ }
++EXPORT_SYMBOL(yield);
++
+ /*
+  * This task is about to go to sleep on IO.  Increment rq->nr_iowait so
+  * that process accounting knows that this is a task in IO wait state.
+@@ -2288,6 +2330,8 @@ void io_schedule(void)
+       atomic_dec(&rq->nr_iowait);
+ }
++EXPORT_SYMBOL(io_schedule);
++
+ long io_schedule_timeout(long timeout)
+ {
+       struct runqueue *rq = this_rq();
+@@ -2402,17 +2446,16 @@ static inline struct task_struct *younge
+ static void show_task(task_t * p)
+ {
+-      unsigned long free = 0;
+       task_t *relative;
+-      int state;
+-      static const char * stat_nam[] = { "R", "S", "D", "T", "Z", "W" };
++      unsigned state;
++      static const char *stat_nam[] = { "R", "S", "D", "T", "Z", "W" };
+       printk("%-13.13s ", p->comm);
+       state = p->state ? __ffs(p->state) + 1 : 0;
+-      if (((unsigned) state) < sizeof(stat_nam)/sizeof(char *))
++      if (state < ARRAY_SIZE(stat_nam))
+               printk(stat_nam[state]);
+       else
+-              printk(" ");
++              printk("?");
+ #if (BITS_PER_LONG == 32)
+       if (p == current)
+               printk(" current  ");
+@@ -2424,13 +2467,7 @@ static void show_task(task_t * p)
+       else
+               printk(" %016lx ", thread_saved_pc(p));
+ #endif
+-      {
+-              unsigned long * n = (unsigned long *) (p->thread_info+1);
+-              while (!*n)
+-                      n++;
+-              free = (unsigned long) n - (unsigned long)(p+1);
+-      }
+-      printk("%5lu %5d %6d ", free, p->pid, p->parent->pid);
++      printk("%5d %6d ", p->pid, p->parent->pid);
+       if ((relative = eldest_child(p)))
+               printk("%5d ", relative->pid);
+       else
+@@ -2457,12 +2494,12 @@ void show_state(void)
+ #if (BITS_PER_LONG == 32)
+       printk("\n"
+-             "                         free                        sibling\n");
+-      printk("  task             PC    stack   pid father child younger older\n");
++             "                                               sibling\n");
++      printk("  task             PC      pid father child younger older\n");
+ #else
+       printk("\n"
+-             "                                 free                        sibling\n");
+-      printk("  task                 PC        stack   pid father child younger older\n");
++             "                                                       sibling\n");
++      printk("  task                 PC          pid father child younger older\n");
+ #endif
+       read_lock(&tasklist_lock);
+       do_each_thread(g, p) {
+@@ -2574,6 +2611,8 @@ int set_cpus_allowed(task_t *p, cpumask_
+       return 0;
+ }
++EXPORT_SYMBOL_GPL(set_cpus_allowed);
++
+ /* Move (not current) task off this cpu, onto dest cpu. */
+ static void move_task_away(struct task_struct *p, int dest_cpu)
+ {
+@@ -2819,6 +2858,7 @@ void __might_sleep(char *file, int line)
+       }
+ #endif
+ }
++EXPORT_SYMBOL(__might_sleep);
+ #endif
+@@ -2847,6 +2887,8 @@ void __preempt_spin_lock(spinlock_t *loc
+       } while (!_raw_spin_trylock(lock));
+ }
++EXPORT_SYMBOL(__preempt_spin_lock);
++
+ void __preempt_write_lock(rwlock_t *lock)
+ {
+       if (preempt_count() > 1) {
+@@ -2861,4 +2903,6 @@ void __preempt_write_lock(rwlock_t *lock
+               preempt_disable();
+       } while (!_raw_write_trylock(lock));
+ }
+-#endif
++
++EXPORT_SYMBOL(__preempt_write_lock);
++#endif /* defined(CONFIG_SMP) && defined(CONFIG_PREEMPT) */
+--- linux-2.6.0-test6/kernel/signal.c  2003-09-27 18:57:47.000000000 -0700
++++ 25/kernel/signal.c 2003-10-05 00:36:15.000000000 -0700
+@@ -593,7 +593,8 @@ static int check_kill_permission(int sig
+       error = -EPERM;
+       if ((!info || ((unsigned long)info != 1 &&
+                       (unsigned long)info != 2 && SI_FROMUSER(info)))
+-          && ((sig != SIGCONT) || (current->session != t->session))
++          && ((sig != SIGCONT) ||
++              (process_session(current) != process_session(t)))
+           && (current->euid ^ t->suid) && (current->euid ^ t->uid)
+           && (current->uid ^ t->suid) && (current->uid ^ t->uid)
+           && !capable(CAP_KILL))
+@@ -1102,7 +1103,7 @@ kill_sl_info(int sig, struct siginfo *in
+       retval = -ESRCH;
+       read_lock(&tasklist_lock);
+       for_each_task_pid(sid, PIDTYPE_SID, p, l, pid) {
+-              if (!p->leader)
++              if (!process_session_leader(p))
+                       continue;
+               err = group_send_sig_info(sig, info, p);
+               if (retval)
+--- linux-2.6.0-test6/kernel/sys.c     2003-09-27 18:57:47.000000000 -0700
++++ 25/kernel/sys.c    2003-10-05 00:36:15.000000000 -0700
+@@ -951,7 +951,7 @@ asmlinkage long sys_setpgid(pid_t pid, p
+       if (p->parent == current || p->real_parent == current) {
+               err = -EPERM;
+-              if (p->session != current->session)
++              if (process_session(p) != process_session(current))
+                       goto out;
+               err = -EACCES;
+               if (p->did_exec)
+@@ -963,7 +963,7 @@ asmlinkage long sys_setpgid(pid_t pid, p
+       }
+       err = -EPERM;
+-      if (p->leader)
++      if (process_session_leader(p))
+               goto out;
+       if (pgid != pid) {
+@@ -972,7 +972,7 @@ asmlinkage long sys_setpgid(pid_t pid, p
+               struct list_head *l;
+               for_each_task_pid(pgid, PIDTYPE_PGID, p, l, pid)
+-                      if (p->session == current->session)
++                      if (process_session(p) == process_session(current))
+                               goto ok_pgid;
+               goto out;
+       }
+@@ -984,7 +984,7 @@ ok_pgid:
+       if (process_group(p) != pgid) {
+               detach_pid(p, PIDTYPE_PGID);
+-              p->group_leader->__pgrp = pgid;
++              p->signal->pgrp = pgid;
+               attach_pid(p, PIDTYPE_PGID, pgid);
+       }
+@@ -1026,7 +1026,7 @@ asmlinkage long sys_getpgrp(void)
+ asmlinkage long sys_getsid(pid_t pid)
+ {
+       if (!pid) {
+-              return current->session;
++              return process_session(current);
+       } else {
+               int retval;
+               struct task_struct *p;
+@@ -1038,7 +1038,7 @@ asmlinkage long sys_getsid(pid_t pid)
+               if(p) {
+                       retval = security_task_getsid(p);
+                       if (!retval)
+-                              retval = p->session;
++                              retval = process_session(p);
+               }
+               read_unlock(&tasklist_lock);
+               return retval;
+@@ -1059,10 +1059,10 @@ asmlinkage long sys_setsid(void)
+       if (pid)
+               goto out;
+-      current->leader = 1;
++      current->signal->leader = 1;
+       __set_special_pids(current->pid, current->pid);
+-      current->tty = NULL;
+-      current->tty_old_pgrp = 0;
++      current->signal->tty = NULL;
++      current->signal->tty_old_pgrp = 0;
+       err = process_group(current);
+ out:
+       write_unlock_irq(&tasklist_lock);
+--- linux-2.6.0-test6/kernel/sysctl.c  2003-09-27 18:57:47.000000000 -0700
++++ 25/kernel/sysctl.c 2003-10-05 00:33:25.000000000 -0700
+@@ -19,6 +19,7 @@
+  */
+ #include <linux/config.h>
++#include <linux/module.h>
+ #include <linux/mm.h>
+ #include <linux/swap.h>
+ #include <linux/slab.h>
+@@ -136,17 +137,14 @@ extern ctl_table random_table[];
+ static ssize_t proc_readsys(struct file *, char __user *, size_t, loff_t *);
+ static ssize_t proc_writesys(struct file *, const char __user *, size_t, loff_t *);
+-static int proc_sys_permission(struct inode *, int, struct nameidata *);
++static int proc_opensys(struct inode *, struct file *);
+ struct file_operations proc_sys_file_operations = {
++      .open           = proc_opensys,
+       .read           = proc_readsys,
+       .write          = proc_writesys,
+ };
+-static struct inode_operations proc_sys_inode_operations = {
+-      .permission     = proc_sys_permission,
+-};
+-
+ extern struct proc_dir_entry *proc_sys_root;
+ static void register_proc_table(ctl_table *, struct proc_dir_entry *);
+@@ -1140,10 +1138,8 @@ static void register_proc_table(ctl_tabl
+                       if (!de)
+                               continue;
+                       de->data = (void *) table;
+-                      if (table->proc_handler) {
++                      if (table->proc_handler)
+                               de->proc_fops = &proc_sys_file_operations;
+-                              de->proc_iops = &proc_sys_inode_operations;
+-                      }
+               }
+               table->de = de;
+               if (de->mode & S_IFDIR)
+@@ -1212,6 +1208,20 @@ static ssize_t do_rw_proc(int write, str
+       return res;
+ }
++static int proc_opensys(struct inode *inode, struct file *file)
++{
++      if (file->f_mode & FMODE_WRITE) {
++              /*
++               * sysctl entries that are not writable,
++               * are _NOT_ writable, capabilities or not.
++               */
++              if (!(inode->i_mode & S_IWUSR))
++                      return -EPERM;
++      }
++
++      return 0;
++}
++
+ static ssize_t proc_readsys(struct file * file, char __user * buf,
+                           size_t count, loff_t *ppos)
+ {
+@@ -1224,11 +1234,6 @@ static ssize_t proc_writesys(struct file
+       return do_rw_proc(1, file, (char __user *) buf, count, ppos);
+ }
+-static int proc_sys_permission(struct inode *inode, int op, struct nameidata *nd)
+-{
+-      return test_perm(inode->i_mode, op);
+-}
+-
+ /**
+  * proc_dostring - read a string sysctl
+  * @table: the sysctl table
+@@ -1994,3 +1999,19 @@ void unregister_sysctl_table(struct ctl_
+ }
+ #endif /* CONFIG_SYSCTL */
++
++/*
++ * No sense putting this after each symbol definition, twice,
++ * exception granted :-)
++ */
++EXPORT_SYMBOL(proc_dointvec);
++EXPORT_SYMBOL(proc_dointvec_jiffies);
++EXPORT_SYMBOL(proc_dointvec_minmax);
++EXPORT_SYMBOL(proc_dostring);
++EXPORT_SYMBOL(proc_doulongvec_minmax);
++EXPORT_SYMBOL(proc_doulongvec_ms_jiffies_minmax);
++EXPORT_SYMBOL(register_sysctl_table);
++EXPORT_SYMBOL(sysctl_intvec);
++EXPORT_SYMBOL(sysctl_jiffies);
++EXPORT_SYMBOL(sysctl_string);
++EXPORT_SYMBOL(unregister_sysctl_table);
+--- linux-2.6.0-test6/lib/kobject.c    2003-09-08 13:58:59.000000000 -0700
++++ 25/lib/kobject.c   2003-10-05 00:34:36.000000000 -0700
+@@ -236,8 +236,6 @@ static void unlink(struct kobject * kobj
+               list_del_init(&kobj->entry);
+               up_write(&kobj->kset->subsys->rwsem);
+       }
+-      if (kobj->parent) 
+-              kobject_put(kobj->parent);
+       kobject_put(kobj);
+ }
+@@ -448,6 +446,8 @@ void kobject_cleanup(struct kobject * ko
+       if (kobj->k_name != kobj->name)
+               kfree(kobj->k_name);
+       kobj->k_name = NULL;
++      if (kobj->parent)
++              kobject_put(kobj->parent);
+       if (t && t->release)
+               t->release(kobj);
+       if (s)
+--- linux-2.6.0-test6/lib/Makefile     2003-09-27 18:57:47.000000000 -0700
++++ 25/lib/Makefile    2003-10-05 00:33:25.000000000 -0700
+@@ -5,7 +5,7 @@
+ lib-y := errno.o ctype.o string.o vsprintf.o cmdline.o \
+        bust_spinlocks.o rbtree.o radix-tree.o dump_stack.o \
+-       kobject.o idr.o div64.o
++       kobject.o idr.o div64.o parser.o
+ lib-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
+ lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/lib/parser.c    2003-10-05 00:33:25.000000000 -0700
+@@ -0,0 +1,138 @@
++/*
++ * lib/parser.c - simple parser for mount, etc. options.
++ *
++ * This source code is licensed under the GNU General Public License,
++ * Version 2.  See the file COPYING for more details.
++ */
++
++#include <linux/ctype.h>
++#include <linux/module.h>
++#include <linux/parser.h>
++#include <linux/slab.h>
++#include <linux/string.h>
++
++static int match_one(char *s, char *p, substring_t args[])
++{
++      char *meta;
++      int argc = 0;
++
++      if (!p)
++              return 1;
++
++      while(1) {
++              int len = -1;
++              meta = strchr(p, '%');
++              if (!meta)
++                      return strcmp(p, s) == 0;
++
++              if (strncmp(p, s, meta-p))
++                      return 0;
++
++              s += meta - p;
++              p = meta + 1;
++
++              if (isdigit(*p))
++                      len = simple_strtoul(p, &p, 10);
++              else if (*p == '%') {
++                      if (*s++ != '%')
++                              return 0;
++                      continue;
++              }
++
++              if (argc >= MAX_OPT_ARGS)
++                      return 0;
++
++              args[argc].from = s;
++              switch (*p++) {
++              case 's':
++                      if (len == -1 || len > strlen(s))
++                              len = strlen(s);
++                      args[argc].to = s + len;
++                      break;
++              case 'd':
++                      simple_strtol(s, &args[argc].to, 0);
++                      goto num;
++              case 'u':
++                      simple_strtoul(s, &args[argc].to, 0);
++                      goto num;
++              case 'o':
++                      simple_strtoul(s, &args[argc].to, 8);
++                      goto num;
++              case 'x':
++                      simple_strtoul(s, &args[argc].to, 16);
++              num:
++                      if (args[argc].to == args[argc].from)
++                              return 0;
++                      break;
++              default:
++                      return 0;
++              }
++              s = args[argc].to;
++              argc++;
++      }
++}
++
++int match_token(char *s, match_table_t table, substring_t args[])
++{
++      struct match_token *p;
++
++      for (p = table; !match_one(s, p->pattern, args) ; p++)
++              ;
++
++      return p->token;
++}
++
++static int match_number(substring_t *s, int *result, int base)
++{
++      char *endp;
++      char *buf;
++      int ret;
++
++      buf = kmalloc(s->to - s->from + 1, GFP_KERNEL);
++      if (!buf)
++              return -ENOMEM;
++      memcpy(buf, s->from, s->to - s->from);
++      buf[s->to - s->from] = '\0';
++      *result = simple_strtol(buf, &endp, base);
++      ret = 0;
++      if (endp == buf)
++              ret = -EINVAL;
++      kfree(buf);
++      return ret;
++}
++
++int match_int(substring_t *s, int *result)
++{
++      return match_number(s, result, 0);
++}
++
++int match_octal(substring_t *s, int *result)
++{
++      return match_number(s, result, 8);
++}
++
++int match_hex(substring_t *s, int *result)
++{
++      return match_number(s, result, 16);
++}
++
++void match_strcpy(char *to, substring_t *s)
++{
++      memcpy(to, s->from, s->to - s->from);
++      to[s->to - s->from] = '\0';
++}
++
++char *match_strdup(substring_t *s)
++{
++      char *p = kmalloc(s->to - s->from + 1, GFP_KERNEL);
++      if (p)
++              match_strcpy(p, s);
++      return p;
++}
++
++EXPORT_SYMBOL(match_token);
++EXPORT_SYMBOL(match_int);
++EXPORT_SYMBOL(match_octal);
++EXPORT_SYMBOL(match_hex);
++EXPORT_SYMBOL(match_strcpy);
++EXPORT_SYMBOL(match_strdup);
+--- linux-2.6.0-test6/MAINTAINERS      2003-09-27 18:57:43.000000000 -0700
++++ 25/MAINTAINERS     2003-10-05 00:34:22.000000000 -0700
+@@ -114,8 +114,8 @@ W: http://sourceforge.net/projects/gkern
+ S:    Maintained
+ 8250/16?50 (AND CLONE UARTS) SERIAL DRIVER
+-P:    Theodore Ts'o
+-M:    tytso@mit.edu
++P:    Russell King
++M:    rmk+serial@arm.linux.org.uk
+ L:    linux-serial@vger.kernel.org
+ W:    http://serial.sourceforge.net
+ S:    Maintained
+@@ -284,6 +284,16 @@ P:        Jonathan Layes
+ L:    linux-net@vger.kernel.org
+ S:    Maintained
++ASUS ACPI EXTRAS DRIVER
++P:    Karol Kozimor
++M:    sziwan@users.sourceforge.net
++P:    Julien Lerouge
++M:    julien.lerouge@free.fr
++L:    acpi4asus-user@lists.sourceforge.net
++W:    http://sourceforge.net/projects/acpi4asus
++W:    http://julien.lerouge.free.fr
++S:    Maintained
++
+ ATM
+ P:    Chas Williams
+ M:    chas@cmf.nrl.navy.mil
+@@ -509,7 +519,7 @@ S: Maintained
+ CRYPTO API
+ P:    James Morris
+-M:    jmorris@intercode.com.au
++M:    jmorris@redhat.com
+ P:    David S. Miller
+ M:    davem@redhat.com
+ W     http://samba.org/~jamesm/crypto/
+@@ -624,7 +634,7 @@ DIGIBOARD PC/XE AND PC/XI DRIVER
+ P:    Christoph Lameter
+ M:    christoph@lameter.com
+ W:    http://www.digi.com
+-L:    digilnux@dgii.com
++L:    digilnux@digi.com
+ S:    Orphaned
+ DIRECTORY NOTIFICATION
+@@ -669,6 +679,12 @@ M:        romieu@cogenit.fr
+ M:    romieu@ensta.fr
+ S:    Maintained
++DVB SUBSYSTEM AND DRIVERS
++P:    LinuxTV.org Project
++L:    linux-dvb@linuxtv.org
++W:    http://linuxtv.org/developer/dvb.xml
++S:    Supported
++
+ EATA-DMA SCSI DRIVER
+ P:    Michael Neuffer
+ L:    linux-eata@i-connect.net, linux-scsi@vger.kernel.org
+@@ -706,6 +722,11 @@ L:        emu10k1-devel@lists.sourceforge.net
+ W:    http://sourceforge.net/projects/emu10k1/
+ S:    Maintained
++EPSON 1355 FRAMEBUFFER DRIVER
++P:    Christopher Hoover
++M:    ch@murgatroid.com, ch@hpl.hp.com
++S:    Maintained
++
+ ETHEREXPRESS-16 NETWORK DRIVER
+ P:    Philip Blundell
+ M:    Philip.Blundell@pobox.com
+@@ -1139,6 +1160,12 @@ W:      http://sf.net/projects/kernel-janitor
+ W:    http://developer.osdl.org/rddunlap/kj-patches/
+ S:    Maintained
++KGDB FOR I386 PLATFORM
++P:    George Anzinger
++M:    george@mvista.com
++L:    linux-net@vger.kernel.org
++S:    Supported
++
+ KERNEL NFSD
+ P:    Neil Brown
+ M:    neilb@cse.unsw.edu.au
+@@ -1386,7 +1413,7 @@ M:       kuznet@ms2.inr.ac.ru
+ P:    Pekka Savola (ipv6)
+ M:    pekkas@netcore.fi
+ P:    James Morris
+-M:    jmorris@intercode.com.au
++M:    jmorris@redhat.com
+ P:    Hideaki YOSHIFUJI
+ M:    yoshfuji@linux-ipv6.org
+ L:    netdev@oss.sgi.com
+@@ -1658,6 +1685,12 @@ L:      linux-390@vm.marist.edu
+ W:    http://oss.software.ibm.com/developerworks/opensource/linux390
+ S:    Supported
++SAA7146 VIDEO4LINUX-2 DRIVER
++P:    Michael Hunold
++M:    michael@mihu.de
++W:    http://www.mihu.de/linux/saa7146
++S:    Maintained
++
+ SA1100 SUPPORT
+ P:    Nicolas Pitre
+ M:    nico@cam.org
+--- linux-2.6.0-test6/Makefile 2003-09-27 18:57:43.000000000 -0700
++++ 25/Makefile        2003-10-05 00:37:37.000000000 -0700
+@@ -1,7 +1,7 @@
+ VERSION = 2
+ PATCHLEVEL = 6
+ SUBLEVEL = 0
+-EXTRAVERSION = -test6
++EXTRAVERSION = -test6-mm4
+ # *DOCUMENTATION*
+ # To see a list of typical targets execute "make help"
+@@ -37,7 +37,7 @@ ifdef V
+   endif
+ endif
+ ifndef KBUILD_VERBOSE
+-  KBUILD_VERBOSE = 0 
++  KBUILD_VERBOSE = 0
+ endif
+ # Call sparse as part of compilation of C files
+@@ -79,16 +79,24 @@ ifdef O
+   endif
+ endif
++# That's our default target when none is given on the command line
++.PHONY: all
++all:
++  
+ ifneq ($(KBUILD_OUTPUT),)
+ # Invoke a second make in the output directory, passing relevant variables
+-      KBUILD_OUTPUT := $(shell cd $(KBUILD_OUTPUT); /bin/pwd)
++# check that the output directory actually exists
++saved-output := $(KBUILD_OUTPUT)
++KBUILD_OUTPUT := $(shell cd $(KBUILD_OUTPUT) && /bin/pwd)
++$(if $(wildcard $(KBUILD_OUTPUT)),, \
++     $(error output directory "$(saved-output)" does not exist))
+-.PHONY: $(MAKECMDGOALS) all
++.PHONY: $(MAKECMDGOALS)
+-$(MAKECMDGOALS) all:
++$(filter-out all,$(MAKECMDGOALS)) all:
+       $(if $(KBUILD_VERBOSE:1=),@)$(MAKE) -C $(KBUILD_OUTPUT)         \
+       KBUILD_SRC=$(CURDIR)    KBUILD_VERBOSE=$(KBUILD_VERBOSE)        \
+-      KBUILD_CHECK=$(KBUILD_CHECK) -f $(CURDIR)/Makefile $(MAKECMDGOALS)
++      KBUILD_CHECK=$(KBUILD_CHECK) -f $(CURDIR)/Makefile $@
+ # Leave processing to above invocation of make
+ skip-makefile := 1
+@@ -156,13 +164,6 @@ HOSTCXX   = g++
+ HOSTCFLAGS    = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
+ HOSTCXXFLAGS  = -O2
+-
+-#     That's our default target when none is given on the command line
+-#     Note that 'modules' will be added as a prerequisite as well, 
+-#     in the CONFIG_MODULES part below
+-
+-all:  vmlinux
+-
+ #     Decide whether to build built-in, modular, or both.
+ #     Normally, just do built-in.
+@@ -366,6 +367,12 @@ else
+ # Build targets only - this includes vmlinux, arch specific targets, clean
+ # targets and others. In general all targets except *config targets.
++# That's our default target when none is given on the command line
++# Note that 'modules' will be added as a prerequisite as well, 
++# in the CONFIG_MODULES part below
++
++all:  vmlinux
++
+ # Objects we will link into vmlinux / subdirs we need to visit
+ init-y                := init/
+ drivers-y     := drivers/ sound/
+@@ -753,7 +760,7 @@ MRPROPER_FILES += \
+       .menuconfig.log \
+       include/asm \
+       .hdepend include/linux/modversions.h \
+-      tags TAGS cscope.out kernel.spec \
++      tags TAGS cscope* kernel.spec \
+       .tmp*
+ # Directories removed with 'make mrproper'
+@@ -877,7 +884,7 @@ help:
+       @echo  '  mrproper        - remove all generated files + config + various backup files'
+       @echo  ''
+       @echo  'Configuration targets:'
+-      @$(MAKE) -f scripts/kconfig/Makefile help
++      @$(MAKE) -f $(srctree)/scripts/kconfig/Makefile help
+       @echo  ''
+       @echo  'Other generic targets:'
+       @echo  '  all             - Build all targets marked with [*]'
+@@ -890,7 +897,7 @@ help:
+       @echo  '  tags/TAGS       - Generate tags file for editors'
+       @echo  ''
+       @echo  'Documentation targets:'
+-      @$(MAKE) -f Documentation/DocBook/Makefile dochelp
++      @$(MAKE) -f $(srctree)/Documentation/DocBook/Makefile dochelp
+       @echo  ''
+       @echo  'Architecture specific targets ($(ARCH)):'
+       @$(if $(archhelp),$(archhelp),\
+--- linux-2.6.0-test6/mm/bootmem.c     2003-08-08 22:55:14.000000000 -0700
++++ 25/mm/bootmem.c    2003-10-05 00:33:25.000000000 -0700
+@@ -146,7 +146,7 @@ static void __init free_bootmem_core(boo
+  * We 'merge' subsequent allocations to save space. We might 'lose'
+  * some fraction of a page if allocations cannot be satisfied due to
+  * size constraints on boxes where there is physical RAM space
+- * fragmentation - in these cases * (mostly large memory boxes) this
++ * fragmentation - in these cases (mostly large memory boxes) this
+  * is not a problem.
+  *
+  * On low memory boxes we get it right in 100% of the cases.
+--- linux-2.6.0-test6/mm/fadvise.c     2003-09-27 18:57:47.000000000 -0700
++++ 25/mm/fadvise.c    2003-10-05 00:34:08.000000000 -0700
+@@ -23,7 +23,6 @@
+ asmlinkage long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice)
+ {
+       struct file *file = fget(fd);
+-      struct inode *inode;
+       struct address_space *mapping;
+       struct backing_dev_info *bdi;
+       pgoff_t start_index;
+@@ -33,8 +32,7 @@ asmlinkage long sys_fadvise64_64(int fd,
+       if (!file)
+               return -EBADF;
+-      inode = file->f_dentry->d_inode;
+-      mapping = inode->i_mapping;
++      mapping = file->f_mapping;
+       if (!mapping) {
+               ret = -EINVAL;
+               goto out;
+--- linux-2.6.0-test6/mm/filemap.c     2003-09-27 18:57:47.000000000 -0700
++++ 25/mm/filemap.c    2003-10-05 00:37:07.000000000 -0700
+@@ -61,6 +61,9 @@
+  *        ->swap_device_lock  (exclusive_swap_page, others)
+  *          ->mapping->page_lock
+  *
++ *  ->i_sem
++ *    ->i_shared_sem          (truncate->invalidate_mmap_range)
++ *
+  *  ->mmap_sem
+  *    ->i_shared_sem          (various places)
+  *
+@@ -70,6 +73,9 @@
+  *  ->mmap_sem
+  *    ->i_sem                 (msync)
+  *
++ *  ->i_sem
++ *    ->i_alloc_sem             (various)
++ *
+  *  ->inode_lock
+  *    ->sb_lock                       (fs/fs-writeback.c)
+  *    ->mapping->page_lock    (__sync_single_inode)
+@@ -151,6 +157,8 @@ int filemap_fdatawrite(struct address_sp
+       return __filemap_fdatawrite(mapping, WB_SYNC_ALL);
+ }
++EXPORT_SYMBOL(filemap_fdatawrite);
++
+ /*
+  * This is a mostly non-blocking flush.  Not suitable for data-integrity
+  * purposes.
+@@ -216,6 +224,20 @@ restart:
+       return ret;
+ }
++EXPORT_SYMBOL(filemap_fdatawait);
++
++int filemap_write_and_wait(struct address_space *mapping)
++{
++      int retval = 0;
++
++      if (mapping->nrpages) {
++              retval = filemap_fdatawrite(mapping);
++              if (retval == 0)
++                      retval = filemap_fdatawait(mapping);
++      }
++      return retval;
++}
++
+ /*
+  * This adds a page to the page cache, starting out as locked, unreferenced,
+  * not uptodate and with no errors.
+@@ -253,6 +275,7 @@ int add_to_page_cache(struct page *page,
+       }
+       return error;
+ }
++
+ EXPORT_SYMBOL(add_to_page_cache);
+ int add_to_page_cache_lru(struct page *page, struct address_space *mapping,
+@@ -281,21 +304,42 @@ static wait_queue_head_t *page_waitqueue
+       return &zone->wait_table[hash_ptr(page, zone->wait_table_bits)];
+ }
+-void wait_on_page_bit(struct page *page, int bit_nr)
++/*
++ * wait for the specified page bit to be cleared
++ * this could be a synchronous wait or could just queue an async
++ * notification callback depending on the wait queue entry parameter
++ *
++ * A NULL wait queue parameter defaults to sync behaviour
++ */
++int wait_on_page_bit_wq(struct page *page, int bit_nr, wait_queue_t *wait)
+ {
+       wait_queue_head_t *waitqueue = page_waitqueue(page);
+-      DEFINE_WAIT(wait);
++      DEFINE_WAIT(local_wait);
++
++      if (!wait)
++              wait = &local_wait; /* default to a sync wait entry */
+       do {
+-              prepare_to_wait(waitqueue, &wait, TASK_UNINTERRUPTIBLE);
++              prepare_to_wait(waitqueue, wait, TASK_UNINTERRUPTIBLE);
+               if (test_bit(bit_nr, &page->flags)) {
+                       sync_page(page);
++                      if (!is_sync_wait(wait)) {
++                              /*
++                               * if we've queued an async wait queue
++                               * callback do not block; just tell the
++                               * caller to return and retry later when
++                               * the callback is notified
++                               */
++                              return -EIOCBRETRY;
++                      }
+                       io_schedule();
+               }
+       } while (test_bit(bit_nr, &page->flags));
+-      finish_wait(waitqueue, &wait);
++      finish_wait(waitqueue, wait);
++
++      return 0;
+ }
+-EXPORT_SYMBOL(wait_on_page_bit);
++EXPORT_SYMBOL(wait_on_page_bit_wq);
+ /**
+  * unlock_page() - unlock a locked page
+@@ -305,7 +349,9 @@ EXPORT_SYMBOL(wait_on_page_bit);
+  * Unlocks the page and wakes up sleepers in ___wait_on_page_locked().
+  * Also wakes sleepers in wait_on_page_writeback() because the wakeup
+  * mechananism between PageLocked pages and PageWriteback pages is shared.
+- * But that's OK - sleepers in wait_on_page_writeback() just go back to sleep.
++ * But that's OK - sleepers in wait_on_page_writeback() just go back to sleep,
++ * or in case the wakeup notifies async wait queue entries, as in the case
++ * of aio, retries would be triggered and may re-queue their callbacks.
+  *
+  * The first mb is necessary to safely close the critical section opened by the
+  * TestSetPageLocked(), the second mb is necessary to enforce ordering between
+@@ -323,6 +369,8 @@ void unlock_page(struct page *page)
+               wake_up_all(waitqueue);
+ }
++EXPORT_SYMBOL(unlock_page);
++
+ /*
+  * End writeback against a page.
+  */
+@@ -339,30 +387,57 @@ void end_page_writeback(struct page *pag
+       if (waitqueue_active(waitqueue))
+               wake_up_all(waitqueue);
+ }
++
+ EXPORT_SYMBOL(end_page_writeback);
+ /*
+- * Get a lock on the page, assuming we need to sleep to get it.
++ * Get a lock on the page, assuming we need to either sleep to get it
++ * or to queue an async notification callback to try again when its
++ * available.
++ *
++ * A NULL wait queue parameter defaults to sync behaviour. Otherwise
++ * it specifies the wait queue entry to be used for async notification
++ * or waiting.
+  *
+  * Ugly: running sync_page() in state TASK_UNINTERRUPTIBLE is scary.  If some
+  * random driver's requestfn sets TASK_RUNNING, we could busywait.  However
+  * chances are that on the second loop, the block layer's plug list is empty,
+  * so sync_page() will then return in state TASK_UNINTERRUPTIBLE.
+  */
+-void __lock_page(struct page *page)
++int __lock_page_wq(struct page *page, wait_queue_t *wait)
+ {
+       wait_queue_head_t *wqh = page_waitqueue(page);
+-      DEFINE_WAIT(wait);
++      DEFINE_WAIT(local_wait);
++
++      if (!wait)
++              wait = &local_wait;
+       while (TestSetPageLocked(page)) {
+-              prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE);
++              prepare_to_wait(wqh, wait, TASK_UNINTERRUPTIBLE);
+               if (PageLocked(page)) {
+                       sync_page(page);
++                      if (!is_sync_wait(wait)) {
++                              /*
++                               * if we've queued an async wait queue
++                               * callback do not block; just tell the
++                               * caller to return and retry later when
++                               * the callback is notified
++                               */
++                              return -EIOCBRETRY;
++                      }
+                       io_schedule();
+               }
+       }
+-      finish_wait(wqh, &wait);
++      finish_wait(wqh, wait);
++      return 0;
++}
++EXPORT_SYMBOL(__lock_page_wq);
++
++void __lock_page(struct page *page)
++{
++      __lock_page_wq(page, NULL);
+ }
++
+ EXPORT_SYMBOL(__lock_page);
+ /*
+@@ -385,6 +460,8 @@ struct page * find_get_page(struct addre
+       return page;
+ }
++EXPORT_SYMBOL(find_get_page);
++
+ /*
+  * Same as above, but trylock it instead of incrementing the count.
+  */
+@@ -400,6 +477,8 @@ struct page *find_trylock_page(struct ad
+       return page;
+ }
++EXPORT_SYMBOL(find_trylock_page);
++
+ /**
+  * find_lock_page - locate, pin and lock a pagecache page
+  *
+@@ -411,8 +490,8 @@ struct page *find_trylock_page(struct ad
+  *
+  * Returns zero if the page was not present. find_lock_page() may sleep.
+  */
+-struct page *find_lock_page(struct address_space *mapping,
+-                              unsigned long offset)
++struct page *find_lock_page_wq(struct address_space *mapping,
++                              unsigned long offset, wait_queue_t *wait)
+ {
+       struct page *page;
+@@ -423,7 +502,10 @@ repeat:
+               page_cache_get(page);
+               if (TestSetPageLocked(page)) {
+                       spin_unlock(&mapping->page_lock);
+-                      lock_page(page);
++                      if (-EIOCBRETRY == lock_page_wq(page, wait)) {
++                              page_cache_release(page);
++                              return ERR_PTR(-EIOCBRETRY);
++                      }
+                       spin_lock(&mapping->page_lock);
+                       /* Has the page been truncated while we slept? */
+@@ -438,6 +520,14 @@ repeat:
+       return page;
+ }
++EXPORT_SYMBOL(find_lock_page);
++
++struct page *find_lock_page(struct address_space *mapping,
++                              unsigned long offset)
++{
++      return find_lock_page_wq(mapping, offset, NULL);
++}
++
+ /**
+  * find_or_create_page - locate or add a pagecache page
+  *
+@@ -482,6 +572,8 @@ repeat:
+       return page;
+ }
++EXPORT_SYMBOL(find_or_create_page);
++
+ /**
+  * find_get_pages - gang pagecache lookup
+  * @mapping:  The address_space to search
+@@ -496,9 +588,12 @@ repeat:
+  * The search returns a group of mapping-contiguous pages with ascending
+  * indexes.  There may be holes in the indices due to not-present pages.
+  *
+- * find_get_pages() returns the number of pages which were found.
++ * find_get_pages() returns the number of pages which were found
++ * and also atomically sets the next offset to continue looking up
++ * mapping contiguous pages from (useful when doing a range of
++ * pagevec lookups in chunks of PAGEVEC_SIZE).
+  */
+-unsigned int find_get_pages(struct address_space *mapping, pgoff_t start,
++unsigned int find_get_pages(struct address_space *mapping, pgoff_t *next,
+                           unsigned int nr_pages, struct page **pages)
+ {
+       unsigned int i;
+@@ -506,9 +601,12 @@ unsigned int find_get_pages(struct addre
+       spin_lock(&mapping->page_lock);
+       ret = radix_tree_gang_lookup(&mapping->page_tree,
+-                              (void **)pages, start, nr_pages);
++                              (void **)pages, *next, nr_pages);
+       for (i = 0; i < ret; i++)
+               page_cache_get(pages[i]);
++      if (ret)
++              *next = pages[ret - 1]->index + 1;
++
+       spin_unlock(&mapping->page_lock);
+       return ret;
+ }
+@@ -543,6 +641,8 @@ grab_cache_page_nowait(struct address_sp
+       return page;
+ }
++EXPORT_SYMBOL(grab_cache_page_nowait);
++
+ /*
+  * This is a generic file read routine, and uses the
+  * inode->i_op->readpage() function for the actual low-level
+@@ -560,21 +660,47 @@ void do_generic_mapping_read(struct addr
+                            read_actor_t actor)
+ {
+       struct inode *inode = mapping->host;
+-      unsigned long index, offset;
++      unsigned long index, offset, first, last, end_index;
+       struct page *cached_page;
++      loff_t isize = i_size_read(inode);
+       int error;
+       cached_page = NULL;
+-      index = *ppos >> PAGE_CACHE_SHIFT;
++      first = *ppos >> PAGE_CACHE_SHIFT;
+       offset = *ppos & ~PAGE_CACHE_MASK;
++      last = (*ppos + desc->count) >> PAGE_CACHE_SHIFT;
++      end_index = isize >> PAGE_CACHE_SHIFT;
++      if (last > end_index)
++              last = end_index;
++
++      /* Don't repeat the readahead if we are executing aio retries */
++      if (in_aio()) {
++              if (is_retried_kiocb(io_wait_to_kiocb(current->io_wait)))
++                      goto done_readahead;
++      }
++
++      /*
++       * Let the readahead logic know upfront about all
++       * the pages we'll need to satisfy this request
++       */
++      for (index = first ; index < last; index++)
++              page_cache_readahead(mapping, ra, filp, index);
++
++      if (ra->next_size == -1UL) {
++              /* the readahead window was maximally shrunk */
++              /* explicitly readahead at least what is needed now */
++              for (index = first; index < last; index++)
++                      handle_ra_miss(mapping, ra, index);
++              do_page_cache_readahead(mapping, filp, first, last - first);
++      }
++
++done_readahead:
++      index = first;
+       for (;;) {
+               struct page *page;
+-              unsigned long end_index, nr, ret;
+-              loff_t isize = i_size_read(inode);
++              unsigned long nr, ret;
+-              end_index = isize >> PAGE_CACHE_SHIFT;
+-                      
+               if (index > end_index)
+                       break;
+               nr = PAGE_CACHE_SIZE;
+@@ -585,7 +711,6 @@ void do_generic_mapping_read(struct addr
+               }
+               cond_resched();
+-              page_cache_readahead(mapping, ra, filp, index);
+               nr = nr - offset;
+ find_page:
+@@ -635,7 +760,12 @@ page_not_up_to_date:
+                       goto page_ok;
+               /* Get exclusive access to the page ... */
+-              lock_page(page);
++
++              if (lock_page_wq(page, current->io_wait)) {
++                      pr_debug("queued lock page \n");
++                      error = -EIOCBRETRY;
++                      goto sync_error;
++              }
+               /* Did it get unhashed before we got the lock? */
+               if (!page->mapping) {
+@@ -657,13 +787,23 @@ readpage:
+               if (!error) {
+                       if (PageUptodate(page))
+                               goto page_ok;
+-                      wait_on_page_locked(page);
++                      if (wait_on_page_locked_wq(page, current->io_wait)) {
++                              pr_debug("queued wait_on_page \n");
++                              error = -EIOCBRETRY;
++                              goto sync_error;
++                      }
++
+                       if (PageUptodate(page))
+                               goto page_ok;
+                       error = -EIO;
+               }
+-              /* UHHUH! A synchronous read error occurred. Report it */
++sync_error:
++              /* We don't have uptodate data in the page yet */
++              /* Could be due to an error or because we need to
++               * retry when we get an async i/o notification.
++               * Report the reason.
++               */
+               desc->error = error;
+               page_cache_release(page);
+               break;
+@@ -699,6 +839,8 @@ no_cached_page:
+       update_atime(inode);
+ }
++EXPORT_SYMBOL(do_generic_mapping_read);
++
+ int file_read_actor(read_descriptor_t *desc, struct page *page,
+                       unsigned long offset, unsigned long size)
+ {
+@@ -775,7 +917,7 @@ __generic_file_aio_read(struct kiocb *io
+               struct address_space *mapping;
+               struct inode *inode;
+-              mapping = filp->f_dentry->d_inode->i_mapping;
++              mapping = filp->f_mapping;
+               inode = mapping->host;
+               retval = 0;
+               if (!count)
+@@ -815,20 +957,19 @@ __generic_file_aio_read(struct kiocb *io
+ out:
+       return retval;
+ }
++EXPORT_SYMBOL(__generic_file_aio_read);
+-ssize_t
+-generic_file_aio_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t pos)
++ssize_t generic_file_aio_read(struct kiocb *iocb, char __user *buf,
++                              size_t count, loff_t pos)
+ {
+       struct iovec local_iov = { .iov_base = buf, .iov_len = count };
+-      BUG_ON(iocb->ki_pos != pos);
+       return __generic_file_aio_read(iocb, &local_iov, 1, &iocb->ki_pos);
+ }
+ EXPORT_SYMBOL(generic_file_aio_read);
+-EXPORT_SYMBOL(__generic_file_aio_read);
+-ssize_t
+-generic_file_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
++ssize_t generic_file_read(struct file *filp, char __user *buf,
++                              size_t count, loff_t *ppos)
+ {
+       struct iovec local_iov = { .iov_base = buf, .iov_len = count };
+       struct kiocb kiocb;
+@@ -840,8 +981,10 @@ generic_file_read(struct file *filp, cha
+               ret = wait_on_sync_kiocb(&kiocb);
+       return ret;
+ }
++EXPORT_SYMBOL(generic_file_read);
+-int file_send_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size)
++int file_send_actor(read_descriptor_t * desc, struct page *page,
++                              unsigned long offset, unsigned long size)
+ {
+       ssize_t written;
+       unsigned long count = desc->count;
+@@ -880,6 +1023,8 @@ ssize_t generic_file_sendfile(struct fil
+       return desc.error;
+ }
++EXPORT_SYMBOL(generic_file_sendfile);
++
+ static ssize_t
+ do_readahead(struct address_space *mapping, struct file *filp,
+            unsigned long index, unsigned long nr)
+@@ -901,7 +1046,7 @@ asmlinkage ssize_t sys_readahead(int fd,
+       file = fget(fd);
+       if (file) {
+               if (file->f_mode & FMODE_READ) {
+-                      struct address_space *mapping = file->f_dentry->d_inode->i_mapping;
++                      struct address_space *mapping = file->f_mapping;
+                       unsigned long start = offset >> PAGE_CACHE_SHIFT;
+                       unsigned long end = (offset + count - 1) >> PAGE_CACHE_SHIFT;
+                       unsigned long len = end - start + 1;
+@@ -920,7 +1065,7 @@ asmlinkage ssize_t sys_readahead(int fd,
+ static int FASTCALL(page_cache_read(struct file * file, unsigned long offset));
+ static int page_cache_read(struct file * file, unsigned long offset)
+ {
+-      struct address_space *mapping = file->f_dentry->d_inode->i_mapping;
++      struct address_space *mapping = file->f_mapping;
+       struct page *page; 
+       int error;
+@@ -959,7 +1104,7 @@ struct page * filemap_nopage(struct vm_a
+ {
+       int error;
+       struct file *file = area->vm_file;
+-      struct address_space *mapping = file->f_dentry->d_inode->i_mapping;
++      struct address_space *mapping = file->f_mapping;
+       struct file_ra_state *ra = &file->f_ra;
+       struct inode *inode = mapping->host;
+       struct page *page;
+@@ -1126,10 +1271,12 @@ page_not_uptodate:
+       return NULL;
+ }
++EXPORT_SYMBOL(filemap_nopage);
++
+ static struct page * filemap_getpage(struct file *file, unsigned long pgoff,
+                                       int nonblock)
+ {
+-      struct address_space *mapping = file->f_dentry->d_inode->i_mapping;
++      struct address_space *mapping = file->f_mapping;
+       struct page *page;
+       int error;
+@@ -1241,7 +1388,7 @@ static int filemap_populate(struct vm_ar
+                       int nonblock)
+ {
+       struct file *file = vma->vm_file;
+-      struct address_space *mapping = file->f_dentry->d_inode->i_mapping;
++      struct address_space *mapping = file->f_mapping;
+       struct inode *inode = mapping->host;
+       unsigned long size;
+       struct mm_struct *mm = vma->vm_mm;
+@@ -1300,7 +1447,7 @@ static struct vm_operations_struct gener
+ int generic_file_mmap(struct file * file, struct vm_area_struct * vma)
+ {
+-      struct address_space *mapping = file->f_dentry->d_inode->i_mapping;
++      struct address_space *mapping = file->f_mapping;
+       struct inode *inode = mapping->host;
+       if (!mapping->a_ops->readpage)
+@@ -1330,6 +1477,9 @@ int generic_file_readonly_mmap(struct fi
+ }
+ #endif /* CONFIG_MMU */
++EXPORT_SYMBOL(generic_file_mmap);
++EXPORT_SYMBOL(generic_file_readonly_mmap);
++
+ static inline struct page *__read_cache_page(struct address_space *mapping,
+                               unsigned long index,
+                               int (*filler)(void *,struct page*),
+@@ -1406,6 +1556,8 @@ retry:
+       return page;
+ }
++EXPORT_SYMBOL(read_cache_page);
++
+ /*
+  * If the page was newly created, increment its refcount and add it to the
+  * caller's lru-buffering pagevec.  This function is specifically for
+@@ -1418,7 +1570,9 @@ __grab_cache_page(struct address_space *
+       int err;
+       struct page *page;
+ repeat:
+-      page = find_lock_page(mapping, index);
++      page = find_lock_page_wq(mapping, index, current->io_wait);
++      if (IS_ERR(page))
++              return page;
+       if (!page) {
+               if (!*cached_page) {
+                       *cached_page = page_cache_alloc(mapping);
+@@ -1456,6 +1610,8 @@ void remove_suid(struct dentry *dentry)
+       }
+ }
++EXPORT_SYMBOL(remove_suid);
++
+ /*
+  * Copy as much as we can into the page and return the number of bytes which
+  * were sucessfully copied.  If a fault is encountered then clear the page
+@@ -1561,9 +1717,9 @@ filemap_set_next_iovec(const struct iove
+  * Returns appropriate error code that caller should return or
+  * zero in case that write should be allowed.
+  */
+-inline int generic_write_checks(struct inode *inode,
+-              struct file *file, loff_t *pos, size_t *count, int isblk)
++inline int generic_write_checks(struct file *file, loff_t *pos, size_t *count, int isblk)
+ {
++      struct inode *inode = file->f_mapping->host;
+       unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
+         if (unlikely(*pos < 0))
+@@ -1625,7 +1781,7 @@ inline int generic_write_checks(struct i
+                       *count = inode->i_sb->s_maxbytes - *pos;
+       } else {
+               loff_t isize;
+-              if (bdev_read_only(inode->i_bdev))
++              if (bdev_read_only(I_BDEV(inode)))
+                       return -EPERM;
+               isize = i_size_read(inode);
+               if (*pos >= isize) {
+@@ -1638,10 +1794,12 @@ inline int generic_write_checks(struct i
+       }
+       return 0;
+ }
++
+ EXPORT_SYMBOL(generic_write_checks);
+ /*
+  * Write to a file through the page cache. 
++ * Called under i_sem for S_ISREG files.
+  *
+  * We put everything into the page cache prior to writing it. This is not a
+  * problem when writing full pages. With partial pages, however, we first have
+@@ -1650,11 +1808,11 @@ EXPORT_SYMBOL(generic_write_checks);
+  *                                                    okir@monad.swb.de
+  */
+ ssize_t
+-generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov,
++__generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov,
+                               unsigned long nr_segs, loff_t *ppos)
+ {
+       struct file *file = iocb->ki_filp;
+-      struct address_space * mapping = file->f_dentry->d_inode->i_mapping;
++      struct address_space * mapping = file->f_mapping;
+       struct address_space_operations *a_ops = mapping->a_ops;
+       size_t ocount;          /* original count */
+       size_t count;           /* after file limit checks */
+@@ -1701,11 +1859,10 @@ generic_file_aio_write_nolock(struct kio
+       current->backing_dev_info = mapping->backing_dev_info;
+       written = 0;
+-      err = generic_write_checks(inode, file, &pos, &count, isblk);
++      err = generic_write_checks(file, &pos, &count, isblk);
+       if (err)
+               goto out;
+-
+       if (count == 0)
+               goto out;
+@@ -1730,12 +1887,19 @@ generic_file_aio_write_nolock(struct kio
+               /*
+                * Sync the fs metadata but not the minor inode changes and
+                * of course not the data as we did direct DMA for the IO.
++               * i_sem is held, which protects generic_osync_inode() from
++               * livelocking.
+                */
+               if (written >= 0 && file->f_flags & O_SYNC)
+-                      status = generic_osync_inode(inode, OSYNC_METADATA);
++                      status = generic_osync_inode(inode, mapping, OSYNC_METADATA);
+               if (written >= 0 && !is_sync_kiocb(iocb))
+                       written = -EIOCBQUEUED;
+-              goto out_status;
++              if (written != -ENOTBLK)
++                      goto out_status;
++              /*
++               * direct-io write to a hole: fall through to buffered I/O
++               */
++              written = 0;
+       }
+       buf = iov->iov_base;
+@@ -1759,6 +1923,10 @@ generic_file_aio_write_nolock(struct kio
+               fault_in_pages_readable(buf, bytes);
+               page = __grab_cache_page(mapping,index,&cached_page,&lru_pvec);
++              if (IS_ERR(page)) {
++                      status = PTR_ERR(page);
++                      break;
++              }
+               if (!page) {
+                       status = -ENOMEM;
+                       break;
+@@ -1807,7 +1975,11 @@ generic_file_aio_write_nolock(struct kio
+               page_cache_release(page);
+               if (status < 0)
+                       break;
+-              balance_dirty_pages_ratelimited(mapping);
++              status = balance_dirty_pages_ratelimited(mapping);
++              if (status < 0) {
++                      pr_debug("async balance_dirty_pages\n");
++                      break;
++              }
+               cond_resched();
+       } while (count);
+       *ppos = pos;
+@@ -1818,12 +1990,22 @@ generic_file_aio_write_nolock(struct kio
+       /*
+        * For now, when the user asks for O_SYNC, we'll actually give O_DSYNC
+        */
+-      if (status >= 0) {
+-              if ((file->f_flags & O_SYNC) || IS_SYNC(inode))
+-                      status = generic_osync_inode(inode,
+-                                      OSYNC_METADATA|OSYNC_DATA);
+-      }
++      if (likely(status >= 0)) {
++              if (unlikely((file->f_flags & O_SYNC) || IS_SYNC(inode))) {
++                      if (!a_ops->writepage)
++                              status = generic_osync_inode(inode, mapping,
++                                              OSYNC_METADATA|OSYNC_DATA);
++              }
++      }
+       
++      /*
++       * If we get here for O_DIRECT writes then we must have fallen through
++       * to buffered writes (block instantiation inside i_size).  So we sync
++       * the file data here, to try to honour O_DIRECT expectations.
++       */
++      if (unlikely(file->f_flags & O_DIRECT) && written)
++              status = filemap_write_and_wait(mapping);
++
+ out_status:   
+       err = written ? written : status;
+ out:
+@@ -1832,6 +2014,57 @@ out:
+       return err;
+ }
++EXPORT_SYMBOL(generic_file_aio_write_nolock);
++
++ssize_t
++generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov,
++                              unsigned long nr_segs, loff_t *ppos)
++{
++      struct file *file = iocb->ki_filp;
++      struct address_space *mapping = file->f_mapping;
++      struct inode *inode = mapping->host;
++      ssize_t ret;
++      loff_t pos = *ppos;
++
++      if (!iov->iov_base && !is_sync_kiocb(iocb)) {
++              /* nothing to transfer, may just need to sync data */
++              ret = iov->iov_len; /* vector AIO not supported yet */
++              goto osync;
++      }
++
++      ret = __generic_file_aio_write_nolock(iocb, iov, nr_segs, ppos);
++
++      /*
++       * Avoid doing a sync in parts for aio - its more efficient to
++       * call in again after all the data has been copied
++       */
++      if (!is_sync_kiocb(iocb))
++              return ret;
++
++osync:
++      if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) {
++              ret = sync_page_range_nolock(inode, mapping, pos, ret);
++              if (ret >= 0)
++                      *ppos = pos + ret;
++      }
++      return ret;
++}
++
++
++ssize_t
++__generic_file_write_nolock(struct file *file, const struct iovec *iov,
++                              unsigned long nr_segs, loff_t *ppos)
++{
++      struct kiocb kiocb;
++      ssize_t ret;
++
++      init_sync_kiocb(&kiocb, file);
++      ret = __generic_file_aio_write_nolock(&kiocb, iov, nr_segs, ppos);
++      if (-EIOCBQUEUED == ret)
++              ret = wait_on_sync_kiocb(&kiocb);
++      return ret;
++}
++
+ ssize_t
+ generic_file_write_nolock(struct file *file, const struct iovec *iov,
+                               unsigned long nr_segs, loff_t *ppos)
+@@ -1846,39 +2079,69 @@ generic_file_write_nolock(struct file *f
+       return ret;
+ }
++EXPORT_SYMBOL(generic_file_write_nolock);
++
+ ssize_t generic_file_aio_write(struct kiocb *iocb, const char __user *buf,
+                              size_t count, loff_t pos)
+ {
+       struct file *file = iocb->ki_filp;
+-      struct inode *inode = file->f_dentry->d_inode->i_mapping->host;
+-      ssize_t err;
+-      struct iovec local_iov = { .iov_base = (void __user *)buf, .iov_len = count };
++      struct address_space *mapping = file->f_mapping;
++      struct inode *inode = mapping->host;
++      ssize_t ret;
++      struct iovec local_iov = { .iov_base = (void __user *)buf,
++                                      .iov_len = count };
+-      BUG_ON(iocb->ki_pos != pos);
++      if (!buf && !is_sync_kiocb(iocb)) {
++              /* nothing to transfer, may just need to sync data */
++              ret = count;
++              goto osync;
++      }
+       down(&inode->i_sem);
+-      err = generic_file_aio_write_nolock(iocb, &local_iov, 1, 
++      ret = __generic_file_aio_write_nolock(iocb, &local_iov, 1,
+                                               &iocb->ki_pos);
+       up(&inode->i_sem);
+-      return err;
++      /*
++       * Avoid doing a sync in parts for aio - its more efficient to
++       * call in again after all the data has been copied
++       */
++      if (!is_sync_kiocb(iocb))
++              return ret;
++
++osync:
++      if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) {
++              ret = sync_page_range(inode, mapping, pos, ret);
++              if (ret >= 0)
++                      iocb->ki_pos = pos + ret;
++      }
++      return ret;
+ }
+ EXPORT_SYMBOL(generic_file_aio_write);
+-EXPORT_SYMBOL(generic_file_aio_write_nolock);
+ ssize_t generic_file_write(struct file *file, const char __user *buf,
+                          size_t count, loff_t *ppos)
+ {
+-      struct inode    *inode = file->f_dentry->d_inode->i_mapping->host;
+-      ssize_t         err;
+-      struct iovec local_iov = { .iov_base = (void __user *)buf, .iov_len = count };
++      struct address_space *mapping = file->f_mapping;
++      struct inode *inode = mapping->host;
++      ssize_t ret;
++      struct iovec local_iov = { .iov_base = (void __user *)buf,
++                                      .iov_len = count };
+       down(&inode->i_sem);
+-      err = generic_file_write_nolock(file, &local_iov, 1, ppos);
++      ret = __generic_file_write_nolock(file, &local_iov, 1, ppos);
+       up(&inode->i_sem);
+-      return err;
++      if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) {
++              ssize_t err;
++
++              err = sync_page_range(inode, mapping, *ppos - ret, ret);
++              if (err < 0)
++                      ret = err;
++      }
++      return ret;
+ }
++EXPORT_SYMBOL(generic_file_write);
+ ssize_t generic_file_readv(struct file *filp, const struct iovec *iov,
+                       unsigned long nr_segs, loff_t *ppos)
+@@ -1893,37 +2156,50 @@ ssize_t generic_file_readv(struct file *
+       return ret;
+ }
++EXPORT_SYMBOL(generic_file_readv);
++
+ ssize_t generic_file_writev(struct file *file, const struct iovec *iov,
+-                      unsigned long nr_segs, loff_t * ppos) 
++                      unsigned long nr_segs, loff_t *ppos)
+ {
+-      struct inode *inode = file->f_dentry->d_inode;
++      struct address_space *mapping = file->f_mapping;
++      struct inode *inode = mapping->host;
+       ssize_t ret;
+       down(&inode->i_sem);
+-      ret = generic_file_write_nolock(file, iov, nr_segs, ppos);
++      ret = __generic_file_write_nolock(file, iov, nr_segs, ppos);
+       up(&inode->i_sem);
++
++      if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) {
++              ssize_t err;
++
++              err = sync_page_range(inode, mapping, *ppos - ret, ret);
++              if (err < 0)
++                      ret = err;
++      }
+       return ret;
+ }
++EXPORT_SYMBOL(generic_file_writev);
++
++/*
++ * Called under i_sem for writes to S_ISREG files
++ */
+ ssize_t
+ generic_file_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
+       loff_t offset, unsigned long nr_segs)
+ {
+       struct file *file = iocb->ki_filp;
+-      struct address_space *mapping = file->f_dentry->d_inode->i_mapping;
++      struct address_space *mapping = file->f_mapping;
+       ssize_t retval;
+-      if (mapping->nrpages) {
+-              retval = filemap_fdatawrite(mapping);
+-              if (retval == 0)
+-                      retval = filemap_fdatawait(mapping);
+-              if (retval)
+-                      goto out;
++      retval = filemap_write_and_wait(mapping);
++      if (retval == 0) {
++              retval = mapping->a_ops->direct_IO(rw, iocb, iov,
++                                              offset, nr_segs);
++              if (rw == WRITE && mapping->nrpages)
++                      invalidate_inode_pages2(mapping);
+       }
+-
+-      retval = mapping->a_ops->direct_IO(rw, iocb, iov, offset, nr_segs);
+-      if (rw == WRITE && mapping->nrpages)
+-              invalidate_inode_pages2(mapping);
+-out:
+       return retval;
+ }
++
++EXPORT_SYMBOL_GPL(generic_file_direct_IO);
+--- linux-2.6.0-test6/mm/highmem.c     2003-06-14 12:18:24.000000000 -0700
++++ 25/mm/highmem.c    2003-10-05 00:33:25.000000000 -0700
+@@ -24,6 +24,7 @@
+ #include <linux/blkdev.h>
+ #include <linux/init.h>
+ #include <linux/hash.h>
++#include <linux/highmem.h>
+ #include <asm/pgalloc.h>
+ #include <asm/tlbflush.h>
+@@ -62,7 +63,7 @@ static void flush_all_zero_pkmaps(void)
+ {
+       int i;
+-      flush_cache_all();
++      flush_cache_kmaps();
+       for (i = 0; i < LAST_PKMAP; i++) {
+               struct page *page;
+--- linux-2.6.0-test6/mm/madvise.c     2003-08-08 22:55:14.000000000 -0700
++++ 25/mm/madvise.c    2003-10-05 00:34:07.000000000 -0700
+@@ -65,7 +65,7 @@ static long madvise_willneed(struct vm_a
+               end = vma->vm_end;
+       end = ((end - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
+-      force_page_cache_readahead(file->f_dentry->d_inode->i_mapping,
++      force_page_cache_readahead(file->f_mapping,
+                       file, start, max_sane_readahead(end - start));
+       return 0;
+ }
+--- linux-2.6.0-test6/mm/Makefile      2003-09-08 13:58:59.000000000 -0700
++++ 25/mm/Makefile     2003-10-05 00:36:48.000000000 -0700
+@@ -12,3 +12,6 @@ obj-y                        := bootmem.o filemap.o mempool.o
+                          slab.o swap.o truncate.o vmscan.o $(mmu-y)
+ obj-$(CONFIG_SWAP)    += page_io.o swap_state.o swapfile.o
++
++obj-$(CONFIG_X86_4G) += usercopy.o
++
+--- linux-2.6.0-test6/mm/memory.c      2003-09-27 18:57:47.000000000 -0700
++++ 25/mm/memory.c     2003-10-05 00:36:48.000000000 -0700
+@@ -100,7 +100,8 @@ static inline void free_one_pmd(struct m
+       pte_free_tlb(tlb, page);
+ }
+-static inline void free_one_pgd(struct mmu_gather *tlb, pgd_t * dir)
++static inline void free_one_pgd(struct mmu_gather *tlb, pgd_t * dir,
++                                                      int pgd_idx)
+ {
+       int j;
+       pmd_t * pmd;
+@@ -114,8 +115,11 @@ static inline void free_one_pgd(struct m
+       }
+       pmd = pmd_offset(dir, 0);
+       pgd_clear(dir);
+-      for (j = 0; j < PTRS_PER_PMD ; j++)
++      for (j = 0; j < PTRS_PER_PMD ; j++) {
++              if (pgd_idx * PGDIR_SIZE + j * PMD_SIZE >= TASK_SIZE)
++                      break;
+               free_one_pmd(tlb, pmd+j);
++      }
+       pmd_free_tlb(tlb, pmd);
+ }
+@@ -128,11 +132,13 @@ static inline void free_one_pgd(struct m
+ void clear_page_tables(struct mmu_gather *tlb, unsigned long first, int nr)
+ {
+       pgd_t * page_dir = tlb->mm->pgd;
++      int pgd_idx = first;
+       page_dir += first;
+       do {
+-              free_one_pgd(tlb, page_dir);
++              free_one_pgd(tlb, page_dir, pgd_idx);
+               page_dir++;
++              pgd_idx++;
+       } while (--nr);
+ }
+@@ -430,7 +436,7 @@ zap_pmd_range(struct mmu_gather *tlb, pg
+               unsigned long address, unsigned long size)
+ {
+       pmd_t * pmd;
+-      unsigned long end;
++      unsigned long end, pgd_boundary;
+       if (pgd_none(*dir))
+               return;
+@@ -441,8 +447,9 @@ zap_pmd_range(struct mmu_gather *tlb, pg
+       }
+       pmd = pmd_offset(dir, address);
+       end = address + size;
+-      if (end > ((address + PGDIR_SIZE) & PGDIR_MASK))
+-              end = ((address + PGDIR_SIZE) & PGDIR_MASK);
++      pgd_boundary = ((address + PGDIR_SIZE) & PGDIR_MASK);
++      if (pgd_boundary && (end > pgd_boundary))
++              end = pgd_boundary;
+       do {
+               zap_pte_range(tlb, pmd, address, end - address);
+               address = (address + PMD_SIZE) & PMD_MASK; 
+@@ -518,7 +525,7 @@ int unmap_vmas(struct mmu_gather **tlbp,
+               unsigned long end_addr, unsigned long *nr_accounted)
+ {
+       unsigned long zap_bytes = ZAP_BLOCK_SIZE;
+-      unsigned long tlb_start;        /* For tlb_finish_mmu */
++      unsigned long tlb_start = 0;    /* For tlb_finish_mmu */
+       int tlb_start_valid = 0;
+       int ret = 0;
+@@ -596,6 +603,11 @@ void zap_page_range(struct vm_area_struc
+       might_sleep();
+       if (is_vm_hugetlb_page(vma)) {
++              static int x;
++              if (x < 10) {
++                      x++;
++                      dump_stack();
++              }
+               zap_hugepage_range(vma, address, size);
+               return;
+       }
+@@ -678,6 +690,7 @@ int get_user_pages(struct task_struct *t
+               struct page **pages, struct vm_area_struct **vmas)
+ {
+       int i;
++      int vm_io;
+       unsigned int flags;
+       /* 
+@@ -734,8 +747,10 @@ int get_user_pages(struct task_struct *t
+               }
+ #endif
+-              if (!vma || (pages && (vma->vm_flags & VM_IO))
+-                              || !(flags & vma->vm_flags))
++              if (!vma)
++                      return i ? : -EFAULT;
++              vm_io = vma->vm_flags & VM_IO;
++              if ((pages && vm_io) || !(flags & vma->vm_flags))
+                       return i ? : -EFAULT;
+               if (is_vm_hugetlb_page(vma)) {
+@@ -743,9 +758,17 @@ int get_user_pages(struct task_struct *t
+                                               &start, &len, i);
+                       continue;
+               }
++
+               spin_lock(&mm->page_table_lock);
+               do {
+-                      struct page *map;
++                      struct page *map = NULL;
++
++                      /*
++                       * We don't follow pagetables for VM_IO regions - they
++                       * may have no pageframes.
++                       */
++                      if (vm_io)
++                              goto no_follow;
+                       while (!(map = follow_page(mm, start, write))) {
+                               spin_unlock(&mm->page_table_lock);
+                               switch (handle_mm_fault(mm,vma,start,write)) {
+@@ -777,6 +800,7 @@ int get_user_pages(struct task_struct *t
+                               if (!PageReserved(pages[i]))
+                                       page_cache_get(pages[i]);
+                       }
++no_follow:
+                       if (vmas)
+                               vmas[i] = vma;
+                       i++;
+@@ -1398,7 +1422,7 @@ do_no_page(struct mm_struct *mm, struct 
+       spin_unlock(&mm->page_table_lock);
+       if (vma->vm_file) {
+-              mapping = vma->vm_file->f_dentry->d_inode->i_mapping;
++              mapping = vma->vm_file->f_mapping;
+               sequence = atomic_read(&mapping->truncate_count);
+       }
+       smp_rmb();  /* Prevent CPU from reordering lock-free ->nopage() */
+@@ -1441,6 +1465,7 @@ retry:
+               sequence = atomic_read(&mapping->truncate_count);
+               spin_unlock(&mm->page_table_lock);
+               page_cache_release(new_page);
++              pte_chain_free(pte_chain);
+               goto retry;
+       }
+       page_table = pte_offset_map(pmd, address);
+--- linux-2.6.0-test6/mm/mincore.c     2003-06-14 12:18:48.000000000 -0700
++++ 25/mm/mincore.c    2003-10-05 00:34:07.000000000 -0700
+@@ -26,7 +26,7 @@ static unsigned char mincore_page(struct
+       unsigned long pgoff)
+ {
+       unsigned char present = 0;
+-      struct address_space * as = vma->vm_file->f_dentry->d_inode->i_mapping;
++      struct address_space * as = vma->vm_file->f_mapping;
+       struct page * page;
+       page = find_get_page(as, pgoff);
+--- linux-2.6.0-test6/mm/mmap.c        2003-09-27 18:57:47.000000000 -0700
++++ 25/mm/mmap.c       2003-10-05 00:36:32.000000000 -0700
+@@ -79,11 +79,10 @@ static void remove_shared_vm_struct(stru
+       struct file *file = vma->vm_file;
+       if (file) {
+-              struct inode *inode = file->f_dentry->d_inode;
+-
+-              down(&inode->i_mapping->i_shared_sem);
+-              __remove_shared_vm_struct(vma, inode);
+-              up(&inode->i_mapping->i_shared_sem);
++              struct address_space *mapping = file->f_mapping;
++              down(&mapping->i_shared_sem);
++              __remove_shared_vm_struct(vma, file->f_dentry->d_inode);
++              up(&mapping->i_shared_sem);
+       }
+ }
+@@ -234,11 +233,10 @@ static inline void __vma_link_file(struc
+       file = vma->vm_file;
+       if (file) {
+-              struct inode * inode = file->f_dentry->d_inode;
+-              struct address_space *mapping = inode->i_mapping;
++              struct address_space *mapping = file->f_mapping;
+               if (vma->vm_flags & VM_DENYWRITE)
+-                      atomic_dec(&inode->i_writecount);
++                      atomic_dec(&file->f_dentry->d_inode->i_writecount);
+               if (vma->vm_flags & VM_SHARED)
+                       list_add_tail(&vma->shared, &mapping->i_mmap_shared);
+@@ -264,7 +262,7 @@ static void vma_link(struct mm_struct *m
+       struct address_space *mapping = NULL;
+       if (vma->vm_file)
+-              mapping = vma->vm_file->f_dentry->d_inode->i_mapping;
++              mapping = vma->vm_file->f_mapping;
+       if (mapping)
+               down(&mapping->i_shared_sem);
+@@ -280,6 +278,26 @@ static void vma_link(struct mm_struct *m
+ }
+ /*
++ * Insert vm structure into process list sorted by address and into the inode's
++ * i_mmap ring. The caller should hold mm->page_table_lock and
++ * ->f_mappping->i_shared_sem if vm_file is non-NULL.
++ */
++static void
++__insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma)
++{
++      struct vm_area_struct * __vma, * prev;
++      struct rb_node ** rb_link, * rb_parent;
++
++      __vma = find_vma_prepare(mm, vma->vm_start,&prev, &rb_link, &rb_parent);
++      if (__vma && __vma->vm_start < vma->vm_end)
++              BUG();
++      __vma_link(mm, vma, prev, rb_link, rb_parent);
++      mark_mm_hugetlb(mm, vma);
++      mm->map_count++;
++      validate_mm(mm);
++}
++
++/*
+  * If the vma has a ->close operation then the driver probably needs to release
+  * per-vma resources, so we don't attempt to merge those.
+  */
+@@ -351,7 +369,8 @@ static int vma_merge(struct mm_struct *m
+                       unsigned long end, unsigned long vm_flags,
+                       struct file *file, unsigned long pgoff)
+ {
+-      spinlock_t * lock = &mm->page_table_lock;
++      spinlock_t *lock = &mm->page_table_lock;
++      struct semaphore *i_shared_sem;
+       /*
+        * We later require that vma->vm_flags == vm_flags, so this tests
+@@ -360,6 +379,8 @@ static int vma_merge(struct mm_struct *m
+       if (vm_flags & VM_SPECIAL)
+               return 0;
++      i_shared_sem = file ? &file->f_mapping->i_shared_sem : NULL;
++
+       if (!prev) {
+               prev = rb_entry(rb_parent, struct vm_area_struct, vm_rb);
+               goto merge_next;
+@@ -377,7 +398,7 @@ static int vma_merge(struct mm_struct *m
+               if (unlikely(file && prev->vm_next &&
+                               prev->vm_next->vm_file == file)) {
+-                      down(&inode->i_mapping->i_shared_sem);
++                      down(i_shared_sem);
+                       need_up = 1;
+               }
+               spin_lock(lock);
+@@ -395,7 +416,7 @@ static int vma_merge(struct mm_struct *m
+                       __remove_shared_vm_struct(next, inode);
+                       spin_unlock(lock);
+                       if (need_up)
+-                              up(&inode->i_mapping->i_shared_sem);
++                              up(i_shared_sem);
+                       if (file)
+                               fput(file);
+@@ -405,7 +426,7 @@ static int vma_merge(struct mm_struct *m
+               }
+               spin_unlock(lock);
+               if (need_up)
+-                      up(&inode->i_mapping->i_shared_sem);
++                      up(i_shared_sem);
+               return 1;
+       }
+@@ -419,14 +440,17 @@ static int vma_merge(struct mm_struct *m
+                               pgoff, (end - addr) >> PAGE_SHIFT))
+                       return 0;
+               if (end == prev->vm_start) {
++                      if (file)
++                              down(i_shared_sem); /* invalidate_mmap_range */
+                       spin_lock(lock);
+                       prev->vm_start = addr;
+                       prev->vm_pgoff -= (end - addr) >> PAGE_SHIFT;
+                       spin_unlock(lock);
++                      if (file)
++                              up(i_shared_sem);
+                       return 1;
+               }
+       }
+-
+       return 0;
+ }
+@@ -1136,6 +1160,7 @@ int split_vma(struct mm_struct * mm, str
+             unsigned long addr, int new_below)
+ {
+       struct vm_area_struct *new;
++      struct address_space *mapping = NULL;
+       if (mm->map_count >= MAX_MAP_COUNT)
+               return -ENOMEM;
+@@ -1149,12 +1174,9 @@ int split_vma(struct mm_struct * mm, str
+       INIT_LIST_HEAD(&new->shared);
+-      if (new_below) {
++      if (new_below)
+               new->vm_end = addr;
+-              vma->vm_start = addr;
+-              vma->vm_pgoff += ((addr - new->vm_start) >> PAGE_SHIFT);
+-      } else {
+-              vma->vm_end = addr;
++      else {
+               new->vm_start = addr;
+               new->vm_pgoff += ((addr - vma->vm_start) >> PAGE_SHIFT);
+       }
+@@ -1165,7 +1187,25 @@ int split_vma(struct mm_struct * mm, str
+       if (new->vm_ops && new->vm_ops->open)
+               new->vm_ops->open(new);
+-      insert_vm_struct(mm, new);
++      if (vma->vm_file)
++               mapping = vma->vm_file->f_mapping;
++
++      if (mapping)
++              down(&mapping->i_shared_sem);
++      spin_lock(&mm->page_table_lock);
++
++      if (new_below) {
++              vma->vm_start = addr;
++              vma->vm_pgoff += ((addr - new->vm_start) >> PAGE_SHIFT);
++      } else
++              vma->vm_end = addr;
++
++      __insert_vm_struct(mm, new);
++
++      spin_unlock(&mm->page_table_lock);
++      if (mapping)
++              up(&mapping->i_shared_sem);
++
+       return 0;
+ }
+--- linux-2.6.0-test6/mm/msync.c       2003-06-14 12:18:07.000000000 -0700
++++ 25/mm/msync.c      2003-10-05 00:34:08.000000000 -0700
+@@ -146,20 +146,20 @@ static int msync_interval(struct vm_area
+               ret = filemap_sync(vma, start, end-start, flags);
+               if (!ret && (flags & MS_SYNC)) {
+-                      struct inode *inode = file->f_dentry->d_inode;
++                      struct address_space *mapping = file->f_mapping;
+                       int err;
+-                      down(&inode->i_sem);
+-                      ret = filemap_fdatawrite(inode->i_mapping);
++                      down(&mapping->host->i_sem);
++                      ret = filemap_fdatawrite(mapping);
+                       if (file->f_op && file->f_op->fsync) {
+                               err = file->f_op->fsync(file,file->f_dentry,1);
+                               if (err && !ret)
+                                       ret = err;
+                       }
+-                      err = filemap_fdatawait(inode->i_mapping);
++                      err = filemap_fdatawait(mapping);
+                       if (!ret)
+                               ret = err;
+-                      up(&inode->i_sem);
++                      up(&mapping->host->i_sem);
+               }
+       }
+       return ret;
+--- linux-2.6.0-test6/mm/page_alloc.c  2003-09-27 18:57:47.000000000 -0700
++++ 25/mm/page_alloc.c 2003-10-05 00:34:39.000000000 -0700
+@@ -50,7 +50,7 @@ EXPORT_SYMBOL(nr_swap_pages);
+  * Used by page_zone() to look up the address of the struct zone whose
+  * id is encoded in the upper bits of page->flags
+  */
+-struct zone *zone_table[MAX_NR_ZONES*MAX_NR_NODES];
++struct zone *zone_table[MAX_NR_ZONES*MAX_NUMNODES];
+ EXPORT_SYMBOL(zone_table);
+ static char *zone_names[MAX_NR_ZONES] = { "DMA", "Normal", "HighMem" };
+--- linux-2.6.0-test6/mm/page-writeback.c      2003-09-27 18:57:47.000000000 -0700
++++ 25/mm/page-writeback.c     2003-10-05 00:37:06.000000000 -0700
+@@ -28,6 +28,7 @@
+ #include <linux/smp.h>
+ #include <linux/sysctl.h>
+ #include <linux/cpu.h>
++#include <linux/pagevec.h>
+ /*
+  * The maximum number of pages to writeout in a single bdflush/kupdate
+@@ -146,7 +147,7 @@ get_dirty_limits(struct page_state *ps, 
+  * If we're over `background_thresh' then pdflush is woken to perform some
+  * writeout.
+  */
+-static void balance_dirty_pages(struct address_space *mapping)
++static int balance_dirty_pages(struct address_space *mapping)
+ {
+       struct page_state ps;
+       long nr_reclaimable;
+@@ -163,6 +164,7 @@ static void balance_dirty_pages(struct a
+                       .sync_mode      = WB_SYNC_NONE,
+                       .older_than_this = NULL,
+                       .nr_to_write    = write_chunk,
++                      .nonblocking    = !is_sync_wait(current->io_wait)
+               };
+               get_dirty_limits(&ps, &background_thresh, &dirty_thresh);
+@@ -189,7 +191,11 @@ static void balance_dirty_pages(struct a
+                       if (pages_written >= write_chunk)
+                               break;          /* We've done our duty */
+               }
+-              blk_congestion_wait(WRITE, HZ/10);
++              if (-EIOCBRETRY == blk_congestion_wait_wq(WRITE, HZ/10,
++                      current->io_wait)) {
++                      pr_debug("async blk congestion wait\n");
++                      return -EIOCBRETRY;
++              }
+       }
+       if (nr_reclaimable + ps.nr_writeback <= dirty_thresh)
+@@ -197,6 +203,8 @@ static void balance_dirty_pages(struct a
+       if (!writeback_in_progress(bdi) && nr_reclaimable > background_thresh)
+               pdflush_operation(background_writeout, 0);
++
++      return 0;
+ }
+ /**
+@@ -212,7 +220,7 @@ static void balance_dirty_pages(struct a
+  * decrease the ratelimiting by a lot, to prevent individual processes from
+  * overshooting the limit by (ratelimit_pages) each.
+  */
+-void balance_dirty_pages_ratelimited(struct address_space *mapping)
++int balance_dirty_pages_ratelimited(struct address_space *mapping)
+ {
+       static DEFINE_PER_CPU(int, ratelimits) = 0;
+       long ratelimit;
+@@ -228,10 +236,10 @@ void balance_dirty_pages_ratelimited(str
+       if (get_cpu_var(ratelimits)++ >= ratelimit) {
+               __get_cpu_var(ratelimits) = 0;
+               put_cpu_var(ratelimits);
+-              balance_dirty_pages(mapping);
+-              return;
++              return balance_dirty_pages(mapping);
+       }
+       put_cpu_var(ratelimits);
++      return 0;
+ }
+ /*
+@@ -566,3 +574,152 @@ int test_clear_page_dirty(struct page *p
+       return 0;
+ }
+ EXPORT_SYMBOL(test_clear_page_dirty);
++
++
++static ssize_t operate_on_page_range(struct address_space *mapping,
++              loff_t pos, size_t count, int (*operator)(struct page *))
++{
++      pgoff_t first = pos >> PAGE_CACHE_SHIFT;
++      pgoff_t last = (pos + count - 1) >> PAGE_CACHE_SHIFT;   /* inclusive */
++      pgoff_t next = first, curr = first;
++      struct pagevec pvec;
++      ssize_t ret = 0, bytes = 0;
++      int i, nr;
++
++      if (count == 0)
++              return 0;
++
++      pagevec_init(&pvec, 0);
++      while ((nr = pagevec_lookup(&pvec, mapping, &next,
++                              min((pgoff_t)PAGEVEC_SIZE, last - next + 1)))) {
++              for (i = 0; i < pagevec_count(&pvec); i++) {
++                      struct page *page = pvec.pages[i];
++
++                      curr = page->index;
++                      if (page->mapping != mapping) /* truncated ?*/ {
++                              curr = next;
++                              break;
++                      } else {
++                              ret = (*operator)(page);
++                              if (ret == -EIOCBRETRY)
++                                      break;
++                              if (PageError(page)) {
++                                      if (!ret)
++                                              ret = -EIO;
++                              } else
++                                      curr++;
++                      }
++              }
++              pagevec_release(&pvec);
++              if ((ret == -EIOCBRETRY) || (next > last))
++                      break;
++      }
++      if (!nr)
++              curr = last + 1;
++
++      bytes = (curr << PAGE_CACHE_SHIFT) - pos;
++      if (bytes > count)
++              bytes = count;
++      return (bytes && (!ret || (ret == -EIOCBRETRY))) ? bytes : ret;
++}
++
++static int page_waiter(struct page *page)
++{
++      return wait_on_page_writeback_wq(page, current->io_wait);
++}
++
++static size_t
++wait_on_page_range(struct address_space *mapping, loff_t pos, size_t count)
++{
++      return operate_on_page_range(mapping, pos, count, page_waiter);
++}
++
++static int page_writer(struct page *page)
++{
++      struct writeback_control wbc = {
++              .sync_mode      = WB_SYNC_ALL,
++              .nr_to_write    = 1,
++      };
++
++      lock_page(page);
++      if (!page->mapping) {   /* truncated */
++              unlock_page(page);
++              return 0;
++      }
++      if (!test_clear_page_dirty(page)) {
++              unlock_page(page);
++              return 0;
++      }
++      wait_on_page_writeback(page);
++      return page->mapping->a_ops->writepage(page, &wbc);
++}
++
++static ssize_t
++write_out_page_range(struct address_space *mapping, loff_t pos, size_t count)
++{
++      return operate_on_page_range(mapping, pos, count, page_writer);
++}
++
++/*
++ * Write and wait upon all the pages in the passed range.  This is a "data
++ * integrity" operation.  It waits upon in-flight writeout before starting and
++ * waiting upon new writeout.  If there was an IO error, return it.
++ *
++ * We need to re-take i_sem during the generic_osync_inode list walk because
++ * it is otherwise livelockable.
++ */
++ssize_t sync_page_range(struct inode *inode, struct address_space *mapping,
++                      loff_t pos, size_t count)
++{
++      int ret = 0;
++
++      if (in_aio()) {
++              /* Already issued writeouts for this iocb ? */
++              if (kiocbTrySync(io_wait_to_kiocb(current->io_wait)))
++                      goto do_wait; /* just need to check if done */
++      }
++      if (!mapping->a_ops->writepage)
++              return 0;
++      if (mapping->backing_dev_info->memory_backed)
++              return 0;
++      ret = write_out_page_range(mapping, pos, count);
++      if (ret >= 0) {
++              down(&inode->i_sem);
++              ret = generic_osync_inode(inode, mapping, OSYNC_METADATA);
++              up(&inode->i_sem);
++      }
++do_wait:
++      if (ret >= 0)
++              ret = wait_on_page_range(mapping, pos, count);
++      return ret;
++}
++
++/*
++ * It is really better to use sync_page_range, rather than call
++ * sync_page_range_nolock while holding i_sem, if you don't
++ * want to block parallel O_SYNC writes until the pages in this
++ * range are written out.
++ */
++ssize_t sync_page_range_nolock(struct inode *inode, struct address_space
++      *mapping, loff_t pos, size_t count)
++{
++      ssize_t ret = 0;
++
++      if (in_aio()) {
++              /* Already issued writeouts for this iocb ? */
++              if (kiocbTrySync(io_wait_to_kiocb(current->io_wait)))
++                      goto do_wait; /* just need to check if done */
++      }
++      if (!mapping->a_ops->writepage)
++              return 0;
++      if (mapping->backing_dev_info->memory_backed)
++              return 0;
++      ret = write_out_page_range(mapping, pos, count);
++      if (ret >= 0) {
++              ret = generic_osync_inode(inode, mapping, OSYNC_METADATA);
++      }
++do_wait:
++      if (ret >= 0)
++              ret = wait_on_page_range(mapping, pos, count);
++      return ret;
++}
+--- linux-2.6.0-test6/mm/pdflush.c     2003-06-14 12:18:52.000000000 -0700
++++ 25/mm/pdflush.c    2003-10-05 00:34:35.000000000 -0700
+@@ -84,6 +84,8 @@ struct pdflush_work {
+       unsigned long when_i_went_to_sleep;
+ };
++static int wakeup_count = 100;
++
+ static int __pdflush(struct pdflush_work *my_work)
+ {
+       daemonize("pdflush");
+@@ -112,7 +114,10 @@ static int __pdflush(struct pdflush_work
+               spin_lock_irq(&pdflush_lock);
+               if (!list_empty(&my_work->list)) {
+-                      printk("pdflush: bogus wakeup!\n");
++                      if (wakeup_count > 0) {
++                              wakeup_count--;
++                              printk("pdflush: bogus wakeup!\n");
++                      }
+                       my_work->fn = NULL;
+                       continue;
+               }
+@@ -182,6 +187,7 @@ int pdflush_operation(void (*fn)(unsigne
+ {
+       unsigned long flags;
+       int ret = 0;
++      static int poke_count = 0;
+       if (fn == NULL)
+               BUG();          /* Hard to diagnose if it's deferred */
+@@ -190,9 +196,19 @@ int pdflush_operation(void (*fn)(unsigne
+       if (list_empty(&pdflush_list)) {
+               spin_unlock_irqrestore(&pdflush_lock, flags);
+               ret = -1;
++              if (wakeup_count < 100 && poke_count < 10) {
++                      printk("%s: no threads\n", __FUNCTION__);
++                      dump_stack();
++                      poke_count++;
++              }
+       } else {
+               struct pdflush_work *pdf;
++              if (wakeup_count < 100 && poke_count < 10) {
++                      printk("%s: found a thread\n", __FUNCTION__);
++                      dump_stack();
++                      poke_count++;
++              }
+               pdf = list_entry(pdflush_list.next, struct pdflush_work, list);
+               list_del_init(&pdf->list);
+               if (list_empty(&pdflush_list))
+--- linux-2.6.0-test6/mm/shmem.c       2003-09-27 18:57:47.000000000 -0700
++++ 25/mm/shmem.c      2003-10-05 00:34:11.000000000 -0700
+@@ -1147,7 +1147,7 @@ shmem_file_write(struct file *file, cons
+       pos = *ppos;
+       written = 0;
+-      err = generic_write_checks(inode, file, &pos, &count, 0);
++      err = generic_write_checks(file, &pos, &count, 0);
+       if (err || !count)
+               goto out;
+@@ -1933,6 +1933,7 @@ struct file *shmem_file_setup(char *name
+       inode->i_nlink = 0;     /* It is unlinked */
+       file->f_vfsmnt = mntget(shm_mnt);
+       file->f_dentry = dentry;
++      file->f_mapping = inode->i_mapping;
+       file->f_op = &shmem_file_operations;
+       file->f_mode = FMODE_WRITE | FMODE_READ;
+       return(file);
+--- linux-2.6.0-test6/mm/slab.c        2003-09-27 18:57:47.000000000 -0700
++++ 25/mm/slab.c       2003-10-05 00:36:48.000000000 -0700
+@@ -250,7 +250,7 @@ struct kmem_cache_s {
+       unsigned int            limit;
+ /* 2) touched by every alloc & free from the backend */
+       struct kmem_list3       lists;
+-      /* NUMA: kmem_3list_t   *nodelists[NR_NODES] */
++      /* NUMA: kmem_3list_t   *nodelists[MAX_NUMNODES] */
+       unsigned int            objsize;
+       unsigned int            flags;  /* constant flags */
+       unsigned int            num;    /* # of objs per slab */
+@@ -1178,7 +1178,8 @@ next:
+               cachep = NULL;
+               goto opps;
+       }
+-      slab_size = L1_CACHE_ALIGN(cachep->num*sizeof(kmem_bufctl_t)+sizeof(struct slab));
++      slab_size = L1_CACHE_ALIGN(cachep->num*sizeof(kmem_bufctl_t) +
++                      sizeof(struct slab));
+       /*
+        * If the slab has been placed off-slab, and we have enough space then
+@@ -1222,10 +1223,13 @@ next:
+                        * the cache that's used by kmalloc(24), otherwise
+                        * the creation of further caches will BUG().
+                        */
+-                      cachep->array[smp_processor_id()] = &initarray_generic.cache;
++                      cachep->array[smp_processor_id()] =
++                                      &initarray_generic.cache;
+                       g_cpucache_up = PARTIAL;
+               } 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);
+               }
+               BUG_ON(!ac_data(cachep));
+               ac_data(cachep)->avail = 0;
+@@ -1239,7 +1243,7 @@ next:
+       } 
+       cachep->lists.next_reap = jiffies + REAPTIMEOUT_LIST3 +
+-                                      ((unsigned long)cachep)%REAPTIMEOUT_LIST3;
++                              ((unsigned long)cachep)%REAPTIMEOUT_LIST3;
+       /* Need the semaphore to access the chain. */
+       down(&cache_chain_sem);
+@@ -1252,16 +1256,24 @@ next:
+               list_for_each(p, &cache_chain) {
+                       kmem_cache_t *pc = list_entry(p, kmem_cache_t, next);
+                       char tmp;
+-                      /* This happens when the module gets unloaded and doesn't
+-                         destroy its slab cache and noone else reuses the vmalloc
+-                         area of the module. Print a warning. */
+-                      if (__get_user(tmp,pc->name)) { 
+-                              printk("SLAB: cache with size %d has lost its name\n", 
+-                                      pc->objsize); 
++
++                      /*
++                       * This happens when the module gets unloaded and
++                       * doesn't destroy its slab cache and noone else reuses
++                       * the vmalloc area of the module. Print a warning.
++                       */
++#ifdef CONFIG_X86_UACCESS_INDIRECT
++                      if (__direct_get_user(tmp,pc->name)) {
++#else
++                      if (__get_user(tmp,pc->name)) {
++#endif
++                              printk("SLAB: cache with size %d has lost its "
++                                              "name\n", pc->objsize);
+                               continue; 
+                       }       
+                       if (!strcmp(pc->name,name)) { 
+-                              printk("kmem_cache_create: duplicate cache %s\n",name); 
++                              printk("kmem_cache_create: duplicate "
++                                              "cache %s\n",name);
+                               up(&cache_chain_sem); 
+                               BUG(); 
+                       }       
+@@ -2675,8 +2687,8 @@ struct seq_operations slabinfo_op = {
+  * slabinfo_write - Tuning for the slab allocator
+  * @file: unused
+  * @buffer: user buffer
+- * @count: data len
+- * @data: unused
++ * @count: data length
++ * @ppos: unused
+  */
+ ssize_t slabinfo_write(struct file *file, const char __user *buffer,
+                               size_t count, loff_t *ppos)
+--- linux-2.6.0-test6/mm/swap.c        2003-07-10 18:50:32.000000000 -0700
++++ 25/mm/swap.c       2003-10-05 00:37:03.000000000 -0700
+@@ -339,12 +339,15 @@ void pagevec_strip(struct pagevec *pvec)
+  * The search returns a group of mapping-contiguous pages with ascending
+  * indexes.  There may be holes in the indices due to not-present pages.
+  *
+- * pagevec_lookup() returns the number of pages which were found.
++ * pagevec_lookup() returns the number of pages which were found
++ * and also atomically sets the next offset to continue looking up
++ * mapping contiguous pages from (useful when doing a range of
++ * pagevec lookups in chunks of PAGEVEC_SIZE).
+  */
+ unsigned int pagevec_lookup(struct pagevec *pvec, struct address_space *mapping,
+-              pgoff_t start, unsigned int nr_pages)
++              pgoff_t *next, unsigned int nr_pages)
+ {
+-      pvec->nr = find_get_pages(mapping, start, nr_pages, pvec->pages);
++      pvec->nr = find_get_pages(mapping, next, nr_pages, pvec->pages);
+       return pagevec_count(pvec);
+ }
+--- linux-2.6.0-test6/mm/swapfile.c    2003-09-08 13:58:59.000000000 -0700
++++ 25/mm/swapfile.c   2003-10-05 00:34:11.000000000 -0700
+@@ -912,7 +912,7 @@ static int setup_swap_extents(struct swa
+       sector_t last_block;
+       int ret;
+-      inode = sis->swap_file->f_dentry->d_inode;
++      inode = sis->swap_file->f_mapping->host;
+       if (S_ISBLK(inode->i_mode)) {
+               ret = add_swap_extent(sis, 0, sis->max, 0);
+               goto done;
+@@ -1031,13 +1031,13 @@ asmlinkage long sys_swapoff(const char _
+       if (IS_ERR(victim))
+               goto out;
+-      mapping = victim->f_dentry->d_inode->i_mapping;
++      mapping = victim->f_mapping;
+       prev = -1;
+       swap_list_lock();
+       for (type = swap_list.head; type >= 0; type = swap_info[type].next) {
+               p = swap_info + type;
+               if ((p->flags & SWP_ACTIVE) == SWP_ACTIVE) {
+-                      if (p->swap_file->f_dentry->d_inode->i_mapping==mapping)
++                      if (p->swap_file->f_mapping == mapping)
+                               break;
+               }
+               prev = type;
+@@ -1099,13 +1099,12 @@ asmlinkage long sys_swapoff(const char _
+       swap_device_unlock(p);
+       swap_list_unlock();
+       vfree(swap_map);
+-      if (S_ISBLK(swap_file->f_dentry->d_inode->i_mode)) {
+-              struct block_device *bdev;
+-              bdev = swap_file->f_dentry->d_inode->i_bdev;
++      if (S_ISBLK(mapping->host->i_mode)) {
++              struct block_device *bdev = I_BDEV(mapping->host);
+               set_blocksize(bdev, p->old_block_size);
+               bd_release(bdev);
+       } else {
+-              up(&swap_file->f_dentry->d_inode->i_mapping->host->i_sem);
++              up(&mapping->host->i_sem);
+       }
+       filp_close(swap_file, NULL);
+       err = 0;
+@@ -1231,8 +1230,8 @@ asmlinkage long sys_swapon(const char __
+       int swapfilesize;
+       unsigned short *swap_map;
+       struct page *page = NULL;
+-      struct inode *inode;
+-      struct inode *downed_inode = NULL;
++      struct inode *inode = NULL;
++      int did_down = 0;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+@@ -1279,8 +1278,8 @@ asmlinkage long sys_swapon(const char __
+       }
+       p->swap_file = swap_file;
+-      inode = swap_file->f_dentry->d_inode;
+-      mapping = swap_file->f_dentry->d_inode->i_mapping;
++      mapping = swap_file->f_mapping;
++      inode = mapping->host;
+       error = -EBUSY;
+       for (i = 0; i < nr_swapfiles; i++) {
+@@ -1288,32 +1287,32 @@ asmlinkage long sys_swapon(const char __
+               if (i == type || !q->swap_file)
+                       continue;
+-              if (mapping == q->swap_file->f_dentry->d_inode->i_mapping)
++              if (mapping == q->swap_file->f_mapping)
+                       goto bad_swap;
+       }
+       error = -EINVAL;
+       if (S_ISBLK(inode->i_mode)) {
+-              bdev = inode->i_bdev;
++              bdev = I_BDEV(inode);
+               error = bd_claim(bdev, sys_swapon);
+               if (error < 0) {
+                       bdev = NULL;
+                       goto bad_swap;
+               }
+               p->old_block_size = block_size(bdev);
+-              error = set_blocksize(inode->i_bdev, PAGE_SIZE);
++              error = set_blocksize(bdev, PAGE_SIZE);
+               if (error < 0)
+                       goto bad_swap;
+               p->bdev = bdev;
+       } else if (S_ISREG(inode->i_mode)) {
+               p->bdev = inode->i_sb->s_bdev;
+-              downed_inode = mapping->host;
+-              down(&downed_inode->i_sem);
++              down(&inode->i_sem);
++              did_down = 1;
+       } else {
+               goto bad_swap;
+       }
+-      swapfilesize = i_size_read(mapping->host) >> PAGE_SHIFT;
++      swapfilesize = i_size_read(inode) >> PAGE_SHIFT;
+       /*
+        * Read the swap header.
+@@ -1461,8 +1460,8 @@ out:
+       }
+       if (name)
+               putname(name);
+-      if (error && downed_inode)
+-              up(&downed_inode->i_sem);
++      if (error && did_down)
++              up(&inode->i_sem);
+       return error;
+ }
+--- linux-2.6.0-test6/mm/truncate.c    2003-06-14 12:18:34.000000000 -0700
++++ 25/mm/truncate.c   2003-10-05 00:37:03.000000000 -0700
+@@ -121,14 +121,10 @@ void truncate_inode_pages(struct address
+       pagevec_init(&pvec, 0);
+       next = start;
+-      while (pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) {
++      while (pagevec_lookup(&pvec, mapping, &next, PAGEVEC_SIZE)) {
+               for (i = 0; i < pagevec_count(&pvec); i++) {
+                       struct page *page = pvec.pages[i];
+-                      pgoff_t page_index = page->index;
+-                      if (page_index > next)
+-                              next = page_index;
+-                      next++;
+                       if (TestSetPageLocked(page))
+                               continue;
+                       if (PageWriteback(page)) {
+@@ -154,7 +150,7 @@ void truncate_inode_pages(struct address
+       next = start;
+       for ( ; ; ) {
+-              if (!pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) {
++              if (!pagevec_lookup(&pvec, mapping, &next, PAGEVEC_SIZE)) {
+                       if (next == start)
+                               break;
+                       next = start;
+@@ -165,9 +161,6 @@ void truncate_inode_pages(struct address
+                       lock_page(page);
+                       wait_on_page_writeback(page);
+-                      if (page->index > next)
+-                              next = page->index;
+-                      next++;
+                       truncate_complete_page(mapping, page);
+                       unlock_page(page);
+               }
+@@ -198,17 +191,13 @@ unsigned long invalidate_mapping_pages(s
+       pagevec_init(&pvec, 0);
+       while (next <= end &&
+-                      pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) {
++                      pagevec_lookup(&pvec, mapping, &next, PAGEVEC_SIZE)) {
+               for (i = 0; i < pagevec_count(&pvec); i++) {
+                       struct page *page = pvec.pages[i];
+                       if (TestSetPageLocked(page)) {
+-                              next++;
+                               continue;
+                       }
+-                      if (page->index > next)
+-                              next = page->index;
+-                      next++;
+                       if (PageDirty(page) || PageWriteback(page))
+                               goto unlock;
+                       if (page_mapped(page))
+@@ -245,14 +234,13 @@ void invalidate_inode_pages2(struct addr
+       int i;
+       pagevec_init(&pvec, 0);
+-      while (pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) {
++      while (pagevec_lookup(&pvec, mapping, &next, PAGEVEC_SIZE)) {
+               for (i = 0; i < pagevec_count(&pvec); i++) {
+                       struct page *page = pvec.pages[i];
+                       lock_page(page);
+                       if (page->mapping == mapping) { /* truncate race? */
+                               wait_on_page_writeback(page);
+-                              next = page->index + 1;
+                               if (page_mapped(page))
+                                       clear_page_dirty(page);
+                               else
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/mm/usercopy.c   2003-10-05 00:36:48.000000000 -0700
+@@ -0,0 +1,279 @@
++/*
++ * linux/mm/usercopy.c
++ *
++ * (C) Copyright 2003 Ingo Molnar
++ *
++ * Generic implementation of all the user-VM access functions, without
++ * relying on being able to access the VM directly.
++ */
++
++#include <linux/module.h>
++#include <linux/sched.h>
++#include <linux/errno.h>
++#include <linux/mm.h>
++#include <linux/highmem.h>
++#include <linux/pagemap.h>
++#include <linux/smp_lock.h>
++#include <linux/ptrace.h>
++#include <linux/interrupt.h>
++
++#include <asm/pgtable.h>
++#include <asm/uaccess.h>
++#include <asm/atomic_kmap.h>
++
++/*
++ * Get kernel address of the user page and pin it.
++ */
++static inline struct page *pin_page(unsigned long addr, int write)
++{
++      struct mm_struct *mm = current->mm ? : &init_mm;
++      struct page *page = NULL;
++      int ret;
++
++      spin_lock(&mm->page_table_lock);
++      /*
++       * Do a quick atomic lookup first - this is the fastpath.
++       */
++      page = follow_page(mm, addr, write);
++      if (likely(page != NULL)) {
++              if (!PageReserved(page))
++                      get_page(page);
++              spin_unlock(&mm->page_table_lock);
++              return page;
++      }
++
++      /*
++       * No luck - bad address or need to fault in the page:
++       */
++      spin_unlock(&mm->page_table_lock);
++
++      /*
++       * In the context of filemap_copy_from_user(), we are not allowed
++       * to sleep.  We must fail this usercopy attempt and allow
++       * filemap_copy_from_user() to recover: drop its atomic kmap and use
++       * a sleeping kmap instead.
++       */
++      if (in_atomic())
++              return NULL;
++
++      down_read(&mm->mmap_sem);
++      ret = get_user_pages(current, mm, addr, 1, write, 0, &page, NULL);
++      up_read(&mm->mmap_sem);
++      if (ret <= 0)
++              return NULL;
++      return page;
++}
++
++static inline void unpin_page(struct page *page)
++{
++      put_page(page);
++}
++
++/*
++ * Access another process' address space.
++ * Source/target buffer must be kernel space,
++ * Do not walk the page table directly, use get_user_pages
++ */
++static int rw_vm(unsigned long addr, void *buf, int len, int write)
++{
++      if (!len)
++              return 0;
++
++      /* ignore errors, just check how much was sucessfully transfered */
++      while (len) {
++              struct page *page = NULL;
++              int bytes, offset;
++              void *maddr;
++
++              page = pin_page(addr, write);
++              if (!page)
++                      break;
++
++              bytes = len;
++              offset = addr & (PAGE_SIZE-1);
++              if (bytes > PAGE_SIZE-offset)
++                      bytes = PAGE_SIZE-offset;
++
++              maddr = kmap_atomic(page, KM_USER_COPY);
++
++#define HANDLE_TYPE(type) \
++      case sizeof(type): *(type *)(maddr+offset) = *(type *)(buf); break;
++
++              if (write) {
++                      switch (bytes) {
++                      HANDLE_TYPE(char);
++                      HANDLE_TYPE(int);
++                      HANDLE_TYPE(long long);
++                      default:
++                              memcpy(maddr + offset, buf, bytes);
++                      }
++              } else {
++#undef HANDLE_TYPE
++#define HANDLE_TYPE(type) \
++      case sizeof(type): *(type *)(buf) = *(type *)(maddr+offset); break;
++                      switch (bytes) {
++                      HANDLE_TYPE(char);
++                      HANDLE_TYPE(int);
++                      HANDLE_TYPE(long long);
++                      default:
++                              memcpy(buf, maddr + offset, bytes);
++                      }
++#undef HANDLE_TYPE
++              }
++              kunmap_atomic(maddr, KM_USER_COPY);
++              unpin_page(page);
++              len -= bytes;
++              buf += bytes;
++              addr += bytes;
++      }
++
++      return len;
++}
++
++static int str_vm(unsigned long addr, void *buf0, int len, int copy)
++{
++      struct mm_struct *mm = current->mm ? : &init_mm;
++      struct page *page;
++      void *buf = buf0;
++
++      if (!len)
++              return len;
++
++      down_read(&mm->mmap_sem);
++      /* ignore errors, just check how much was sucessfully transfered */
++      while (len) {
++              int bytes, ret, offset, left, copied;
++              char *maddr;
++
++              ret = get_user_pages(current, mm, addr, 1, copy == 2, 0, &page, NULL);
++              if (ret <= 0) {
++                      up_read(&mm->mmap_sem);
++                      return -EFAULT;
++              }
++
++              bytes = len;
++              offset = addr & (PAGE_SIZE-1);
++              if (bytes > PAGE_SIZE-offset)
++                      bytes = PAGE_SIZE-offset;
++
++              maddr = kmap_atomic(page, KM_USER_COPY);
++              if (copy == 2) {
++                      memset(maddr + offset, 0, bytes);
++                      copied = bytes;
++                      left = 0;
++              } else if (copy == 1) {
++                      left = strncpy_count(buf, maddr + offset, bytes);
++                      copied = bytes - left;
++              } else {
++                      copied = strnlen(maddr + offset, bytes);
++                      left = bytes - copied;
++              }
++              BUG_ON(bytes < 0 || copied < 0);
++              kunmap_atomic(maddr, KM_USER_COPY);
++              page_cache_release(page);
++              len -= copied;
++              buf += copied;
++              addr += copied;
++              if (left)
++                      break;
++      }
++      up_read(&mm->mmap_sem);
++
++      return len;
++}
++
++/*
++ * Copies memory from userspace (ptr) into kernelspace (val).
++ *
++ * returns # of bytes not copied.
++ */
++int get_user_size(unsigned int size, void *val, const void *ptr)
++{
++      int ret;
++
++      if (unlikely(segment_eq(get_fs(), KERNEL_DS))) {
++              __direct_copy_from_user(val, ptr, size);
++              return 0;
++      }
++      ret = rw_vm((unsigned long)ptr, val, size, 0);
++      if (ret)
++              /*
++               * Zero the rest:
++               */
++              memset(val + size - ret, 0, ret);
++      return ret;
++}
++
++/*
++ * Copies memory from kernelspace (val) into userspace (ptr).
++ *
++ * returns # of bytes not copied.
++ */
++int put_user_size(unsigned int size, const void *val, void *ptr)
++{
++      if (unlikely(segment_eq(get_fs(), KERNEL_DS))) {
++              __direct_copy_to_user(ptr, val, size);
++              return 0;
++      }
++      return rw_vm((unsigned long)ptr, (void *)val, size, 1);
++}
++
++int copy_str_fromuser_size(unsigned int size, void *val, const void *ptr)
++{
++      int copied, left;
++
++      if (unlikely(segment_eq(get_fs(), KERNEL_DS))) {
++              left = strncpy_count(val, ptr, size);
++              copied = size - left;
++              BUG_ON(copied < 0);
++
++              return copied;
++      }
++      left = str_vm((unsigned long)ptr, val, size, 1);
++      if (left < 0)
++              return left;
++      copied = size - left;
++      BUG_ON(copied < 0);
++
++      return copied;
++}
++
++int strlen_fromuser_size(unsigned int size, const void *ptr)
++{
++      int copied, left;
++
++      if (unlikely(segment_eq(get_fs(), KERNEL_DS))) {
++              copied = strnlen(ptr, size) + 1;
++              BUG_ON(copied < 0);
++
++              return copied;
++      }
++      left = str_vm((unsigned long)ptr, NULL, size, 0);
++      if (left < 0)
++              return 0;
++      copied = size - left + 1;
++      BUG_ON(copied < 0);
++
++      return copied;
++}
++
++int zero_user_size(unsigned int size, void *ptr)
++{
++      int left;
++
++      if (unlikely(segment_eq(get_fs(), KERNEL_DS))) {
++              memset(ptr, 0, size);
++              return 0;
++      }
++      left = str_vm((unsigned long)ptr, NULL, size, 2);
++      if (left < 0)
++              return size;
++      return left;
++}
++
++EXPORT_SYMBOL(get_user_size);
++EXPORT_SYMBOL(put_user_size);
++EXPORT_SYMBOL(zero_user_size);
++EXPORT_SYMBOL(copy_str_fromuser_size);
++EXPORT_SYMBOL(strlen_fromuser_size);
++
+--- linux-2.6.0-test6/mm/vmalloc.c     2003-08-22 19:23:42.000000000 -0700
++++ 25/mm/vmalloc.c    2003-10-05 00:33:25.000000000 -0700
+@@ -135,23 +135,23 @@ static int map_area_pmd(pmd_t *pmd, unsi
+ void unmap_vm_area(struct vm_struct *area)
+ {
+-      unsigned long address = VMALLOC_VMADDR(area->addr);
++      unsigned long address = (unsigned long) area->addr;
+       unsigned long end = (address + area->size);
+       pgd_t *dir;
+       dir = pgd_offset_k(address);
+-      flush_cache_all();
++      flush_cache_vunmap(address, end);
+       do {
+               unmap_area_pmd(dir, address, end - address);
+               address = (address + PGDIR_SIZE) & PGDIR_MASK;
+               dir++;
+       } while (address && (address < end));
+-      flush_tlb_kernel_range(VMALLOC_VMADDR(area->addr), end);
++      flush_tlb_kernel_range((unsigned long) area->addr, end);
+ }
+ int map_vm_area(struct vm_struct *area, pgprot_t prot, struct page ***pages)
+ {
+-      unsigned long address = VMALLOC_VMADDR(area->addr);
++      unsigned long address = (unsigned long) area->addr;
+       unsigned long end = address + (area->size-PAGE_SIZE);
+       pgd_t *dir;
+       int err = 0;
+@@ -174,7 +174,7 @@ int map_vm_area(struct vm_struct *area, 
+       } while (address && (address < end));
+       spin_unlock(&init_mm.page_table_lock);
+-      flush_cache_all();
++      flush_cache_vmap((unsigned long) area->addr, end);
+       return err;
+ }
+--- linux-2.6.0-test6/net/802/fddi.c   2003-06-14 12:18:30.000000000 -0700
++++ 25/net/802/fddi.c  2003-10-05 00:33:25.000000000 -0700
+@@ -27,6 +27,7 @@
+  */
+  
+ #include <linux/config.h>
++#include <linux/module.h>
+ #include <asm/system.h>
+ #include <linux/types.h>
+ #include <linux/kernel.h>
+@@ -163,3 +164,5 @@ unsigned short fddi_type_trans(struct sk
+       return(type);
+ }
++
++EXPORT_SYMBOL(fddi_type_trans);
+--- linux-2.6.0-test6/net/802/hippi.c  2003-06-14 12:18:21.000000000 -0700
++++ 25/net/802/hippi.c 2003-10-05 00:33:25.000000000 -0700
+@@ -20,6 +20,7 @@
+  *            2 of the License, or (at your option) any later version.
+  */
++#include <linux/module.h>
+ #include <linux/types.h>
+ #include <linux/kernel.h>
+ #include <linux/sched.h>
+@@ -151,3 +152,5 @@ unsigned short hippi_type_trans(struct s
+       return hip->snap.ethertype;
+ }
++
++EXPORT_SYMBOL(hippi_type_trans);
+--- linux-2.6.0-test6/net/802/p8023.c  2003-06-14 12:17:57.000000000 -0700
++++ 25/net/802/p8023.c 2003-10-05 00:33:25.000000000 -0700
+@@ -12,22 +12,24 @@
+  *    running raw 802.3 on different devices. Thankfully nobody else
+  *    has done anything like the old IPX.
+  */
+- 
++
++#include <linux/in.h>
++#include <linux/mm.h>
++#include <linux/module.h>
+ #include <linux/netdevice.h>
+ #include <linux/skbuff.h>
++
+ #include <net/datalink.h>
+-#include <linux/mm.h>
+-#include <linux/in.h>
+ /*
+  *    Place an 802.3 header on a packet. The driver will do the mac
+  *    addresses, we just need to give it the buffer length.
+  */
+- 
+-static int p8023_request(struct datalink_proto *dl, 
+-              struct sk_buff *skb, unsigned char *dest_node)
++static int p8023_request(struct datalink_proto *dl,
++                       struct sk_buff *skb, unsigned char *dest_node)
+ {
+-      struct net_device       *dev = skb->dev;
++      struct net_device *dev = skb->dev;
++
+       dev->hard_header(skb, dev, ETH_P_802_3, dest_node, NULL, skb->len);
+       return dev_queue_xmit(skb);
+ }
+@@ -35,16 +37,13 @@ static int p8023_request(struct datalink
+ /*
+  *    Create an 802.3 client. Note there can be only one 802.3 client
+  */
+- 
+ struct datalink_proto *make_8023_client(void)
+ {
+-      struct datalink_proto   *proto;
++      struct datalink_proto *proto = kmalloc(sizeof(*proto), GFP_ATOMIC);
+-      proto = (struct datalink_proto *) kmalloc(sizeof(*proto), GFP_ATOMIC);
+-      if (proto != NULL) 
+-      {
++      if (proto) {
+               proto->header_length = 0;
+-              proto->request = p8023_request;
++              proto->request       = p8023_request;
+       }
+       return proto;
+ }
+@@ -52,10 +51,11 @@ struct datalink_proto *make_8023_client(
+ /*
+  *    Destroy the 802.3 client.
+  */
+- 
+ void destroy_8023_client(struct datalink_proto *dl)
+ {
+       if (dl)
+               kfree(dl);
+ }
++EXPORT_SYMBOL(destroy_8023_client);
++EXPORT_SYMBOL(make_8023_client);
+--- linux-2.6.0-test6/net/802/tr.c     2003-09-27 18:57:47.000000000 -0700
++++ 25/net/802/tr.c    2003-10-05 00:33:25.000000000 -0700
+@@ -18,6 +18,7 @@
+ #include <asm/uaccess.h>
+ #include <asm/system.h>
+ #include <linux/config.h>
++#include <linux/module.h>
+ #include <linux/types.h>
+ #include <linux/kernel.h>
+ #include <linux/jiffies.h>
+@@ -600,3 +601,6 @@ static int __init rif_init(void)
+ }
+ module_init(rif_init);
++
++EXPORT_SYMBOL(tr_source_route);
++EXPORT_SYMBOL(tr_type_trans);
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ 25/net/bridge/netfilter/ebt_limit.c        2003-10-05 00:33:25.000000000 -0700
+@@ -0,0 +1,104 @@
++/*
++ *  ebt_limit
++ *
++ *    Authors:
++ *    Tom Marshall <tommy@home.tig-grr.com>
++ *
++ *    Mostly copied from netfilter's ipt_limit.c, see that file for
++ *    more explanation
++ *
++ *  September, 2003
++ *
++ */
++
++#include <linux/netfilter_bridge/ebtables.h>
++#include <linux/netfilter_bridge/ebt_limit.h>
++#include <linux/module.h>
++
++#include <linux/netdevice.h>
++#include <linux/spinlock.h>
++
++static spinlock_t limit_lock = SPIN_LOCK_UNLOCKED;
++
++#define CREDITS_PER_JIFFY 128
++
++static int ebt_limit_match(const struct sk_buff *skb,
++   const struct net_device *in, const struct net_device *out,
++   const void *data, unsigned int datalen)
++{
++      struct ebt_limit_info *info = (struct ebt_limit_info *)data;
++      unsigned long now = jiffies;
++
++      spin_lock_bh(&limit_lock);
++      info->credit += (now - xchg(&info->prev, now)) * CREDITS_PER_JIFFY;
++      if (info->credit > info->credit_cap)
++              info->credit = info->credit_cap;
++
++      if (info->credit >= info->cost) {
++              /* We're not limited. */
++              info->credit -= info->cost;
++              spin_unlock_bh(&limit_lock);
++              return EBT_MATCH;
++      }
++
++      spin_unlock_bh(&limit_lock);
++      return EBT_NOMATCH;
++}
++
++/* Precision saver. */
++static u_int32_t
++user2credits(u_int32_t user)
++{
++      /* If multiplying would overflow... */
++      if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY))
++              /* Divide first. */
++              return (user / EBT_LIMIT_SCALE) * HZ * CREDITS_PER_JIFFY;
++
++      return (user * HZ * CREDITS_PER_JIFFY) / EBT_LIMIT_SCALE;
++}
++
++static int ebt_limit_check(const char *tablename, unsigned int hookmask,
++   const struct ebt_entry *e, void *data, unsigned int datalen)
++{
++      struct ebt_limit_info *info = (struct ebt_limit_info *)data;
++
++      if (datalen != EBT_ALIGN(sizeof(struct ebt_limit_info)))
++              return -EINVAL;
++
++      /* Check for overflow. */
++      if (info->burst == 0 ||
++          user2credits(info->avg * info->burst) < user2credits(info->avg)) {
++              printk("Overflow in ebt_limit: %u/%u\n",
++                      info->avg, info->burst);
++              return -EINVAL;
++      }
++
++      /* User avg in seconds * EBT_LIMIT_SCALE: convert to jiffies * 128. */
++      info->prev = jiffies;
++      info->credit = user2credits(info->avg * info->burst);
++      info->credit_cap = user2credits(info->avg * info->burst);
++      info->cost = user2credits(info->avg);
++      return 0;
++}
++
++static struct ebt_match ebt_limit_reg =
++{
++      .name           = EBT_LIMIT_MATCH,
++      .match          = ebt_limit_match,
++      .check          = ebt_limit_check,
++      .me             = THIS_MODULE,
++};
++
++static int __init init(void)
++{
++      return ebt_register_match(&ebt_limit_reg);
++}
++
++static void __exit fini(void)
++{
++      ebt_unregister_match(&ebt_limit_reg);
++}
++
++module_init(init);
++module_exit(fini);
++MODULE_LICENSE("GPL");
+--- linux-2.6.0-test6/net/bridge/netfilter/ebt_vlan.c  2003-07-27 12:14:40.000000000 -0700
++++ 25/net/bridge/netfilter/ebt_vlan.c 2003-10-05 00:33:25.000000000 -0700
+@@ -48,7 +48,7 @@ ebt_filter_vlan(const struct sk_buff *sk
+               const void *data, unsigned int datalen)
+ {
+       struct ebt_vlan_info *info = (struct ebt_vlan_info *) data;
+-      struct vlan_ethhdr frame;
++      struct vlan_hdr frame;
+       unsigned short TCI;     /* Whole TCI, given from parsed frame */
+       unsigned short id;      /* VLAN ID, given from frame TCI */
+--- linux-2.6.0-test6/net/bridge/netfilter/Kconfig     2003-09-27 18:57:47.000000000 -0700
++++ 25/net/bridge/netfilter/Kconfig    2003-10-05 00:33:25.000000000 -0700
+@@ -73,6 +73,17 @@ config BRIDGE_EBT_IP
+         To compile it as a module, choose M here.  If unsure, say N.
++config BRIDGE_EBT_LIMIT
++      tristate "ebt: limit match support"
++      depends on BRIDGE_NF_EBTABLES
++      help
++        This option adds the limit match, which allows you to control
++        the rate at which a rule can be matched. This match is the
++        equivalent of the iptables limit match.
++
++        If you want to compile it as a module, say M here and read
++        <file:Documentation/modules.txt>.  If unsure, say `N'.
++
+ config BRIDGE_EBT_MARK
+       tristate "ebt: mark filter support"
+       depends on BRIDGE_NF_EBTABLES
+--- linux-2.6.0-test6/net/bridge/netfilter/Makefile    2003-09-08 13:58:59.000000000 -0700
++++ 25/net/bridge/netfilter/Makefile   2003-10-05 00:33:25.000000000 -0700
+@@ -13,6 +13,7 @@ obj-$(CONFIG_BRIDGE_EBT_T_NAT) += ebtabl
+ obj-$(CONFIG_BRIDGE_EBT_802_3) += ebt_802_3.o
+ obj-$(CONFIG_BRIDGE_EBT_ARP) += ebt_arp.o
+ obj-$(CONFIG_BRIDGE_EBT_IP) += ebt_ip.o
++obj-$(CONFIG_BRIDGE_EBT_LIMIT) += ebt_limit.o
+ obj-$(CONFIG_BRIDGE_EBT_MARK) += ebt_mark_m.o
+ obj-$(CONFIG_BRIDGE_EBT_PKTTYPE) += ebt_pkttype.o
+ obj-$(CONFIG_BRIDGE_EBT_STP) += ebt_stp.o
+--- linux-2.6.0-test6/net/core/datagram.c      2003-06-14 12:18:24.000000000 -0700
++++ 25/net/core/datagram.c     2003-10-05 00:33:25.000000000 -0700
+@@ -33,6 +33,7 @@
+  *
+  */
++#include <linux/module.h>
+ #include <linux/types.h>
+ #include <linux/kernel.h>
+ #include <asm/uaccess.h>
+@@ -485,3 +486,10 @@ unsigned int datagram_poll(struct file *
+       return mask;
+ }
++
++EXPORT_SYMBOL(datagram_poll);
++EXPORT_SYMBOL(skb_copy_and_csum_datagram_iovec);
++EXPORT_SYMBOL(skb_copy_datagram);
++EXPORT_SYMBOL(skb_copy_datagram_iovec);
++EXPORT_SYMBOL(skb_free_datagram);
++EXPORT_SYMBOL(skb_recv_datagram);
+--- linux-2.6.0-test6/net/core/dev.c   2003-09-27 18:57:47.000000000 -0700
++++ 25/net/core/dev.c  2003-10-05 00:36:10.000000000 -0700
+@@ -111,6 +111,10 @@
+ #endif        /* CONFIG_NET_RADIO */
+ #include <asm/current.h>
++#ifdef CONFIG_KGDB
++#include <asm/kgdb.h>
++#endif
++
+ /* This define, if set, will randomly drop a packet when congestion
+  * is more than moderate.  It helps fairness in the multi-interface
+  * case when one of them is a hog, but it kills performance for the
+@@ -915,6 +919,8 @@ int unregister_netdevice_notifier(struct
+ /**
+  *    call_netdevice_notifiers - call all network notifier blocks
++ *      @val: value passed unmodified to notifier function
++ *      @v:   pointer passed unmodified to notifier function
+  *
+  *    Call all network notifier blocks.  Parameters and return value
+  *    are as for notifier_call_chain().
+@@ -1322,7 +1328,6 @@ static void sample_queue(unsigned long d
+ }
+ #endif
+-
+ /**
+  *    netif_rx        -       post buffer to the network code
+  *    @skb: buffer to post
+@@ -1347,6 +1352,21 @@ int netif_rx(struct sk_buff *skb)
+       struct softnet_data *queue;
+       unsigned long flags;
++#ifdef CONFIG_KGDB
++      /* See if kgdb_eth wants this packet */
++      if (!kgdb_net_interrupt(skb)) {
++              /* No.. if we're 'trapped' then junk it */
++              if (kgdb_eth_is_trapped()) {
++                      kfree_skb(skb);
++                      return NET_RX_DROP;
++              }
++      } else {
++              /* kgdb_eth ate the packet... drop it silently */
++              kfree_skb(skb);
++              return NET_RX_DROP;
++      }
++#endif
++
+       if (!skb->stamp.tv_sec)
+               do_gettimeofday(&skb->stamp);
+@@ -1488,6 +1508,18 @@ static void net_tx_action(struct softirq
+       }
+ }
++static __inline__ int deliver_skb(struct sk_buff *skb,
++                                struct packet_type *pt_prev, int last)
++{
++      if (unlikely(!pt_prev->data))
++              return deliver_to_old_ones(pt_prev, skb, last);
++      else {
++              atomic_inc(&skb->users);
++              return pt_prev->func(skb, skb->dev, pt_prev);
++      }
++}
++
++
+ #if defined(CONFIG_BRIDGE) || defined (CONFIG_BRIDGE_MODULE)
+ int (*br_handle_frame_hook)(struct sk_buff *skb);
+@@ -1495,15 +1527,8 @@ static __inline__ int handle_bridge(stru
+                                    struct packet_type *pt_prev)
+ {
+       int ret = NET_RX_DROP;
+-
+-      if (pt_prev) {
+-              if (!pt_prev->data)
+-                      ret = deliver_to_old_ones(pt_prev, skb, 0);
+-              else {
+-                      atomic_inc(&skb->users);
+-                      ret = pt_prev->func(skb, skb->dev, pt_prev);
+-              }
+-      }
++      if (pt_prev)
++              ret = deliver_skb(skb, pt_prev, 0);
+       return ret;
+ }
+@@ -1551,16 +1576,8 @@ int netif_receive_skb(struct sk_buff *sk
+       rcu_read_lock();
+       list_for_each_entry_rcu(ptype, &ptype_all, list) {
+               if (!ptype->dev || ptype->dev == skb->dev) {
+-                      if (pt_prev) {
+-                              if (!pt_prev->data) {
+-                                      ret = deliver_to_old_ones(pt_prev,
+-                                                                skb, 0);
+-                              } else {
+-                                      atomic_inc(&skb->users);
+-                                      ret = pt_prev->func(skb, skb->dev,
+-                                                          pt_prev);
+-                              }
+-                      }
++                      if (pt_prev) 
++                              ret = deliver_skb(skb, pt_prev, 0);
+                       pt_prev = ptype;
+               }
+       }
+@@ -1573,16 +1590,8 @@ int netif_receive_skb(struct sk_buff *sk
+       list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type)&15], list) {
+               if (ptype->type == type &&
+                   (!ptype->dev || ptype->dev == skb->dev)) {
+-                      if (pt_prev) {
+-                              if (!pt_prev->data) {
+-                                      ret = deliver_to_old_ones(pt_prev,
+-                                                                skb, 0);
+-                              } else {
+-                                      atomic_inc(&skb->users);
+-                                      ret = pt_prev->func(skb, skb->dev,
+-                                                          pt_prev);
+-                              }
+-                      }
++                      if (pt_prev) 
++                              ret = deliver_skb(skb, pt_prev, 0);
+                       pt_prev = ptype;
+               }
+       }
+@@ -1637,8 +1646,8 @@ static int process_backlog(struct net_de
+ #ifdef CONFIG_NET_HW_FLOWCONTROL
+               if (queue->throttle &&
+                   queue->input_pkt_queue.qlen < no_cong_thresh ) {
++                      queue->throttle = 0;
+                       if (atomic_dec_and_test(&netdev_dropping)) {
+-                              queue->throttle = 0;
+                               netdev_wakeup();
+                               break;
+                       }
+@@ -3036,3 +3045,63 @@ out:
+ }
+ subsys_initcall(net_dev_init);
++
++EXPORT_SYMBOL(__dev_get);
++EXPORT_SYMBOL(__dev_get_by_flags);
++EXPORT_SYMBOL(__dev_get_by_index);
++EXPORT_SYMBOL(__dev_get_by_name);
++EXPORT_SYMBOL(__dev_remove_pack);
++EXPORT_SYMBOL(__skb_linearize);
++EXPORT_SYMBOL(call_netdevice_notifiers);
++EXPORT_SYMBOL(dev_add_pack);
++EXPORT_SYMBOL(dev_alloc);
++EXPORT_SYMBOL(dev_alloc_name);
++EXPORT_SYMBOL(dev_close);
++EXPORT_SYMBOL(dev_get_by_flags);
++EXPORT_SYMBOL(dev_get_by_index);
++EXPORT_SYMBOL(dev_get_by_name);
++EXPORT_SYMBOL(dev_getbyhwaddr);
++EXPORT_SYMBOL(dev_ioctl);
++EXPORT_SYMBOL(dev_new_index);
++EXPORT_SYMBOL(dev_open);
++EXPORT_SYMBOL(dev_queue_xmit);
++EXPORT_SYMBOL(dev_queue_xmit_nit);
++EXPORT_SYMBOL(dev_remove_pack);
++EXPORT_SYMBOL(dev_set_allmulti);
++EXPORT_SYMBOL(dev_set_promiscuity);
++EXPORT_SYMBOL(free_netdev);
++EXPORT_SYMBOL(netdev_boot_setup_check);
++EXPORT_SYMBOL(netdev_set_master);
++EXPORT_SYMBOL(netdev_state_change);
++EXPORT_SYMBOL(netif_receive_skb);
++EXPORT_SYMBOL(netif_rx);
++EXPORT_SYMBOL(register_gifconf);
++EXPORT_SYMBOL(register_netdevice);
++EXPORT_SYMBOL(register_netdevice_notifier);
++EXPORT_SYMBOL(skb_checksum_help);
++EXPORT_SYMBOL(synchronize_net);
++EXPORT_SYMBOL(unregister_netdevice);
++EXPORT_SYMBOL(unregister_netdevice_notifier);
++
++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
++EXPORT_SYMBOL(br_handle_frame_hook);
++#endif
++/* for 801q VLAN support */
++#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
++EXPORT_SYMBOL(dev_change_flags);
++#endif
++#ifdef CONFIG_KMOD
++EXPORT_SYMBOL(dev_load);
++#endif
++#ifdef CONFIG_NET_HW_FLOWCONTROL
++EXPORT_SYMBOL(netdev_dropping);
++EXPORT_SYMBOL(netdev_fc_xoff);
++EXPORT_SYMBOL(netdev_register_fc);
++EXPORT_SYMBOL(netdev_unregister_fc);
++#endif
++#ifdef CONFIG_NET_FASTROUTE
++EXPORT_SYMBOL(netdev_fastroute);
++EXPORT_SYMBOL(netdev_fastroute_obstacles);
++#endif
++
++EXPORT_PER_CPU_SYMBOL(softnet_data);
+--- linux-2.6.0-test6/net/core/dev_mcast.c     2003-06-14 12:18:06.000000000 -0700
++++ 25/net/core/dev_mcast.c    2003-10-05 00:33:25.000000000 -0700
+@@ -22,6 +22,7 @@
+  */
+ #include <linux/config.h> 
++#include <linux/module.h> 
+ #include <asm/uaccess.h>
+ #include <asm/system.h>
+ #include <asm/bitops.h>
+@@ -273,3 +274,6 @@ void __init dev_mcast_init(void)
+ #endif
+ }
++EXPORT_SYMBOL(dev_mc_add);
++EXPORT_SYMBOL(dev_mc_delete);
++EXPORT_SYMBOL(dev_mc_upload);
+--- linux-2.6.0-test6/net/core/dst.c   2003-06-14 12:18:23.000000000 -0700
++++ 25/net/core/dst.c  2003-10-05 00:33:25.000000000 -0700
+@@ -6,15 +6,16 @@
+  */
+ #include <linux/bitops.h>
+-#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/init.h>
+ #include <linux/kernel.h>
+-#include <linux/sched.h>
+ #include <linux/mm.h>
+-#include <linux/string.h>
+-#include <linux/errno.h>
++#include <linux/module.h>
+ #include <linux/netdevice.h>
++#include <linux/sched.h>
+ #include <linux/skbuff.h>
+-#include <linux/init.h>
++#include <linux/string.h>
++#include <linux/types.h>
+ #include <net/dst.h>
+@@ -257,3 +258,7 @@ void __init dst_init(void)
+ {
+       register_netdevice_notifier(&dst_dev_notifier);
+ }
++
++EXPORT_SYMBOL(__dst_free);
++EXPORT_SYMBOL(dst_alloc);
++EXPORT_SYMBOL(dst_destroy);
+--- linux-2.6.0-test6/net/core/dv.c    2003-09-08 13:58:59.000000000 -0700
++++ 25/net/core/dv.c   2003-10-05 00:33:25.000000000 -0700
+@@ -10,6 +10,7 @@
+  *            Dave Miller:    improvement on the code (correctness, performance and source files)
+  *
+  */
++#include <linux/module.h>
+ #include <linux/types.h>
+ #include <linux/kernel.h>
+ #include <linux/sched.h>
+@@ -237,7 +238,7 @@ int divert_ioctl(unsigned int cmd, struc
+               default:
+                       return -EINVAL;
+-              };
++              }
+               break;
+@@ -281,7 +282,7 @@ int divert_ioctl(unsigned int cmd, struc
+                       default:
+                               return -EINVAL;
+-                      };
++                      }
+                       break;
+@@ -301,7 +302,7 @@ int divert_ioctl(unsigned int cmd, struc
+                       default:
+                               return -EINVAL;
+-                      };
++                      }
+                       break;
+@@ -321,7 +322,7 @@ int divert_ioctl(unsigned int cmd, struc
+                       default:
+                               return -EINVAL;
+-                      };
++                      }
+                       break;
+@@ -337,7 +338,7 @@ int divert_ioctl(unsigned int cmd, struc
+                       default:
+                               return -EINVAL;
+-                      };
++                      }
+                       break;
+@@ -353,7 +354,7 @@ int divert_ioctl(unsigned int cmd, struc
+                       default:
+                               return -EINVAL;
+-                      };
++                      }
+                       break;
+@@ -373,7 +374,7 @@ int divert_ioctl(unsigned int cmd, struc
+                       default:
+                               return -EINVAL;
+-                      };
++                      }
+                       break;
+@@ -389,7 +390,7 @@ int divert_ioctl(unsigned int cmd, struc
+                       default:
+                               return -EINVAL;
+-                      };
++                      }
+                       break;
+@@ -405,7 +406,7 @@ int divert_ioctl(unsigned int cmd, struc
+                       default:
+                               return -EINVAL;
+-                      };
++                      }
+                       break;
+@@ -425,19 +426,19 @@ int divert_ioctl(unsigned int cmd, struc
+                       default:
+                               return -EINVAL;
+-                      };
++                      }
+                       break;
+               default:
+                       return -EINVAL;
+-              };
++              }
+               break;
+       default:
+               return -EINVAL;
+-      };
++      }
+       return 0;
+ }
+@@ -550,8 +551,8 @@ void divert_frame(struct sk_buff *skb)
+                       }
+               }
+               break;
+-      };
+-
+-      return;
++      }
+ }
++EXPORT_SYMBOL(alloc_divert_blk);
++EXPORT_SYMBOL(free_divert_blk);
+--- linux-2.6.0-test6/net/core/ethtool.c       2003-09-08 13:58:59.000000000 -0700
++++ 25/net/core/ethtool.c      2003-10-05 00:33:25.000000000 -0700
+@@ -9,6 +9,7 @@
+  * It's GPL, stupid.
+  */
++#include <linux/module.h>
+ #include <linux/types.h>
+ #include <linux/errno.h>
+ #include <linux/ethtool.h>
+@@ -727,3 +728,11 @@ int dev_ethtool(struct ifreq *ifr)
+               return dev->do_ioctl(dev, ifr, SIOCETHTOOL);
+       return -EOPNOTSUPP;
+ }
++
++EXPORT_SYMBOL(ethtool_op_get_link);
++EXPORT_SYMBOL(ethtool_op_get_sg);
++EXPORT_SYMBOL(ethtool_op_get_tso);
++EXPORT_SYMBOL(ethtool_op_get_tx_csum);
++EXPORT_SYMBOL(ethtool_op_set_sg);
++EXPORT_SYMBOL(ethtool_op_set_tso);
++EXPORT_SYMBOL(ethtool_op_set_tx_csum);
+--- linux-2.6.0-test6/net/core/filter.c        2003-07-27 12:14:40.000000000 -0700
++++ 25/net/core/filter.c       2003-10-05 00:33:25.000000000 -0700
+@@ -424,3 +424,6 @@ int sk_attach_filter(struct sock_fprog *
+               sk_filter_release(sk, fp);
+       return err;
+ }
++
++EXPORT_SYMBOL(sk_chk_filter);
++EXPORT_SYMBOL(sk_run_filter);
+--- linux-2.6.0-test6/net/core/flow.c  2003-06-22 12:04:45.000000000 -0700
++++ 25/net/core/flow.c 2003-10-05 00:33:25.000000000 -0700
+@@ -5,6 +5,7 @@
+  */
+ #include <linux/kernel.h>
++#include <linux/module.h>
+ #include <linux/list.h>
+ #include <linux/jhash.h>
+ #include <linux/interrupt.h>
+@@ -401,3 +402,6 @@ static int __init flow_cache_init(void)
+ }
+ module_init(flow_cache_init);
++
++EXPORT_SYMBOL(flow_cache_genid);
++EXPORT_SYMBOL(flow_cache_lookup);
+--- linux-2.6.0-test6/net/core/iovec.c 2003-06-14 12:18:52.000000000 -0700
++++ 25/net/core/iovec.c        2003-10-05 00:33:25.000000000 -0700
+@@ -16,8 +16,8 @@
+  *            Andi Kleen      :       Fix csum*fromiovecend for IPv6.
+  */
+-
+ #include <linux/errno.h>
++#include <linux/module.h>
+ #include <linux/sched.h>
+ #include <linux/kernel.h>
+ #include <linux/mm.h>
+@@ -254,3 +254,9 @@ out_fault:
+       err = -EFAULT;
+       goto out;
+ }
++
++EXPORT_SYMBOL(csum_partial_copy_fromiovecend);
++EXPORT_SYMBOL(memcpy_fromiovec);
++EXPORT_SYMBOL(memcpy_fromiovecend);
++EXPORT_SYMBOL(memcpy_toiovec);
++EXPORT_SYMBOL(memcpy_tokerneliovec);
+--- linux-2.6.0-test6/net/core/link_watch.c    2003-09-08 13:58:59.000000000 -0700
++++ 25/net/core/link_watch.c   2003-10-05 00:33:25.000000000 -0700
+@@ -1,5 +1,5 @@
+ /*
+- * Linux network device link state notifaction
++ * Linux network device link state notification
+  *
+  * Author:
+  *     Stefan Rompf <sux@loplof.de>
+@@ -12,6 +12,7 @@
+  */
+ #include <linux/config.h>
++#include <linux/module.h>
+ #include <linux/netdevice.h>
+ #include <linux/if.h>
+ #include <linux/rtnetlink.h>
+@@ -132,3 +133,4 @@ void linkwatch_fire_event(struct net_dev
+       }
+ }
++EXPORT_SYMBOL(linkwatch_fire_event);
+--- linux-2.6.0-test6/net/core/neighbour.c     2003-08-22 19:23:42.000000000 -0700
++++ 25/net/core/neighbour.c    2003-10-05 00:33:25.000000000 -0700
+@@ -17,6 +17,7 @@
+ #include <linux/config.h>
+ #include <linux/types.h>
+ #include <linux/kernel.h>
++#include <linux/module.h>
+ #include <linux/socket.h>
+ #include <linux/sched.h>
+ #include <linux/netdevice.h>
+@@ -1683,3 +1684,34 @@ void neigh_sysctl_unregister(struct neig
+ }
+ #endif        /* CONFIG_SYSCTL */
++
++EXPORT_SYMBOL(__neigh_event_send);
++EXPORT_SYMBOL(neigh_add);
++EXPORT_SYMBOL(neigh_changeaddr);
++EXPORT_SYMBOL(neigh_compat_output);
++EXPORT_SYMBOL(neigh_connected_output);
++EXPORT_SYMBOL(neigh_create);
++EXPORT_SYMBOL(neigh_delete);
++EXPORT_SYMBOL(neigh_destroy);
++EXPORT_SYMBOL(neigh_dump_info);
++EXPORT_SYMBOL(neigh_event_ns);
++EXPORT_SYMBOL(neigh_ifdown);
++EXPORT_SYMBOL(neigh_lookup);
++EXPORT_SYMBOL(neigh_parms_alloc);
++EXPORT_SYMBOL(neigh_parms_release);
++EXPORT_SYMBOL(neigh_rand_reach_time);
++EXPORT_SYMBOL(neigh_resolve_output);
++EXPORT_SYMBOL(neigh_table_clear);
++EXPORT_SYMBOL(neigh_table_init);
++EXPORT_SYMBOL(neigh_update);
++EXPORT_SYMBOL(neigh_update_hhs);
++EXPORT_SYMBOL(pneigh_enqueue);
++EXPORT_SYMBOL(pneigh_lookup);
++
++#ifdef CONFIG_ARPD
++EXPORT_SYMBOL(neigh_app_ns);
++#endif
++#ifdef CONFIG_SYSCTL
++EXPORT_SYMBOL(neigh_sysctl_register);
++EXPORT_SYMBOL(neigh_sysctl_unregister);
++#endif
+--- linux-2.6.0-test6/net/core/netfilter.c     2003-09-08 13:58:59.000000000 -0700
++++ 25/net/core/netfilter.c    2003-10-05 00:33:25.000000000 -0700
+@@ -759,3 +759,17 @@ void __init netfilter_init(void)
+                       INIT_LIST_HEAD(&nf_hooks[i][h]);
+       }
+ }
++
++EXPORT_SYMBOL(ip_ct_attach);
++EXPORT_SYMBOL(ip_route_me_harder);
++EXPORT_SYMBOL(nf_getsockopt);
++EXPORT_SYMBOL(nf_hook_slow);
++EXPORT_SYMBOL(nf_hooks);
++EXPORT_SYMBOL(nf_register_hook);
++EXPORT_SYMBOL(nf_register_queue_handler);
++EXPORT_SYMBOL(nf_register_sockopt);
++EXPORT_SYMBOL(nf_reinject);
++EXPORT_SYMBOL(nf_setsockopt);
++EXPORT_SYMBOL(nf_unregister_hook);
++EXPORT_SYMBOL(nf_unregister_queue_handler);
++EXPORT_SYMBOL(nf_unregister_sockopt);
+--- linux-2.6.0-test6/net/core/rtnetlink.c     2003-09-08 13:58:59.000000000 -0700
++++ 25/net/core/rtnetlink.c    2003-10-05 00:33:25.000000000 -0700
+@@ -18,6 +18,7 @@
+ #include <linux/config.h>
+ #include <linux/errno.h>
++#include <linux/module.h>
+ #include <linux/types.h>
+ #include <linux/socket.h>
+ #include <linux/kernel.h>
+@@ -556,7 +557,6 @@ struct notifier_block rtnetlink_dev_noti
+       .notifier_call  = rtnetlink_event,
+ };
+-
+ void __init rtnetlink_init(void)
+ {
+       rtnl = netlink_kernel_create(NETLINK_ROUTE, rtnetlink_rcv);
+@@ -567,3 +567,13 @@ void __init rtnetlink_init(void)
+       rtnetlink_links[PF_UNSPEC] = link_rtnetlink_table;
+       rtnetlink_links[PF_PACKET] = link_rtnetlink_table;
+ }
++
++EXPORT_SYMBOL(__rta_fill);
++EXPORT_SYMBOL(rtattr_parse);
++EXPORT_SYMBOL(rtnetlink_dump_ifinfo);
++EXPORT_SYMBOL(rtnetlink_links);
++EXPORT_SYMBOL(rtnetlink_put_metrics);
++EXPORT_SYMBOL(rtnl);
++EXPORT_SYMBOL(rtnl_lock);
++EXPORT_SYMBOL(rtnl_sem);
++EXPORT_SYMBOL(rtnl_unlock);
+--- linux-2.6.0-test6/net/core/scm.c   2003-09-08 13:58:59.000000000 -0700
++++ 25/net/core/scm.c  2003-10-05 00:33:25.000000000 -0700
+@@ -9,6 +9,7 @@
+  *            2 of the License, or (at your option) any later version.
+  */
++#include <linux/module.h>
+ #include <linux/signal.h>
+ #include <linux/errno.h>
+ #include <linux/sched.h>
+@@ -282,3 +283,9 @@ struct scm_fp_list *scm_fp_dup(struct sc
+       }
+       return new_fpl;
+ }
++
++EXPORT_SYMBOL(__scm_destroy);
++EXPORT_SYMBOL(__scm_send);
++EXPORT_SYMBOL(put_cmsg);
++EXPORT_SYMBOL(scm_detach_fds);
++EXPORT_SYMBOL(scm_fp_dup);
+--- linux-2.6.0-test6/net/core/skbuff.c        2003-09-08 13:58:59.000000000 -0700
++++ 25/net/core/skbuff.c       2003-10-05 00:33:25.000000000 -0700
+@@ -39,6 +39,7 @@
+  */
+ #include <linux/config.h>
++#include <linux/module.h>
+ #include <linux/types.h>
+ #include <linux/kernel.h>
+ #include <linux/sched.h>
+@@ -1103,3 +1104,22 @@ void __init skb_init(void)
+       if (!skbuff_head_cache)
+               panic("cannot create skbuff cache");
+ }
++
++EXPORT_SYMBOL(___pskb_trim);
++EXPORT_SYMBOL(__kfree_skb);
++EXPORT_SYMBOL(__pskb_pull_tail);
++EXPORT_SYMBOL(alloc_skb);
++EXPORT_SYMBOL(pskb_copy);
++EXPORT_SYMBOL(pskb_expand_head);
++EXPORT_SYMBOL(skb_checksum);
++EXPORT_SYMBOL(skb_clone);
++EXPORT_SYMBOL(skb_clone_fraglist);
++EXPORT_SYMBOL(skb_copy);
++EXPORT_SYMBOL(skb_copy_and_csum_bits);
++EXPORT_SYMBOL(skb_copy_and_csum_dev);
++EXPORT_SYMBOL(skb_copy_bits);
++EXPORT_SYMBOL(skb_copy_expand);
++EXPORT_SYMBOL(skb_over_panic);
++EXPORT_SYMBOL(skb_pad);
++EXPORT_SYMBOL(skb_realloc_headroom);
++EXPORT_SYMBOL(skb_under_panic);
+--- linux-2.6.0-test6/net/core/sock.c  2003-06-14 12:18:29.000000000 -0700
++++ 25/net/core/sock.c 2003-10-05 00:33:25.000000000 -0700
+@@ -98,6 +98,7 @@
+ #include <linux/in.h>
+ #include <linux/kernel.h>
+ #include <linux/major.h>
++#include <linux/module.h>
+ #include <linux/sched.h>
+ #include <linux/timer.h>
+ #include <linux/string.h>
+@@ -1111,3 +1112,40 @@ void sock_init_data(struct socket *sock,
+       atomic_set(&sk->sk_refcnt, 1);
+ }
++
++EXPORT_SYMBOL(__lock_sock);
++EXPORT_SYMBOL(__release_sock);
++EXPORT_SYMBOL(sk_alloc);
++EXPORT_SYMBOL(sk_free);
++EXPORT_SYMBOL(sk_send_sigurg);
++EXPORT_SYMBOL(sock_alloc_send_pskb);
++EXPORT_SYMBOL(sock_alloc_send_skb);
++EXPORT_SYMBOL(sock_getsockopt);
++EXPORT_SYMBOL(sock_init_data);
++EXPORT_SYMBOL(sock_kfree_s);
++EXPORT_SYMBOL(sock_kmalloc);
++EXPORT_SYMBOL(sock_no_accept);
++EXPORT_SYMBOL(sock_no_bind);
++EXPORT_SYMBOL(sock_no_connect);
++EXPORT_SYMBOL(sock_no_getname);
++EXPORT_SYMBOL(sock_no_getsockopt);
++EXPORT_SYMBOL(sock_no_ioctl);
++EXPORT_SYMBOL(sock_no_listen);
++EXPORT_SYMBOL(sock_no_mmap);
++EXPORT_SYMBOL(sock_no_poll);
++EXPORT_SYMBOL(sock_no_recvmsg);
++EXPORT_SYMBOL(sock_no_release);
++EXPORT_SYMBOL(sock_no_sendmsg);
++EXPORT_SYMBOL(sock_no_sendpage);
++EXPORT_SYMBOL(sock_no_setsockopt);
++EXPORT_SYMBOL(sock_no_shutdown);
++EXPORT_SYMBOL(sock_no_socketpair);
++EXPORT_SYMBOL(sock_rfree);
++EXPORT_SYMBOL(sock_rmalloc);
++EXPORT_SYMBOL(sock_setsockopt);
++EXPORT_SYMBOL(sock_wfree);
++EXPORT_SYMBOL(sock_wmalloc);
++#ifdef CONFIG_SYSCTL
++EXPORT_SYMBOL(sysctl_rmem_max);
++EXPORT_SYMBOL(sysctl_wmem_max);
++#endif
+--- linux-2.6.0-test6/net/core/utils.c 2003-06-14 12:17:55.000000000 -0700
++++ 25/net/core/utils.c        2003-10-05 00:33:25.000000000 -0700
+@@ -13,13 +13,15 @@
+  *      2 of the License, or (at your option) any later version.
+  */
+-#include <asm/uaccess.h>
+-#include <asm/system.h>
+-#include <linux/types.h>
+-#include <linux/kernel.h>
++#include <linux/module.h>
+ #include <linux/jiffies.h>
+-#include <linux/string.h>
++#include <linux/kernel.h>
+ #include <linux/mm.h>
++#include <linux/string.h>
++#include <linux/types.h>
++
++#include <asm/system.h>
++#include <asm/uaccess.h>
+ static unsigned long net_rand_seed = 152L;
+@@ -71,3 +73,7 @@ int net_ratelimit(void)
+       spin_unlock_irqrestore(&ratelimit_lock, flags);
+       return 0;
+ }
++
++EXPORT_SYMBOL(net_random);
++EXPORT_SYMBOL(net_ratelimit);
++EXPORT_SYMBOL(net_srandom);
+--- linux-2.6.0-test6/net/core/wireless.c      2003-09-27 18:57:47.000000000 -0700
++++ 25/net/core/wireless.c     2003-10-05 00:33:25.000000000 -0700
+@@ -1365,3 +1365,10 @@ void wireless_spy_update(struct net_devi
+ #endif /* IW_WIRELESS_THRSPY */
+ #endif /* IW_WIRELESS_SPY */
+ }
++
++EXPORT_SYMBOL(iw_handler_get_spy);
++EXPORT_SYMBOL(iw_handler_get_thrspy);
++EXPORT_SYMBOL(iw_handler_set_spy);
++EXPORT_SYMBOL(iw_handler_set_thrspy);
++EXPORT_SYMBOL(wireless_send_event);
++EXPORT_SYMBOL(wireless_spy_update);
+--- linux-2.6.0-test6/net/ethernet/eth.c       2003-06-22 12:04:45.000000000 -0700
++++ 25/net/ethernet/eth.c      2003-10-05 00:33:25.000000000 -0700
+@@ -37,6 +37,7 @@
+  *            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/types.h>
+ #include <linux/kernel.h>
+ #include <linux/sched.h>
+@@ -241,3 +242,5 @@ void eth_header_cache_update(struct hh_c
+       memcpy(((u8*)hh->hh_data) + HH_DATA_OFF(sizeof(struct ethhdr)),
+              haddr, dev->addr_len);
+ }
++
++EXPORT_SYMBOL(eth_type_trans);
+--- linux-2.6.0-test6/net/ethernet/pe2.c       2003-06-14 12:18:51.000000000 -0700
++++ 25/net/ethernet/pe2.c      2003-10-05 00:33:25.000000000 -0700
+@@ -1,27 +1,28 @@
++#include <linux/in.h>
++#include <linux/mm.h>
++#include <linux/module.h>
+ #include <linux/netdevice.h>
+ #include <linux/skbuff.h>
++
+ #include <net/datalink.h>
+-#include <linux/mm.h>
+-#include <linux/in.h>
+-static int pEII_request(struct datalink_proto *dl, 
+-              struct sk_buff *skb, unsigned char *dest_node)
++static int pEII_request(struct datalink_proto *dl,
++                      struct sk_buff *skb, unsigned char *dest_node)
+ {
+-      struct net_device       *dev = skb->dev;
++      struct net_device *dev = skb->dev;
+-      skb->protocol = htons (ETH_P_IPX);
+-      if(dev->hard_header)
+-              dev->hard_header(skb, dev, ETH_P_IPX, dest_node, NULL, skb->len);
++      skb->protocol = htons(ETH_P_IPX);
++      if (dev->hard_header)
++              dev->hard_header(skb, dev, ETH_P_IPX,
++                               dest_node, NULL, skb->len);
+       return dev_queue_xmit(skb);
+ }
+-struct datalink_proto *
+-make_EII_client(void)
++struct datalink_proto *make_EII_client(void)
+ {
+-      struct datalink_proto   *proto;
++      struct datalink_proto *proto = kmalloc(sizeof(*proto), GFP_ATOMIC);
+-      proto = (struct datalink_proto *) kmalloc(sizeof(*proto), GFP_ATOMIC);
+-      if (proto != NULL) {
++      if (proto) {
+               proto->header_length = 0;
+               proto->request = pEII_request;
+       }
+@@ -34,3 +35,6 @@ void destroy_EII_client(struct datalink_
+       if (dl)
+               kfree(dl);
+ }
++
++EXPORT_SYMBOL(destroy_EII_client);
++EXPORT_SYMBOL(make_EII_client);
+--- linux-2.6.0-test6/net/ipv4/af_inet.c       2003-09-08 13:58:59.000000000 -0700
++++ 25/net/ipv4/af_inet.c      2003-10-05 00:33:25.000000000 -0700
+@@ -74,6 +74,7 @@
+ #include <linux/in.h>
+ #include <linux/kernel.h>
+ #include <linux/major.h>
++#include <linux/module.h>
+ #include <linux/sched.h>
+ #include <linux/timer.h>
+ #include <linux/string.h>
+@@ -1246,4 +1247,33 @@ int __init ipv4_proc_init(void)
+       return 0;
+ }
+ #endif /* CONFIG_PROC_FS */
++
+ MODULE_ALIAS_NETPROTO(PF_INET);
++
++EXPORT_SYMBOL(inet_accept);
++EXPORT_SYMBOL(inet_bind);
++EXPORT_SYMBOL(inet_dgram_connect);
++EXPORT_SYMBOL(inet_dgram_ops);
++EXPORT_SYMBOL(inet_family_ops);
++EXPORT_SYMBOL(inet_getname);
++EXPORT_SYMBOL(inet_getsockopt);
++EXPORT_SYMBOL(inet_ioctl);
++EXPORT_SYMBOL(inet_listen);
++EXPORT_SYMBOL(inet_recvmsg);
++EXPORT_SYMBOL(inet_register_protosw);
++EXPORT_SYMBOL(inet_release);
++EXPORT_SYMBOL(inet_sendmsg);
++EXPORT_SYMBOL(inet_setsockopt);
++EXPORT_SYMBOL(inet_shutdown);
++EXPORT_SYMBOL(inet_sock_destruct);
++EXPORT_SYMBOL(inet_sock_release);
++EXPORT_SYMBOL(inet_stream_connect);
++EXPORT_SYMBOL(inet_stream_ops);
++EXPORT_SYMBOL(inet_unregister_protosw);
++EXPORT_SYMBOL(net_statistics);
++EXPORT_SYMBOL(tcp_protocol);
++EXPORT_SYMBOL(udp_protocol);
++
++#ifdef INET_REFCNT_DEBUG
++EXPORT_SYMBOL(inet_sock_nr);
++#endif
+--- linux-2.6.0-test6/net/ipv4/arp.c   2003-09-27 18:57:47.000000000 -0700
++++ 25/net/ipv4/arp.c  2003-10-05 00:33:25.000000000 -0700
+@@ -69,6 +69,7 @@
+  *            Arnaldo C. Melo :       convert /proc/net/arp to seq_file
+  */
++#include <linux/module.h>
+ #include <linux/types.h>
+ #include <linux/string.h>
+ #include <linux/kernel.h>
+@@ -630,12 +631,6 @@ int arp_process(struct sk_buff *skb)
+       if (in_dev == NULL)
+               goto out;
+-      /* ARP header, plus 2 device addresses, plus 2 IP addresses.  */
+-      if (!pskb_may_pull(skb, (sizeof(struct arphdr) +
+-                               (2 * dev->addr_len) +
+-                               (2 * sizeof(u32)))))
+-              goto out;
+-
+       arp = skb->nh.arph;
+       switch (dev_type) {
+@@ -835,8 +830,15 @@ out:
+ int arp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
+ {
+-      struct arphdr *arp = skb->nh.arph;
++      struct arphdr *arp;
++
++      /* ARP header, plus 2 device addresses, plus 2 IP addresses.  */
++      if (!pskb_may_pull(skb, (sizeof(struct arphdr) +
++                               (2 * dev->addr_len) +
++                               (2 * sizeof(u32)))))
++              goto freeskb;
++      arp = skb->nh.arph;
+       if (arp->ar_hln != dev->addr_len ||
+           dev->flags & IFF_NOARP ||
+           skb->pkt_type == PACKET_OTHERHOST ||
+@@ -1429,3 +1431,13 @@ static int __init arp_proc_init(void)
+ }
+ #endif /* CONFIG_PROC_FS */
++
++EXPORT_SYMBOL(arp_broken_ops);
++EXPORT_SYMBOL(arp_find);
++EXPORT_SYMBOL(arp_rcv);
++EXPORT_SYMBOL(arp_send);
++EXPORT_SYMBOL(arp_tbl);
++
++#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
++EXPORT_SYMBOL(clip_tbl_hook);
++#endif
+--- linux-2.6.0-test6/net/ipv4/devinet.c       2003-08-22 19:23:42.000000000 -0700
++++ 25/net/ipv4/devinet.c      2003-10-05 00:33:25.000000000 -0700
+@@ -32,6 +32,7 @@
+ #include <asm/uaccess.h>
+ #include <asm/system.h>
+ #include <asm/bitops.h>
++#include <linux/module.h>
+ #include <linux/types.h>
+ #include <linux/kernel.h>
+ #include <linux/sched.h>
+@@ -1354,3 +1355,11 @@ void __init devinet_init(void)
+       devinet_sysctl_register(NULL, &ipv4_devconf_dflt);
+ #endif
+ }
++
++EXPORT_SYMBOL(devinet_ioctl);
++EXPORT_SYMBOL(in_dev_finish_destroy);
++EXPORT_SYMBOL(inet_select_addr);
++EXPORT_SYMBOL(inetdev_by_index);
++EXPORT_SYMBOL(inetdev_lock);
++EXPORT_SYMBOL(register_inetaddr_notifier);
++EXPORT_SYMBOL(unregister_inetaddr_notifier);
+--- linux-2.6.0-test6/net/ipv4/fib_frontend.c  2003-06-14 12:18:51.000000000 -0700
++++ 25/net/ipv4/fib_frontend.c 2003-10-05 00:33:25.000000000 -0700
+@@ -16,6 +16,7 @@
+  */
+ #include <linux/config.h>
++#include <linux/module.h>
+ #include <asm/uaccess.h>
+ #include <asm/system.h>
+ #include <asm/bitops.h>
+@@ -605,3 +606,6 @@ void __init ip_fib_init(void)
+       register_inetaddr_notifier(&fib_inetaddr_notifier);
+ }
++EXPORT_SYMBOL(inet_addr_type);
++EXPORT_SYMBOL(ip_dev_find);
++EXPORT_SYMBOL(ip_rt_ioctl);
+--- linux-2.6.0-test6/net/ipv4/icmp.c  2003-09-27 18:57:47.000000000 -0700
++++ 25/net/ipv4/icmp.c 2003-10-05 00:33:25.000000000 -0700
+@@ -65,6 +65,7 @@
+  */
+ #include <linux/config.h>
++#include <linux/module.h>
+ #include <linux/types.h>
+ #include <linux/jiffies.h>
+ #include <linux/kernel.h>
+@@ -1126,3 +1127,8 @@ void __init icmp_init(struct net_proto_f
+               per_cpu(__icmp_socket, i)->sk->sk_prot->unhash(per_cpu(__icmp_socket, i)->sk);
+       }
+ }
++
++EXPORT_SYMBOL(icmp_err_convert);
++EXPORT_SYMBOL(icmp_send);
++EXPORT_SYMBOL(icmp_statistics);
++EXPORT_SYMBOL(xrlim_allow);
+--- linux-2.6.0-test6/net/ipv4/igmp.c  2003-09-27 18:57:47.000000000 -0700
++++ 25/net/ipv4/igmp.c 2003-10-05 00:33:25.000000000 -0700
+@@ -72,8 +72,8 @@
+  *                                    Vinay Kulkarni
+  */
+-
+ #include <linux/config.h>
++#include <linux/module.h>
+ #include <asm/uaccess.h>
+ #include <asm/system.h>
+ #include <linux/types.h>
+@@ -2438,3 +2438,6 @@ int __init igmp_mc_proc_init(void)
+ }
+ #endif
++EXPORT_SYMBOL(ip_mc_dec_group);
++EXPORT_SYMBOL(ip_mc_inc_group);
++EXPORT_SYMBOL(ip_mc_join_group);
+--- linux-2.6.0-test6/net/ipv4/inetpeer.c      2003-06-14 12:18:33.000000000 -0700
++++ 25/net/ipv4/inetpeer.c     2003-10-05 00:33:25.000000000 -0700
+@@ -8,6 +8,7 @@
+  *  Authors:  Andrey V. Savochkin <saw@msu.ru>
+  */
++#include <linux/module.h>
+ #include <linux/types.h>
+ #include <linux/slab.h>
+ #include <linux/interrupt.h>
+@@ -452,3 +453,5 @@ static void peer_check_expire(unsigned l
+                       peer_total / inet_peer_threshold * HZ;
+       add_timer(&peer_periodic_timer);
+ }
++
++EXPORT_SYMBOL(inet_peer_idlock);
+--- linux-2.6.0-test6/net/ipv4/ip_fragment.c   2003-06-14 12:18:05.000000000 -0700
++++ 25/net/ipv4/ip_fragment.c  2003-10-05 00:33:25.000000000 -0700
+@@ -23,6 +23,7 @@
+  */
+ #include <linux/config.h>
++#include <linux/module.h>
+ #include <linux/types.h>
+ #include <linux/mm.h>
+ #include <linux/jiffies.h>
+@@ -675,3 +676,5 @@ void ipfrag_init(void)
+       ipfrag_secret_timer.expires = jiffies + sysctl_ipfrag_secret_interval;
+       add_timer(&ipfrag_secret_timer);
+ }
++
++EXPORT_SYMBOL(ip_defrag);
+--- linux-2.6.0-test6/net/ipv4/ip_input.c      2003-09-27 18:57:47.000000000 -0700
++++ 25/net/ipv4/ip_input.c     2003-10-05 00:33:25.000000000 -0700
+@@ -116,6 +116,7 @@
+  */
+ #include <asm/system.h>
++#include <linux/module.h>
+ #include <linux/types.h>
+ #include <linux/kernel.h>
+ #include <linux/string.h>
+@@ -432,3 +433,5 @@ out:
+         return NET_RX_DROP;
+ }
++EXPORT_SYMBOL(ip_rcv);
++EXPORT_SYMBOL(ip_statistics);
+--- linux-2.6.0-test6/net/ipv4/ipip.c  2003-08-22 19:23:42.000000000 -0700
++++ 25/net/ipv4/ipip.c 2003-10-05 00:33:25.000000000 -0700
+@@ -483,6 +483,11 @@ static int ipip_rcv(struct sk_buff *skb)
+       read_lock(&ipip_lock);
+       if ((tunnel = ipip_tunnel_lookup(iph->saddr, iph->daddr)) != NULL) {
++              if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
++                      kfree_skb(skb);
++                      return 0;
++              }
++
+               tunnel->stat.rx_packets++;
+               tunnel->stat.rx_bytes += skb->len;
+               skb->dev = tunnel->dev;
+--- linux-2.6.0-test6/net/ipv4/ip_options.c    2003-06-14 12:18:28.000000000 -0700
++++ 25/net/ipv4/ip_options.c   2003-10-05 00:33:25.000000000 -0700
+@@ -11,6 +11,7 @@
+  *            
+  */
++#include <linux/module.h>
+ #include <linux/types.h>
+ #include <asm/uaccess.h>
+ #include <linux/skbuff.h>
+@@ -617,3 +618,6 @@ int ip_options_rcv_srr(struct sk_buff *s
+       }
+       return 0;
+ }
++
++EXPORT_SYMBOL(ip_options_compile);
++EXPORT_SYMBOL(ip_options_undo);
+--- linux-2.6.0-test6/net/ipv4/ip_output.c     2003-09-27 18:57:47.000000000 -0700
++++ 25/net/ipv4/ip_output.c    2003-10-05 00:33:25.000000000 -0700
+@@ -46,6 +46,7 @@
+ #include <asm/uaccess.h>
+ #include <asm/system.h>
++#include <linux/module.h>
+ #include <linux/types.h>
+ #include <linux/kernel.h>
+ #include <linux/sched.h>
+@@ -1317,3 +1318,13 @@ void __init ip_init(void)
+       igmp_mc_proc_init();
+ #endif
+ }
++
++EXPORT_SYMBOL(ip_finish_output);
++EXPORT_SYMBOL(ip_fragment);
++EXPORT_SYMBOL(ip_generic_getfrag);
++EXPORT_SYMBOL(ip_queue_xmit);
++EXPORT_SYMBOL(ip_send_check);
++
++#ifdef CONFIG_SYSCTL
++EXPORT_SYMBOL(sysctl_ip_default_ttl);
++#endif
+--- linux-2.6.0-test6/net/ipv4/ip_sockglue.c   2003-06-14 12:18:06.000000000 -0700
++++ 25/net/ipv4/ip_sockglue.c  2003-10-05 00:33:25.000000000 -0700
+@@ -18,6 +18,7 @@
+  */
+ #include <linux/config.h>
++#include <linux/module.h>
+ #include <linux/types.h>
+ #include <linux/mm.h>
+ #include <linux/sched.h>
+@@ -1055,3 +1056,10 @@ int ip_getsockopt(struct sock *sk, int l
+       }
+       return 0;
+ }
++
++EXPORT_SYMBOL(ip_cmsg_recv);
++
++#ifdef CONFIG_IP_SCTP_MODULE
++EXPORT_SYMBOL(ip_getsockopt);
++EXPORT_SYMBOL(ip_setsockopt);
++#endif
+--- linux-2.6.0-test6/net/ipv4/ipvs/ip_vs_lblc.c       2003-09-27 18:57:47.000000000 -0700
++++ 25/net/ipv4/ipvs/ip_vs_lblc.c      2003-10-05 00:33:25.000000000 -0700
+@@ -458,10 +458,11 @@ __ip_vs_wlc_schedule(struct ip_vs_servic
+        * The server with weight=0 is quiesced and will not receive any
+        * new connection.
+        */
+-      list_for_each_entry(least, &svc->destinations, n_list) {
+-              if (least->flags & IP_VS_DEST_F_OVERLOAD)
++      list_for_each_entry(dest, &svc->destinations, n_list) {
++              if (dest->flags & IP_VS_DEST_F_OVERLOAD)
+                       continue;
+-              if (atomic_read(&least->weight) > 0) {
++              if (atomic_read(&dest->weight) > 0) {
++                      least = dest;
+                       loh = atomic_read(&least->activeconns) * 50
+                               + atomic_read(&least->inactconns);
+                       goto nextstage;
+@@ -473,7 +474,7 @@ __ip_vs_wlc_schedule(struct ip_vs_servic
+        *    Find the destination with the least load.
+        */
+   nextstage:
+-      list_for_each_entry(dest, &svc->destinations, n_list) {
++      list_for_each_entry_continue(dest, &svc->destinations, n_list) {
+               if (dest->flags & IP_VS_DEST_F_OVERLOAD)
+                       continue;
+--- linux-2.6.0-test6/net/ipv4/ipvs/ip_vs_lblcr.c      2003-09-27 18:57:47.000000000 -0700
++++ 25/net/ipv4/ipvs/ip_vs_lblcr.c     2003-10-05 00:33:25.000000000 -0700
+@@ -711,11 +711,12 @@ __ip_vs_wlc_schedule(struct ip_vs_servic
+        * The server with weight=0 is quiesced and will not receive any
+        * new connection.
+        */
+-      list_for_each_entry(least, &svc->destinations, n_list) {
+-              if (least->flags & IP_VS_DEST_F_OVERLOAD)
++      list_for_each_entry(dest, &svc->destinations, n_list) {
++              if (dest->flags & IP_VS_DEST_F_OVERLOAD)
+                       continue;
+-              if (atomic_read(&least->weight) > 0) {
++              if (atomic_read(&dest->weight) > 0) {
++                      least = dest;
+                       loh = atomic_read(&least->activeconns) * 50
+                               + atomic_read(&least->inactconns);
+                       goto nextstage;
+@@ -727,7 +728,7 @@ __ip_vs_wlc_schedule(struct ip_vs_servic
+        *    Find the destination with the least load.
+        */
+   nextstage:
+-      list_for_each_entry(dest, &svc->destinations, n_list) {
++      list_for_each_entry_continue(dest, &svc->destinations, n_list) {
+               if (dest->flags & IP_VS_DEST_F_OVERLOAD)
+                       continue;
+--- linux-2.6.0-test6/net/ipv4/ipvs/ip_vs_lc.c 2003-09-27 18:57:47.000000000 -0700
++++ 25/net/ipv4/ipvs/ip_vs_lc.c        2003-10-05 00:33:25.000000000 -0700
+@@ -65,8 +65,8 @@ ip_vs_lc_dest_overhead(struct ip_vs_dest
+ static struct ip_vs_dest *
+ ip_vs_lc_schedule(struct ip_vs_service *svc, struct iphdr *iph)
+ {
+-      struct ip_vs_dest *dest, *least;
+-      unsigned int loh, doh;
++      struct ip_vs_dest *dest, *least = NULL;
++      unsigned int loh = 0, doh;
+       IP_VS_DBG(6, "ip_vs_lc_schedule(): Scheduling...\n");
+@@ -79,31 +79,18 @@ ip_vs_lc_schedule(struct ip_vs_service *
+        * served, but no new connection is assigned to the server.
+        */
+-      list_for_each_entry(least, &svc->destinations, n_list) {
+-              if (least->flags & IP_VS_DEST_F_OVERLOAD)
+-                      continue;
+-              if (atomic_read(&least->weight) > 0) {
+-                      loh = ip_vs_lc_dest_overhead(least);
+-                      goto nextstage;
+-              }
+-      }
+-      return NULL;
+-
+-      /*
+-       *    Find the destination with the least load.
+-       */
+-  nextstage:
+       list_for_each_entry(dest, &svc->destinations, n_list) {
+               if ((dest->flags & IP_VS_DEST_F_OVERLOAD) ||
+                   atomic_read(&dest->weight) == 0)
+                       continue;
+               doh = ip_vs_lc_dest_overhead(dest);
+-              if (doh < loh) {
++              if (!least || doh < loh) {
+                       least = dest;
+                       loh = doh;
+               }
+       }
++      if (least)
+       IP_VS_DBG(6, "LC: server %u.%u.%u.%u:%u activeconns %d inactconns %d\n",
+                 NIPQUAD(least->addr), ntohs(least->port),
+                 atomic_read(&least->activeconns),
+--- linux-2.6.0-test6/net/ipv4/ipvs/ip_vs_nq.c 2003-09-27 18:57:47.000000000 -0700
++++ 25/net/ipv4/ipvs/ip_vs_nq.c        2003-10-05 00:33:25.000000000 -0700
+@@ -81,8 +81,8 @@ ip_vs_nq_dest_overhead(struct ip_vs_dest
+ static struct ip_vs_dest *
+ ip_vs_nq_schedule(struct ip_vs_service *svc, struct iphdr *iph)
+ {
+-      struct ip_vs_dest *dest, *least;
+-      unsigned int loh, doh;
++      struct ip_vs_dest *dest, *least = NULL;
++      unsigned int loh = 0, doh;
+       IP_VS_DBG(6, "ip_vs_nq_schedule(): Scheduling...\n");
+@@ -99,27 +99,10 @@ ip_vs_nq_schedule(struct ip_vs_service *
+        * new connections.
+        */
+-      list_for_each_entry(least, &svc->destinations, n_list) {
+-              if (!(least->flags & IP_VS_DEST_F_OVERLOAD) &&
+-                  atomic_read(&least->weight) > 0) {
+-                      loh = ip_vs_nq_dest_overhead(least);
+-
+-                      /* return the server directly if it is idle */
+-                      if (atomic_read(&least->activeconns) == 0)
+-                              goto out;
+-
+-                      goto nextstage;
+-              }
+-      }
+-      return NULL;
+-
+-      /*
+-       *    Find the destination with the least load.
+-       */
+-  nextstage:
+       list_for_each_entry(dest, &svc->destinations, n_list) {
+-              if (dest->flags & IP_VS_DEST_F_OVERLOAD)
++              if (dest->flags & IP_VS_DEST_F_OVERLOAD ||
++                  !atomic_read(&dest->weight))
+                       continue;
+               doh = ip_vs_nq_dest_overhead(dest);
+@@ -127,16 +110,21 @@ ip_vs_nq_schedule(struct ip_vs_service *
+               /* return the server directly if it is idle */
+               if (atomic_read(&dest->activeconns) == 0) {
+                       least = dest;
++                      loh = doh;
+                       goto out;
+               }
+-              if (loh * atomic_read(&dest->weight) >
+-                  doh * atomic_read(&least->weight)) {
++              if (!least ||
++                  (loh * atomic_read(&dest->weight) >
++                   doh * atomic_read(&least->weight))) {
+                       least = dest;
+                       loh = doh;
+               }
+       }
++      if (!least)
++              return NULL;
++
+   out:
+       IP_VS_DBG(6, "NQ: server %u.%u.%u.%u:%u "
+                 "activeconns %d refcnt %d weight %d overhead %d\n",
+--- linux-2.6.0-test6/net/ipv4/ipvs/ip_vs_sed.c        2003-09-27 18:57:47.000000000 -0700
++++ 25/net/ipv4/ipvs/ip_vs_sed.c       2003-10-05 00:33:25.000000000 -0700
+@@ -103,9 +103,10 @@ ip_vs_sed_schedule(struct ip_vs_service 
+        * new connections.
+        */
+-      list_for_each_entry(least, &svc->destinations, n_list) {
+-              if (!(least->flags & IP_VS_DEST_F_OVERLOAD) &&
+-                  atomic_read(&least->weight) > 0) {
++      list_for_each_entry(dest, &svc->destinations, n_list) {
++              if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
++                  atomic_read(&dest->weight) > 0) {
++                      least = dest;
+                       loh = ip_vs_sed_dest_overhead(least);
+                       goto nextstage;
+               }
+@@ -116,7 +117,7 @@ ip_vs_sed_schedule(struct ip_vs_service 
+        *    Find the destination with the least load.
+        */
+   nextstage:
+-      list_for_each_entry(dest, &svc->destinations, n_list) {
++      list_for_each_entry_continue(dest, &svc->destinations, n_list) {
+               if (dest->flags & IP_VS_DEST_F_OVERLOAD)
+                       continue;
+               doh = ip_vs_sed_dest_overhead(dest);
+--- linux-2.6.0-test6/net/ipv4/ipvs/ip_vs_wlc.c        2003-09-27 18:57:47.000000000 -0700
++++ 25/net/ipv4/ipvs/ip_vs_wlc.c       2003-10-05 00:33:25.000000000 -0700
+@@ -91,9 +91,10 @@ ip_vs_wlc_schedule(struct ip_vs_service 
+        * new connections.
+        */
+-      list_for_each_entry(least, &svc->destinations, n_list) {
+-              if (!(least->flags & IP_VS_DEST_F_OVERLOAD) &&
+-                  atomic_read(&least->weight) > 0) {
++      list_for_each_entry(dest, &svc->destinations, n_list) {
++              if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
++                  atomic_read(&dest->weight) > 0) {
++                      least = dest;
+                       loh = ip_vs_wlc_dest_overhead(least);
+                       goto nextstage;
+               }
+@@ -104,7 +105,7 @@ ip_vs_wlc_schedule(struct ip_vs_service 
+        *    Find the destination with the least load.
+        */
+   nextstage:
+-      list_for_each_entry(dest, &svc->destinations, n_list) {
++      list_for_each_entry_continue(dest, &svc->destinations, n_list) {
+               if (dest->flags & IP_VS_DEST_F_OVERLOAD)
+                       continue;
+               doh = ip_vs_wlc_dest_overhead(dest);
+--- linux-2.6.0-test6/net/ipv4/ipvs/ip_vs_wrr.c        2003-09-27 18:57:47.000000000 -0700
++++ 25/net/ipv4/ipvs/ip_vs_wrr.c       2003-10-05 00:33:25.000000000 -0700
+@@ -58,26 +58,18 @@ static int ip_vs_wrr_gcd_weight(struct i
+ {
+       struct ip_vs_dest *dest;
+       int weight;
+-      int g = 1;
++      int g = 0;
+       list_for_each_entry(dest, &svc->destinations, n_list) {
+               weight = atomic_read(&dest->weight);
+               if (weight > 0) {
+-                      g = weight;
+-                      goto search_gcd;
++                      if (g > 0)
++                              g = gcd(weight, g);
++                      else
++                              g = weight;
+               }
+       }
+-
+-      return g;
+-
+- search_gcd:
+-      list_for_each_entry(dest, &svc->destinations, n_list) {
+-              weight = atomic_read(&dest->weight);
+-              if (weight > 0)
+-                      g = gcd(weight, g);
+-      }
+-
+-      return g;
++      return g ? g : 1;
+ }
+--- linux-2.6.0-test6/net/ipv4/netfilter/ip_conntrack_core.c   2003-09-08 13:58:59.000000000 -0700
++++ 25/net/ipv4/netfilter/ip_conntrack_core.c  2003-10-05 00:33:25.000000000 -0700
+@@ -59,7 +59,7 @@ LIST_HEAD(ip_conntrack_expect_list);
+ LIST_HEAD(protocol_list);
+ static LIST_HEAD(helpers);
+ unsigned int ip_conntrack_htable_size = 0;
+-static int ip_conntrack_max;
++int ip_conntrack_max;
+ static atomic_t ip_conntrack_count = ATOMIC_INIT(0);
+ struct list_head *ip_conntrack_hash;
+ static kmem_cache_t *ip_conntrack_cachep;
+@@ -301,7 +301,7 @@ clean_from_lists(struct ip_conntrack *ct
+ static void
+ destroy_conntrack(struct nf_conntrack *nfct)
+ {
+-      struct ip_conntrack *ct = (struct ip_conntrack *)nfct;
++      struct ip_conntrack *ct = (struct ip_conntrack *)nfct, *master = NULL;
+       struct ip_conntrack_protocol *proto;
+       DEBUGP("destroy_conntrack(%p)\n", ct);
+@@ -328,12 +328,15 @@ destroy_conntrack(struct nf_conntrack *n
+                       /* can't call __unexpect_related here,
+                        * since it would screw up expect_list */
+                       list_del(&ct->master->expected_list);
+-                      ip_conntrack_put(ct->master->expectant);
++                      master = ct->master->expectant;
+               }
+               kfree(ct->master);
+       }
+       WRITE_UNLOCK(&ip_conntrack_lock);
++      if (master)
++              ip_conntrack_put(master);
++
+       DEBUGP("destroy_conntrack: returning ct=%p to slab\n", ct);
+       kmem_cache_free(ip_conntrack_cachep, ct);
+       atomic_dec(&ip_conntrack_count);
+@@ -1276,11 +1279,14 @@ getorigdst(struct sock *sk, int optval, 
+ {
+       struct inet_opt *inet = inet_sk(sk);
+       struct ip_conntrack_tuple_hash *h;
+-      struct ip_conntrack_tuple tuple = { { inet->rcv_saddr,
+-                                              { .tcp = { inet->sport } } },
+-                                          { inet->daddr,
+-                                              { .tcp = { inet->dport } },
+-                                            IPPROTO_TCP } };
++      struct ip_conntrack_tuple tuple;
++      
++      IP_CT_TUPLE_U_BLANK(&tuple);
++      tuple.src.ip = inet->rcv_saddr;
++      tuple.src.u.tcp.port = inet->sport;
++      tuple.dst.ip = inet->daddr;
++      tuple.dst.u.tcp.port = inet->dport;
++      tuple.dst.protonum = IPPROTO_TCP;
+       /* We only do TCP at the moment: is there a better way? */
+       if (strcmp(sk->sk_prot->name, "TCP")) {
+@@ -1325,45 +1331,6 @@ static struct nf_sockopt_ops so_getorigd
+       .get            = &getorigdst,
+ };
+-#define NET_IP_CONNTRACK_MAX 2089
+-#define NET_IP_CONNTRACK_MAX_NAME "ip_conntrack_max"
+-
+-#ifdef CONFIG_SYSCTL
+-static struct ctl_table_header *ip_conntrack_sysctl_header;
+-
+-static ctl_table ip_conntrack_table[] = {
+-      {
+-              .ctl_name       = NET_IP_CONNTRACK_MAX,
+-              .procname       = NET_IP_CONNTRACK_MAX_NAME,
+-              .data           = &ip_conntrack_max,
+-              .maxlen         = sizeof(ip_conntrack_max),
+-              .mode           = 0644,
+-              .proc_handler   = proc_dointvec
+-      },
+-      { .ctl_name = 0 }
+-};
+-
+-static ctl_table ip_conntrack_dir_table[] = {
+-      {
+-              .ctl_name       = NET_IPV4,
+-              .procname       = "ipv4",
+-              .mode           = 0555,
+-              .child          = ip_conntrack_table
+-      },
+-      { .ctl_name = 0 }
+-};
+-
+-static ctl_table ip_conntrack_root_table[] = {
+-      {
+-              .ctl_name       = CTL_NET,
+-              .procname       = "net",
+-              .mode           = 0555,
+-              .child          = ip_conntrack_dir_table
+-      },
+-      { .ctl_name = 0 }
+-};
+-#endif /*CONFIG_SYSCTL*/
+-
+ static int kill_all(const struct ip_conntrack *i, void *data)
+ {
+       return 1;
+@@ -1373,9 +1340,6 @@ static int kill_all(const struct ip_conn
+    supposed to kill the mall. */
+ void ip_conntrack_cleanup(void)
+ {
+-#ifdef CONFIG_SYSCTL
+-      unregister_sysctl_table(ip_conntrack_sysctl_header);
+-#endif
+       ip_ct_attach = NULL;
+       /* This makes sure all current packets have passed through
+            netfilter framework.  Roll on, two-stage module
+@@ -1453,25 +1417,10 @@ int __init ip_conntrack_init(void)
+       for (i = 0; i < ip_conntrack_htable_size; i++)
+               INIT_LIST_HEAD(&ip_conntrack_hash[i]);
+-/* This is fucking braindead.  There is NO WAY of doing this without
+-   the CONFIG_SYSCTL unless you don't want to detect errors.
+-   Grrr... --RR */
+-#ifdef CONFIG_SYSCTL
+-      ip_conntrack_sysctl_header
+-              = register_sysctl_table(ip_conntrack_root_table, 0);
+-      if (ip_conntrack_sysctl_header == NULL) {
+-              goto err_free_ct_cachep;
+-      }
+-#endif /*CONFIG_SYSCTL*/
+-
+       /* For use by ipt_REJECT */
+       ip_ct_attach = ip_conntrack_attach;
+       return ret;
+-#ifdef CONFIG_SYSCTL
+-err_free_ct_cachep:
+-      kmem_cache_destroy(ip_conntrack_cachep);
+-#endif /*CONFIG_SYSCTL*/
+ err_free_hash:
+       vfree(ip_conntrack_hash);
+ err_unreg_sockopt:
+--- linux-2.6.0-test6/net/ipv4/netfilter/ip_conntrack_irc.c    2003-09-08 13:58:59.000000000 -0700
++++ 25/net/ipv4/netfilter/ip_conntrack_irc.c   2003-10-05 00:33:25.000000000 -0700
+@@ -177,7 +177,10 @@ static int help(struct sk_buff *skb,
+                       DEBUGP("DCC bound ip/port: %u.%u.%u.%u:%u\n",
+                               HIPQUAD(dcc_ip), dcc_port);
+-                      if (ct->tuplehash[dir].tuple.src.ip != htonl(dcc_ip)) {
++                      /* dcc_ip can be the internal OR external (NAT'ed) IP
++                       * Tiago Sousa <mirage@kaotik.org> */
++                      if (ct->tuplehash[dir].tuple.src.ip != htonl(dcc_ip)
++                          && ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip != htonl(dcc_ip)) {
+                               if (net_ratelimit())
+                                       printk(KERN_WARNING
+                                               "Forged DCC command from "
+@@ -201,7 +204,7 @@ static int help(struct sk_buff *skb,
+                       exp->tuple = ((struct ip_conntrack_tuple)
+                               { { 0, { 0 } },
+-                                { htonl(dcc_ip), { .tcp = { htons(dcc_port) } },
++                                { ct->tuplehash[dir].tuple.src.ip, { .tcp = { htons(dcc_port) } },
+                                   IPPROTO_TCP }});
+                       exp->mask = ((struct ip_conntrack_tuple)
+                               { { 0, { 0 } },
+--- linux-2.6.0-test6/net/ipv4/netfilter/ip_conntrack_proto_generic.c  2003-06-14 12:18:07.000000000 -0700
++++ 25/net/ipv4/netfilter/ip_conntrack_proto_generic.c 2003-10-05 00:33:25.000000000 -0700
+@@ -4,7 +4,7 @@
+ #include <linux/netfilter.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
+-#define GENERIC_TIMEOUT (600*HZ)
++unsigned long ip_ct_generic_timeout = 600*HZ;
+ static int generic_pkt_to_tuple(const struct sk_buff *skb,
+                               unsigned int dataoff,
+@@ -44,7 +44,7 @@ static int packet(struct ip_conntrack *c
+                 const struct sk_buff *skb,
+                 enum ip_conntrack_info conntrackinfo)
+ {
+-      ip_ct_refresh(conntrack, GENERIC_TIMEOUT);
++      ip_ct_refresh(conntrack, ip_ct_generic_timeout);
+       return NF_ACCEPT;
+ }
+--- linux-2.6.0-test6/net/ipv4/netfilter/ip_conntrack_proto_icmp.c     2003-06-14 12:17:56.000000000 -0700
++++ 25/net/ipv4/netfilter/ip_conntrack_proto_icmp.c    2003-10-05 00:33:25.000000000 -0700
+@@ -6,7 +6,7 @@
+ #include <linux/icmp.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
+-#define ICMP_TIMEOUT (30*HZ)
++unsigned long ip_ct_icmp_timeout = 30*HZ;
+ #if 0
+ #define DEBUGP printk
+@@ -86,7 +86,7 @@ static int icmp_packet(struct ip_conntra
+                       ct->timeout.function((unsigned long)ct);
+       } else {
+               atomic_inc(&ct->proto.icmp.count);
+-              ip_ct_refresh(ct, ICMP_TIMEOUT);
++              ip_ct_refresh(ct, ip_ct_icmp_timeout);
+       }
+       return NF_ACCEPT;
+--- linux-2.6.0-test6/net/ipv4/netfilter/ip_conntrack_proto_tcp.c      2003-06-14 12:18:51.000000000 -0700
++++ 25/net/ipv4/netfilter/ip_conntrack_proto_tcp.c     2003-10-05 00:33:25.000000000 -0700
+@@ -49,20 +49,28 @@ static const char *tcp_conntrack_names[]
+ #define HOURS * 60 MINS
+ #define DAYS * 24 HOURS
+-
+-static unsigned long tcp_timeouts[]
+-= { 30 MINS,  /*      TCP_CONNTRACK_NONE,     */
+-    5 DAYS,   /*      TCP_CONNTRACK_ESTABLISHED,      */
+-    2 MINS,   /*      TCP_CONNTRACK_SYN_SENT, */
+-    60 SECS,  /*      TCP_CONNTRACK_SYN_RECV, */
+-    2 MINS,   /*      TCP_CONNTRACK_FIN_WAIT, */
+-    2 MINS,   /*      TCP_CONNTRACK_TIME_WAIT,        */
+-    10 SECS,  /*      TCP_CONNTRACK_CLOSE,    */
+-    60 SECS,  /*      TCP_CONNTRACK_CLOSE_WAIT,       */
+-    30 SECS,  /*      TCP_CONNTRACK_LAST_ACK, */
+-    2 MINS,   /*      TCP_CONNTRACK_LISTEN,   */
+-};
+-
++unsigned long ip_ct_tcp_timeout_syn_sent =      2 MINS;
++unsigned long ip_ct_tcp_timeout_syn_recv =     60 SECS;
++unsigned long ip_ct_tcp_timeout_established =   5 DAYS;
++unsigned long ip_ct_tcp_timeout_fin_wait =      2 MINS;
++unsigned long ip_ct_tcp_timeout_close_wait =    3 DAYS;
++unsigned long ip_ct_tcp_timeout_last_ack =     30 SECS;
++unsigned long ip_ct_tcp_timeout_time_wait =     2 MINS;
++unsigned long ip_ct_tcp_timeout_close =        10 SECS;
++
++static unsigned long * tcp_timeouts[]
++= { 0,                                 /*      TCP_CONNTRACK_NONE */
++    &ip_ct_tcp_timeout_established,    /*      TCP_CONNTRACK_ESTABLISHED,      */
++    &ip_ct_tcp_timeout_syn_sent,       /*      TCP_CONNTRACK_SYN_SENT, */
++    &ip_ct_tcp_timeout_syn_recv,       /*      TCP_CONNTRACK_SYN_RECV, */
++    &ip_ct_tcp_timeout_fin_wait,       /*      TCP_CONNTRACK_FIN_WAIT, */
++    &ip_ct_tcp_timeout_time_wait,      /*      TCP_CONNTRACK_TIME_WAIT,        */
++    &ip_ct_tcp_timeout_close,          /*      TCP_CONNTRACK_CLOSE,    */
++    &ip_ct_tcp_timeout_close_wait,     /*      TCP_CONNTRACK_CLOSE_WAIT,       */
++    &ip_ct_tcp_timeout_last_ack,       /*      TCP_CONNTRACK_LAST_ACK, */
++    0,                                 /*      TCP_CONNTRACK_LISTEN */
++ };
++ 
+ #define sNO TCP_CONNTRACK_NONE
+ #define sES TCP_CONNTRACK_ESTABLISHED
+ #define sSS TCP_CONNTRACK_SYN_SENT
+@@ -204,7 +212,7 @@ static int tcp_packet(struct ip_conntrac
+                       set_bit(IPS_ASSURED_BIT, &conntrack->status);
+               WRITE_UNLOCK(&tcp_lock);
+-              ip_ct_refresh(conntrack, tcp_timeouts[newconntrack]);
++              ip_ct_refresh(conntrack, *tcp_timeouts[newconntrack]);
+       }
+       return NF_ACCEPT;
+--- linux-2.6.0-test6/net/ipv4/netfilter/ip_conntrack_proto_udp.c      2003-06-14 12:17:55.000000000 -0700
++++ 25/net/ipv4/netfilter/ip_conntrack_proto_udp.c     2003-10-05 00:33:25.000000000 -0700
+@@ -6,8 +6,8 @@
+ #include <linux/udp.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
+-#define UDP_TIMEOUT (30*HZ)
+-#define UDP_STREAM_TIMEOUT (180*HZ)
++unsigned long ip_ct_udp_timeout = 30*HZ;
++unsigned long ip_ct_udp_timeout_stream = 180*HZ;
+ static int udp_pkt_to_tuple(const struct sk_buff *skb,
+                            unsigned int dataoff,
+@@ -57,11 +57,11 @@ static int udp_packet(struct ip_conntrac
+       /* If we've seen traffic both ways, this is some kind of UDP
+          stream.  Extend timeout. */
+       if (test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) {
+-              ip_ct_refresh(conntrack, UDP_STREAM_TIMEOUT);
++              ip_ct_refresh(conntrack, ip_ct_udp_timeout_stream);
+               /* Also, more likely to be important, and not a probe */
+               set_bit(IPS_ASSURED_BIT, &conntrack->status);
+       } else
+-              ip_ct_refresh(conntrack, UDP_TIMEOUT);
++              ip_ct_refresh(conntrack, ip_ct_udp_timeout);
+       return NF_ACCEPT;
+ }
+--- linux-2.6.0-test6/net/ipv4/netfilter/ip_conntrack_standalone.c     2003-09-08 13:58:59.000000000 -0700
++++ 25/net/ipv4/netfilter/ip_conntrack_standalone.c    2003-10-05 00:33:25.000000000 -0700
+@@ -7,6 +7,7 @@
+ /* (c) 1999 Paul `Rusty' Russell.  Licenced under the GNU General
+    Public Licence. */
++#include <linux/config.h>
+ #include <linux/types.h>
+ #include <linux/ip.h>
+ #include <linux/netfilter.h>
+@@ -14,6 +15,9 @@
+ #include <linux/module.h>
+ #include <linux/skbuff.h>
+ #include <linux/proc_fs.h>
++#ifdef CONFIG_SYSCTL
++#include <linux/sysctl.h>
++#endif
+ #include <net/checksum.h>
+ #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock)
+@@ -256,6 +260,98 @@ static struct nf_hook_ops ip_conntrack_l
+       .priority       = NF_IP_PRI_LAST-1,
+ };
++/* Sysctl support */
++
++#ifdef CONFIG_SYSCTL
++
++/* From ip_conntrack_core.c */
++extern int ip_conntrack_max;
++
++/* From ip_conntrack_proto_tcp.c */
++extern unsigned long ip_ct_tcp_timeout_syn_sent;
++extern unsigned long ip_ct_tcp_timeout_syn_recv;
++extern unsigned long ip_ct_tcp_timeout_established;
++extern unsigned long ip_ct_tcp_timeout_fin_wait;
++extern unsigned long ip_ct_tcp_timeout_close_wait;
++extern unsigned long ip_ct_tcp_timeout_last_ack;
++extern unsigned long ip_ct_tcp_timeout_time_wait;
++extern unsigned long ip_ct_tcp_timeout_close;
++
++/* From ip_conntrack_proto_udp.c */
++extern unsigned long ip_ct_udp_timeout;
++extern unsigned long ip_ct_udp_timeout_stream;
++
++/* From ip_conntrack_proto_icmp.c */
++extern unsigned long ip_ct_icmp_timeout;
++
++/* From ip_conntrack_proto_icmp.c */
++extern unsigned long ip_ct_generic_timeout;
++
++static struct ctl_table_header *ip_ct_sysctl_header;
++
++static ctl_table ip_ct_sysctl_table[] = {
++      {NET_IPV4_NF_CONNTRACK_MAX, "ip_conntrack_max",
++       &ip_conntrack_max, sizeof(int), 0644, NULL,
++       &proc_dointvec},
++      {NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT, "ip_conntrack_tcp_timeout_syn_sent",
++       &ip_ct_tcp_timeout_syn_sent, sizeof(unsigned int), 0644, NULL,
++       &proc_dointvec_jiffies},
++      {NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV, "ip_conntrack_tcp_timeout_syn_recv",
++       &ip_ct_tcp_timeout_syn_recv, sizeof(unsigned int), 0644, NULL,
++       &proc_dointvec_jiffies},
++      {NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED, "ip_conntrack_tcp_timeout_established",
++       &ip_ct_tcp_timeout_established, sizeof(unsigned int), 0644, NULL,
++       &proc_dointvec_jiffies},
++      {NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT, "ip_conntrack_tcp_timeout_fin_wait",
++       &ip_ct_tcp_timeout_fin_wait, sizeof(unsigned int), 0644, NULL,
++       &proc_dointvec_jiffies},
++      {NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT, "ip_conntrack_tcp_timeout_close_wait",
++       &ip_ct_tcp_timeout_close_wait, sizeof(unsigned int), 0644, NULL,
++       &proc_dointvec_jiffies},
++      {NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK, "ip_conntrack_tcp_timeout_last_ack",
++       &ip_ct_tcp_timeout_last_ack, sizeof(unsigned int), 0644, NULL,
++       &proc_dointvec_jiffies},
++      {NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT, "ip_conntrack_tcp_timeout_time_wait",
++       &ip_ct_tcp_timeout_time_wait, sizeof(unsigned int), 0644, NULL,
++       &proc_dointvec_jiffies},
++      {NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE, "ip_conntrack_tcp_timeout_close",
++       &ip_ct_tcp_timeout_close, sizeof(unsigned int), 0644, NULL,
++       &proc_dointvec_jiffies},
++      {NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT, "ip_conntrack_udp_timeout",
++       &ip_ct_udp_timeout, sizeof(unsigned int), 0644, NULL,
++       &proc_dointvec_jiffies},
++      {NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT_STREAM, "ip_conntrack_udp_timeout_stream",
++       &ip_ct_udp_timeout_stream, sizeof(unsigned int), 0644, NULL,
++       &proc_dointvec_jiffies},
++      {NET_IPV4_NF_CONNTRACK_ICMP_TIMEOUT, "ip_conntrack_icmp_timeout",
++       &ip_ct_icmp_timeout, sizeof(unsigned int), 0644, NULL,
++       &proc_dointvec_jiffies},
++      {NET_IPV4_NF_CONNTRACK_GENERIC_TIMEOUT, "ip_conntrack_generic_timeout",
++       &ip_ct_generic_timeout, sizeof(unsigned int), 0644, NULL,
++       &proc_dointvec_jiffies},
++      {0}
++};
++
++#define NET_IP_CONNTRACK_MAX 2089
++
++static ctl_table ip_ct_netfilter_table[] = {
++      {NET_IPV4_NETFILTER, "netfilter", NULL, 0, 0555, ip_ct_sysctl_table, 0, 0, 0, 0, 0},
++      {NET_IP_CONNTRACK_MAX, "ip_conntrack_max",
++       &ip_conntrack_max, sizeof(int), 0644, NULL,
++       &proc_dointvec},
++      {0}
++};
++
++static ctl_table ip_ct_ipv4_table[] = {
++      {NET_IPV4, "ipv4", NULL, 0, 0555, ip_ct_netfilter_table, 0, 0, 0, 0, 0},
++      {0}
++};
++
++static ctl_table ip_ct_net_table[] = {
++      {CTL_NET, "net", NULL, 0, 0555, ip_ct_ipv4_table, 0, 0, 0, 0, 0},
++      {0}
++};
++#endif
+ static int init_or_cleanup(int init)
+ {
+       struct proc_dir_entry *proc;
+@@ -291,10 +387,20 @@ static int init_or_cleanup(int init)
+               printk("ip_conntrack: can't register local in hook.\n");
+               goto cleanup_inoutandlocalops;
+       }
++#ifdef CONFIG_SYSCTL
++      ip_ct_sysctl_header = register_sysctl_table(ip_ct_net_table, 0);
++      if (ip_ct_sysctl_header == NULL) {
++              printk("ip_conntrack: can't register to sysctl.\n");
++              goto cleanup;
++      }
++#endif
+       return ret;
+  cleanup:
++#ifdef CONFIG_SYSCTL
++      unregister_sysctl_table(ip_ct_sysctl_header);
++#endif
+       nf_unregister_hook(&ip_conntrack_local_in_ops);
+  cleanup_inoutandlocalops:
+       nf_unregister_hook(&ip_conntrack_out_ops);
+--- linux-2.6.0-test6/net/ipv4/netfilter/ip_nat_core.c 2003-09-08 13:58:59.000000000 -0700
++++ 25/net/ipv4/netfilter/ip_nat_core.c        2003-10-05 00:33:25.000000000 -0700
+@@ -516,12 +516,14 @@ ip_nat_setup_info(struct ip_conntrack *c
+       struct ip_conntrack_tuple new_tuple, inv_tuple, reply;
+       struct ip_conntrack_tuple orig_tp;
+       struct ip_nat_info *info = &conntrack->nat.info;
++      int in_hashes = info->initialized;
+       MUST_BE_WRITE_LOCKED(&ip_nat_lock);
+       IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING
+                    || hooknum == NF_IP_POST_ROUTING
+                    || hooknum == NF_IP_LOCAL_OUT);
+       IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS);
++      IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
+       /* What we've got will look like inverse of reply. Normally
+          this is what is in the conntrack, except for prior
+@@ -638,6 +640,14 @@ ip_nat_setup_info(struct ip_conntrack *c
+       /* It's done. */
+       info->initialized |= (1 << HOOK2MANIP(hooknum));
++
++      if (in_hashes) {
++              IP_NF_ASSERT(info->bysource.conntrack);
++              replace_in_hashes(conntrack, info);
++      } else {
++              place_in_hashes(conntrack, info);
++      }
++
+       return NF_ACCEPT;
+ }
+@@ -761,11 +771,6 @@ do_bindings(struct ip_conntrack *ct,
+       enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
+       int proto = (*pskb)->nh.iph->protocol;
+-      /* Skip everything and don't call helpers if there are no
+-       * manips for this connection */
+-      if (info->num_manips == 0)
+-              return NF_ACCEPT;
+-
+       /* Need nat lock to protect against modification, but neither
+          conntrack (referenced) and helper (deleted with
+          synchronize_bh()) can vanish. */
+--- linux-2.6.0-test6/net/ipv4/netfilter/ip_nat_helper.c       2003-09-08 13:58:59.000000000 -0700
++++ 25/net/ipv4/netfilter/ip_nat_helper.c      2003-10-05 00:33:25.000000000 -0700
+@@ -122,7 +122,6 @@ static void mangle_contents(struct sk_bu
+       /* fix IP hdr checksum information */
+       skb->nh.iph->tot_len = htons(skb->len);
+       ip_send_check(skb->nh.iph);
+-      skb->csum = csum_partial(data, skb->len - dataoff, 0);
+ }
+ /* Unusual, but possible case. */
+@@ -167,6 +166,7 @@ ip_nat_mangle_tcp_packet(struct sk_buff 
+ {
+       struct iphdr *iph;
+       struct tcphdr *tcph;
++      int datalen;
+       if (!skb_ip_make_writable(pskb, (*pskb)->len))
+               return 0;
+@@ -184,11 +184,11 @@ ip_nat_mangle_tcp_packet(struct sk_buff 
+       mangle_contents(*pskb, iph->ihl*4 + tcph->doff*4,
+                       match_offset, match_len, rep_buffer, rep_len);
++      datalen = (*pskb)->len - iph->ihl*4;
+       tcph->check = 0;
+-      tcph->check = tcp_v4_check(tcph, (*pskb)->len - iph->ihl*4,
+-                                 iph->saddr, iph->daddr,
+-                                 csum_partial((char *)tcph, tcph->doff*4,
+-                                              (*pskb)->csum));
++      tcph->check = tcp_v4_check(tcph, datalen, iph->saddr, iph->daddr,
++                                 csum_partial((char *)tcph, datalen, 0));
++
+       adjust_tcp_sequence(ntohl(tcph->seq),
+                           (int)rep_len - (int)match_len,
+                           ct, ctinfo);
+@@ -216,7 +216,12 @@ ip_nat_mangle_udp_packet(struct sk_buff 
+ {
+       struct iphdr *iph;
+       struct udphdr *udph;
+-      int need_csum = ((*pskb)->csum != 0);
++
++      /* UDP helpers might accidentally mangle the wrong packet */
++      iph = (*pskb)->nh.iph;
++      if ((*pskb)->len < iph->ihl*4 + sizeof(*udph) + 
++                             match_offset + match_len)
++              return 0;
+       if (!skb_ip_make_writable(pskb, (*pskb)->len))
+               return 0;
+@@ -235,17 +240,15 @@ ip_nat_mangle_udp_packet(struct sk_buff 
+       udph->len = htons((*pskb)->len - iph->ihl*4);
+       /* fix udp checksum if udp checksum was previously calculated */
+-      if (need_csum) {
++      if (udph->check) {
++              int datalen = (*pskb)->len - iph->ihl * 4;
+               udph->check = 0;
+-              udph->check
+-                      = csum_tcpudp_magic(iph->saddr, iph->daddr,
+-                                          (*pskb)->len - iph->ihl*4,
+-                                          IPPROTO_UDP,
+-                                          csum_partial((char *)udph,
+-                                                       sizeof(struct udphdr),
+-                                                       (*pskb)->csum));
+-      } else
+-              (*pskb)->csum = 0;
++              udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
++                                              datalen, IPPROTO_UDP,
++                                              csum_partial((char *)udph,
++                                                           datalen, 0));
++      }
++
+       return 1;
+ }
+--- linux-2.6.0-test6/net/ipv4/netfilter/ip_nat_rule.c 2003-09-08 13:58:59.000000000 -0700
++++ 25/net/ipv4/netfilter/ip_nat_rule.c        2003-10-05 00:33:25.000000000 -0700
+@@ -233,7 +233,7 @@ static int ipt_dnat_checkentry(const cha
+       return 1;
+ }
+-static inline unsigned int
++inline unsigned int
+ alloc_null_binding(struct ip_conntrack *conntrack,
+                  struct ip_nat_info *info,
+                  unsigned int hooknum)
+--- linux-2.6.0-test6/net/ipv4/netfilter/ip_nat_standalone.c   2003-09-08 13:58:59.000000000 -0700
++++ 25/net/ipv4/netfilter/ip_nat_standalone.c  2003-10-05 00:33:25.000000000 -0700
+@@ -119,7 +119,6 @@ ip_nat_fn(unsigned int hooknum,
+               /* Seen it before?  This can happen for loopback, retrans,
+                  or local packets.. */
+               if (!(info->initialized & (1 << maniptype))) {
+-                      int in_hashes = info->initialized;
+                       unsigned int ret;
+                       if (ct->master
+@@ -130,9 +129,10 @@ ip_nat_fn(unsigned int hooknum,
+                       } else {
+ #ifdef CONFIG_IP_NF_NAT_LOCAL
+                               /* LOCAL_IN hook doesn't have a chain!  */
+-                              if (hooknum == NF_IP_LOCAL_IN) {
+-                                      ret = NF_ACCEPT;
+-                              } else
++                              if (hooknum == NF_IP_LOCAL_IN)
++                                      ret = alloc_null_binding(ct, info,
++                                                               hooknum);
++                              else
+ #endif
+                               ret = ip_nat_rule_find(pskb, hooknum, in, out,
+                                                      ct, info);
+@@ -142,13 +142,6 @@ ip_nat_fn(unsigned int hooknum,
+                               WRITE_UNLOCK(&ip_nat_lock);
+                               return ret;
+                       }
+-
+-                      if (in_hashes) {
+-                              IP_NF_ASSERT(info->bysource.conntrack);
+-                              replace_in_hashes(ct, info);
+-                      } else {
+-                              place_in_hashes(ct, info);
+-                      }
+               } else
+                       DEBUGP("Already setup manip %s for ct %p\n",
+                              maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST",
+@@ -199,6 +192,7 @@ ip_nat_out(unsigned int hooknum,
+       return ip_nat_fn(hooknum, pskb, in, out, okfn);
+ }
++#ifdef CONFIG_IP_NF_NAT_LOCAL
+ static unsigned int
+ ip_nat_local_fn(unsigned int hooknum,
+               struct sk_buff **pskb,
+@@ -224,6 +218,7 @@ ip_nat_local_fn(unsigned int hooknum,
+               return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP;
+       return ret;
+ }
++#endif
+ /* We must be after connection tracking and before packet filtering. */
+@@ -245,6 +240,7 @@ static struct nf_hook_ops ip_nat_out_ops
+       .priority       = NF_IP_PRI_NAT_SRC,
+ };
++#ifdef CONFIG_IP_NF_NAT_LOCAL
+ /* Before packet filtering, change destination */
+ static struct nf_hook_ops ip_nat_local_out_ops = {
+       .hook           = ip_nat_local_fn,
+@@ -254,7 +250,7 @@ static struct nf_hook_ops ip_nat_local_o
+       .priority       = NF_IP_PRI_NAT_DST,
+ };
+-#ifdef CONFIG_IP_NF_NAT_LOCAL
++/* After packet filtering, change source for reply packets of LOCAL_OUT DNAT */
+ static struct nf_hook_ops ip_nat_local_in_ops = {
+       .hook           = ip_nat_fn,
+       .owner          = THIS_MODULE,
+@@ -324,12 +320,12 @@ static int init_or_cleanup(int init)
+               printk("ip_nat_init: can't register out hook.\n");
+               goto cleanup_inops;
+       }
++#ifdef CONFIG_IP_NF_NAT_LOCAL
+       ret = nf_register_hook(&ip_nat_local_out_ops);
+       if (ret < 0) {
+               printk("ip_nat_init: can't register local out hook.\n");
+               goto cleanup_outops;
+       }
+-#ifdef CONFIG_IP_NF_NAT_LOCAL
+       ret = nf_register_hook(&ip_nat_local_in_ops);
+       if (ret < 0) {
+               printk("ip_nat_init: can't register local in hook.\n");
+@@ -342,9 +338,9 @@ static int init_or_cleanup(int init)
+ #ifdef CONFIG_IP_NF_NAT_LOCAL
+       nf_unregister_hook(&ip_nat_local_in_ops);
+  cleanup_localoutops:
+-#endif
+       nf_unregister_hook(&ip_nat_local_out_ops);
+  cleanup_outops:
++#endif
+       nf_unregister_hook(&ip_nat_out_ops);
+  cleanup_inops:
+       nf_unregister_hook(&ip_nat_in_ops);
+--- linux-2.6.0-test6/net/ipv4/netfilter/ipt_owner.c   2003-09-08 13:58:59.000000000 -0700
++++ 25/net/ipv4/netfilter/ipt_owner.c  2003-10-05 00:36:15.000000000 -0700
+@@ -90,7 +90,7 @@ match_sid(const struct sk_buff *skb, pid
+       read_lock(&tasklist_lock);
+       do_each_thread(g, p) {
+               struct files_struct *files;
+-              if (p->session != sid)
++              if (process_session(p) != sid)
+                       continue;
+               task_lock(p);
+--- linux-2.6.0-test6/net/ipv4/netfilter/ipt_REJECT.c  2003-09-27 18:57:47.000000000 -0700
++++ 25/net/ipv4/netfilter/ipt_REJECT.c 2003-10-05 00:33:25.000000000 -0700
+@@ -40,16 +40,17 @@ static void connection_attach(struct sk_
+       }
+ }
+-static inline struct rtable *route_reverse(struct sk_buff *skb, int local)
++static inline struct rtable *route_reverse(struct sk_buff *skb, int hook)
+ {
+       struct iphdr *iph = skb->nh.iph;
+       struct dst_entry *odst;
+       struct flowi fl = {};
+       struct rtable *rt;
+-      if (local) {
++      if (hook != NF_IP_FORWARD) {
+               fl.nl_u.ip4_u.daddr = iph->saddr;
+-              fl.nl_u.ip4_u.saddr = iph->daddr;
++              if (hook == NF_IP_LOCAL_IN)
++                      fl.nl_u.ip4_u.saddr = iph->daddr;
+               fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
+               if (ip_route_output_key(&rt, &fl) != 0)
+@@ -81,7 +82,7 @@ static inline struct rtable *route_rever
+ }
+ /* Send RST reply */
+-static void send_reset(struct sk_buff *oldskb, int local)
++static void send_reset(struct sk_buff *oldskb, int hook)
+ {
+       struct sk_buff *nskb;
+       struct tcphdr otcph, *tcph;
+@@ -104,7 +105,7 @@ static void send_reset(struct sk_buff *o
+               return;
+       /* FIXME: Check checksum --RR */
+-      if ((rt = route_reverse(oldskb, local)) == NULL)
++      if ((rt = route_reverse(oldskb, hook)) == NULL)
+               return;
+       hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;
+@@ -390,7 +391,7 @@ static unsigned int reject(struct sk_buf
+               send_unreach(*pskb, ICMP_PKT_FILTERED);
+               break;
+       case IPT_TCP_RESET:
+-              send_reset(*pskb, hooknum == NF_IP_LOCAL_IN);
++              send_reset(*pskb, hooknum);
+       case IPT_ICMP_ECHOREPLY:
+               /* Doesn't happen. */
+               break;
+--- linux-2.6.0-test6/net/ipv4/protocol.c      2003-06-14 12:17:58.000000000 -0700
++++ 25/net/ipv4/protocol.c     2003-10-05 00:33:25.000000000 -0700
+@@ -27,6 +27,7 @@
+ #include <asm/uaccess.h>
+ #include <asm/system.h>
++#include <linux/module.h>
+ #include <linux/types.h>
+ #include <linux/kernel.h>
+ #include <linux/sched.h>
+@@ -95,3 +96,6 @@ int inet_del_protocol(struct inet_protoc
+       return ret;
+ }
++
++EXPORT_SYMBOL(inet_add_protocol);
++EXPORT_SYMBOL(inet_del_protocol);
+--- linux-2.6.0-test6/net/ipv4/route.c 2003-09-27 18:57:47.000000000 -0700
++++ 25/net/ipv4/route.c        2003-10-05 00:33:25.000000000 -0700
+@@ -62,6 +62,7 @@
+  */
+ #include <linux/config.h>
++#include <linux/module.h>
+ #include <asm/uaccess.h>
+ #include <asm/system.h>
+ #include <asm/bitops.h>
+@@ -2823,3 +2824,7 @@ out_enomem1:
+       rc = -ENOMEM;
+       goto out;
+ }
++
++EXPORT_SYMBOL(__ip_select_ident);
++EXPORT_SYMBOL(ip_route_input);
++EXPORT_SYMBOL(ip_route_output_key);
+--- linux-2.6.0-test6/net/ipv4/sysctl_net_ipv4.c       2003-08-22 19:23:42.000000000 -0700
++++ 25/net/ipv4/sysctl_net_ipv4.c      2003-10-05 00:33:25.000000000 -0700
+@@ -8,6 +8,7 @@
+  */
+ #include <linux/mm.h>
++#include <linux/module.h>
+ #include <linux/sysctl.h>
+ #include <linux/config.h>
+ #include <net/snmp.h>
+@@ -587,3 +588,5 @@ ctl_table ipv4_table[] = {
+ };
+ #endif /* CONFIG_SYSCTL */
++
++EXPORT_SYMBOL(ipv4_config);
+--- linux-2.6.0-test6/net/ipv4/tcp.c   2003-06-22 12:04:45.000000000 -0700
++++ 25/net/ipv4/tcp.c  2003-10-05 00:33:25.000000000 -0700
+@@ -248,6 +248,7 @@
+  */
+ #include <linux/config.h>
++#include <linux/module.h>
+ #include <linux/types.h>
+ #include <linux/fcntl.h>
+ #include <linux/poll.h>
+@@ -2682,3 +2683,26 @@ void __init tcp_init(void)
+       tcpdiag_init();
+ }
++
++EXPORT_SYMBOL(__tcp_mem_reclaim);
++EXPORT_SYMBOL(sysctl_tcp_rmem);
++EXPORT_SYMBOL(sysctl_tcp_wmem);
++EXPORT_SYMBOL(tcp_accept);
++EXPORT_SYMBOL(tcp_close);
++EXPORT_SYMBOL(tcp_close_state);
++EXPORT_SYMBOL(tcp_destroy_sock);
++EXPORT_SYMBOL(tcp_disconnect);
++EXPORT_SYMBOL(tcp_getsockopt);
++EXPORT_SYMBOL(tcp_ioctl);
++EXPORT_SYMBOL(tcp_openreq_cachep);
++EXPORT_SYMBOL(tcp_poll);
++EXPORT_SYMBOL(tcp_read_sock);
++EXPORT_SYMBOL(tcp_recvmsg);
++EXPORT_SYMBOL(tcp_sendmsg);
++EXPORT_SYMBOL(tcp_sendpage);
++EXPORT_SYMBOL(tcp_setsockopt);
++EXPORT_SYMBOL(tcp_shutdown);
++EXPORT_SYMBOL(tcp_sockets_allocated);
++EXPORT_SYMBOL(tcp_statistics);
++EXPORT_SYMBOL(tcp_timewait_cachep);
++EXPORT_SYMBOL(tcp_write_space);
+--- linux-2.6.0-test6/net/ipv4/tcp_input.c     2003-07-27 12:14:40.000000000 -0700
++++ 25/net/ipv4/tcp_input.c    2003-10-05 00:33:25.000000000 -0700
+@@ -65,6 +65,7 @@
+ #include <linux/config.h>
+ #include <linux/mm.h>
++#include <linux/module.h>
+ #include <linux/sysctl.h>
+ #include <net/tcp.h>
+ #include <net/inet_common.h>
+@@ -4089,3 +4090,10 @@ discard:
+       }
+       return 0;
+ }
++
++EXPORT_SYMBOL(sysctl_tcp_ecn);
++EXPORT_SYMBOL(sysctl_tcp_reordering);
++EXPORT_SYMBOL(tcp_cwnd_application_limited);
++EXPORT_SYMBOL(tcp_parse_options);
++EXPORT_SYMBOL(tcp_rcv_established);
++EXPORT_SYMBOL(tcp_rcv_state_process);
+--- linux-2.6.0-test6/net/ipv4/tcp_ipv4.c      2003-09-27 18:57:47.000000000 -0700
++++ 25/net/ipv4/tcp_ipv4.c     2003-10-05 00:33:25.000000000 -0700
+@@ -56,6 +56,7 @@
+ #include <linux/types.h>
+ #include <linux/fcntl.h>
++#include <linux/module.h>
+ #include <linux/random.h>
+ #include <linux/cache.h>
+ #include <linux/jhash.h>
+@@ -2644,3 +2645,32 @@ void __init tcp_v4_init(struct net_proto
+        */
+       tcp_socket->sk->sk_prot->unhash(tcp_socket->sk);
+ }
++
++EXPORT_SYMBOL(ipv4_specific);
++EXPORT_SYMBOL(tcp_bind_hash);
++EXPORT_SYMBOL(tcp_bucket_create);
++EXPORT_SYMBOL(tcp_hashinfo);
++EXPORT_SYMBOL(tcp_inherit_port);
++EXPORT_SYMBOL(tcp_listen_wlock);
++EXPORT_SYMBOL(tcp_port_rover);
++EXPORT_SYMBOL(tcp_prot);
++EXPORT_SYMBOL(tcp_put_port);
++EXPORT_SYMBOL(tcp_unhash);
++EXPORT_SYMBOL(tcp_v4_conn_request);
++EXPORT_SYMBOL(tcp_v4_connect);
++EXPORT_SYMBOL(tcp_v4_do_rcv);
++EXPORT_SYMBOL(tcp_v4_lookup_listener);
++EXPORT_SYMBOL(tcp_v4_rebuild_header);
++EXPORT_SYMBOL(tcp_v4_remember_stamp);
++EXPORT_SYMBOL(tcp_v4_send_check);
++EXPORT_SYMBOL(tcp_v4_syn_recv_sock);
++
++#ifdef CONFIG_PROC_FS
++EXPORT_SYMBOL(tcp_proc_register);
++EXPORT_SYMBOL(tcp_proc_unregister);
++#endif
++#ifdef CONFIG_SYSCTL
++EXPORT_SYMBOL(sysctl_local_port_range);
++EXPORT_SYMBOL(sysctl_max_syn_backlog);
++EXPORT_SYMBOL(sysctl_tcp_low_latency);
++#endif
+--- linux-2.6.0-test6/net/ipv4/tcp_minisocks.c 2003-07-02 14:53:18.000000000 -0700
++++ 25/net/ipv4/tcp_minisocks.c        2003-10-05 00:33:25.000000000 -0700
+@@ -22,6 +22,7 @@
+ #include <linux/config.h>
+ #include <linux/mm.h>
++#include <linux/module.h>
+ #include <linux/sysctl.h>
+ #include <linux/workqueue.h>
+ #include <net/tcp.h>
+@@ -1053,3 +1054,13 @@ int tcp_child_process(struct sock *paren
+       sock_put(child);
+       return ret;
+ }
++
++EXPORT_SYMBOL(tcp_check_req);
++EXPORT_SYMBOL(tcp_child_process);
++EXPORT_SYMBOL(tcp_create_openreq_child);
++EXPORT_SYMBOL(tcp_timewait_state_process);
++EXPORT_SYMBOL(tcp_tw_deschedule);
++
++#ifdef CONFIG_SYSCTL
++EXPORT_SYMBOL(sysctl_tcp_tw_recycle);
++#endif
+--- linux-2.6.0-test6/net/ipv4/tcp_output.c    2003-07-02 14:53:18.000000000 -0700
++++ 25/net/ipv4/tcp_output.c   2003-10-05 00:33:25.000000000 -0700
+@@ -39,6 +39,7 @@
+ #include <net/tcp.h>
+ #include <linux/compiler.h>
++#include <linux/module.h>
+ #include <linux/smp_lock.h>
+ /* People can turn this off for buggy TCP's found in printers etc. */
+@@ -1542,3 +1543,14 @@ void tcp_send_probe0(struct sock *sk)
+                                     min(tp->rto << tp->backoff, TCP_RESOURCE_PROBE_INTERVAL));
+       }
+ }
++
++EXPORT_SYMBOL(tcp_acceptable_seq);
++EXPORT_SYMBOL(tcp_connect);
++EXPORT_SYMBOL(tcp_connect_init);
++EXPORT_SYMBOL(tcp_make_synack);
++EXPORT_SYMBOL(tcp_send_synack);
++EXPORT_SYMBOL(tcp_simple_retransmit);
++EXPORT_SYMBOL(tcp_sync_mss);
++EXPORT_SYMBOL(tcp_transmit_skb);
++EXPORT_SYMBOL(tcp_write_wakeup);
++EXPORT_SYMBOL(tcp_write_xmit);
+--- linux-2.6.0-test6/net/ipv4/tcp_timer.c     2003-06-16 22:32:21.000000000 -0700
++++ 25/net/ipv4/tcp_timer.c    2003-10-05 00:33:25.000000000 -0700
+@@ -20,6 +20,7 @@
+  *            Jorge Cwik, <jorge@laser.satlink.net>
+  */
++#include <linux/module.h>
+ #include <net/tcp.h>
+ int sysctl_tcp_syn_retries = TCP_SYN_RETRIES; 
+@@ -656,3 +657,8 @@ out:
+       bh_unlock_sock(sk);
+       sock_put(sk);
+ }
++
++EXPORT_SYMBOL(tcp_clear_xmit_timers);
++EXPORT_SYMBOL(tcp_delete_keepalive_timer);
++EXPORT_SYMBOL(tcp_init_xmit_timers);
++EXPORT_SYMBOL(tcp_reset_keepalive_timer);
+--- linux-2.6.0-test6/net/ipv4/udp.c   2003-09-27 18:57:47.000000000 -0700
++++ 25/net/ipv4/udp.c  2003-10-05 00:33:25.000000000 -0700
+@@ -83,6 +83,7 @@
+ #include <asm/ioctls.h>
+ #include <linux/types.h>
+ #include <linux/fcntl.h>
++#include <linux/module.h>
+ #include <linux/socket.h>
+ #include <linux/sockios.h>
+ #include <linux/in.h>
+@@ -1532,3 +1533,17 @@ void udp4_proc_exit(void)
+       udp_proc_unregister(&udp4_seq_afinfo);
+ }
+ #endif /* CONFIG_PROC_FS */
++
++EXPORT_SYMBOL(udp_connect);
++EXPORT_SYMBOL(udp_disconnect);
++EXPORT_SYMBOL(udp_hash);
++EXPORT_SYMBOL(udp_hash_lock);
++EXPORT_SYMBOL(udp_ioctl);
++EXPORT_SYMBOL(udp_port_rover);
++EXPORT_SYMBOL(udp_prot);
++EXPORT_SYMBOL(udp_sendmsg);
++
++#ifdef CONFIG_PROC_FS
++EXPORT_SYMBOL(udp_proc_register);
++EXPORT_SYMBOL(udp_proc_unregister);
++#endif
+--- linux-2.6.0-test6/net/ipv4/utils.c 2003-07-02 14:53:18.000000000 -0700
++++ 25/net/ipv4/utils.c        2003-10-05 00:33:25.000000000 -0700
+@@ -21,6 +21,7 @@
+  *            2 of the License, or (at your option) any later version.
+  */
++#include <linux/module.h>
+ #include <linux/types.h>
+ #include <asm/byteorder.h>
+@@ -55,3 +56,4 @@ __u32 in_aton(const char *str)
+       return(htonl(l));
+ }
++EXPORT_SYMBOL(in_aton);
+--- linux-2.6.0-test6/net/ipv4/xfrm4_tunnel.c  2003-08-22 19:23:42.000000000 -0700
++++ 25/net/ipv4/xfrm4_tunnel.c 2003-10-05 00:33:25.000000000 -0700
+@@ -169,6 +169,7 @@ static struct xfrm_type ipip_type = {
+ static struct inet_protocol ipip_protocol = {
+       .handler        =       ipip_rcv,
+       .err_handler    =       ipip_err,
++      .no_policy      =       1,
+ };
+ static int __init ipip_init(void)
+--- linux-2.6.0-test6/net/ipv6/netfilter/ip6t_ipv6header.c     2003-06-14 12:18:51.000000000 -0700
++++ 25/net/ipv6/netfilter/ip6t_ipv6header.c    2003-10-05 00:33:25.000000000 -0700
+@@ -126,18 +126,11 @@ ipv6header_checkentry(const char *tablen
+       return 1;
+ }
+-static void
+-ipv6header_destroy(void *matchinfo,
+-                 unsigned int matchinfosize)
+-{
+-      return;
+-}
+-
+ static struct ip6t_match ip6t_ipv6header_match = {
+       .name           = "ipv6header",
+       .match          = &ipv6header_match,
+       .checkentry     = &ipv6header_checkentry,
+-      .destroy        = &ipv6header_destroy,
++      .destroy        = NULL,
+       .me             = THIS_MODULE,
+ };
+--- linux-2.6.0-test6/net/ipv6/netfilter/ip6t_owner.c  2003-06-14 12:18:30.000000000 -0700
++++ 25/net/ipv6/netfilter/ip6t_owner.c 2003-10-05 00:36:15.000000000 -0700
+@@ -56,7 +56,7 @@ match_sid(const struct sk_buff *skb, pid
+       read_lock(&tasklist_lock);
+       do_each_thread(g, p) {
+               struct files_struct *files;
+-              if (p->session != sid)
++              if (process_session(p) != sid)
+                       continue;
+               task_lock(p);
+--- linux-2.6.0-test6/net/irda/irda_device.c   2003-09-08 13:58:59.000000000 -0700
++++ 25/net/irda/irda_device.c  2003-10-05 00:33:25.000000000 -0700
+@@ -85,7 +85,7 @@ static void irda_task_timer_expired(void
+ int __init irda_device_init( void)
+ {
+-      dongles = hashbin_new(HB_LOCK);
++      dongles = hashbin_new(HB_NOLOCK);
+       if (dongles == NULL) {
+               printk(KERN_WARNING "IrDA: Can't allocate dongles hashbin!\n");
+               return -ENOMEM;
+@@ -109,7 +109,9 @@ void __exit irda_device_cleanup(void)
+       IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+       hashbin_delete(tasks, (FREE_FUNC) __irda_task_delete);
++      spin_lock(&dongles->hb_spinlock);
+       hashbin_delete(dongles, NULL);
++      spin_unlock(&dongles->hb_spinlock);
+ }
+ /*
+@@ -378,8 +380,6 @@ void irda_device_setup(struct net_device
+         dev->hard_header_len = 0;
+         dev->addr_len        = 0;
+-      dev->destructor      = free_netdev;
+-
+         dev->type            = ARPHRD_IRDA;
+         dev->tx_queue_len    = 8; /* Window size + 1 s-frame */
+@@ -390,6 +390,17 @@ void irda_device_setup(struct net_device
+ }
+ /*
++ * Funciton  alloc_irdadev 
++ *    Allocates and sets up an IRDA device in a manner similar to
++ *    alloc_etherdev.
++ */
++struct net_device *alloc_irdadev(int sizeof_priv)
++{
++      return alloc_netdev(sizeof_priv, "irda%d", irda_device_setup);
++}
++
++
++/*
+  * Function irda_device_txqueue_empty (dev)
+  *
+  *    Check if there is still some frames in the transmit queue for this
+@@ -415,25 +426,34 @@ int irda_device_txqueue_empty(struct net
+ dongle_t *irda_device_dongle_init(struct net_device *dev, int type)
+ {
+       struct dongle_reg *reg;
+-      dongle_t *dongle;
++      dongle_t *dongle = NULL;
++
++      might_sleep();
+-      ASSERT(dev != NULL, return NULL;);
++      spin_lock(&dongles->hb_spinlock);
++      reg = hashbin_find(dongles, type, NULL);
+ #ifdef CONFIG_KMOD
+-      ASSERT(!in_interrupt(), return NULL;);
+       /* Try to load the module needed */
+-      request_module("irda-dongle-%d", type);
++      if (!reg && capable(CAP_SYS_MODULE)) {
++              spin_unlock(&dongles->hb_spinlock);
++      
++              request_module("irda-dongle-%d", type);
++              
++              spin_lock(&dongles->hb_spinlock);
++              reg = hashbin_find(dongles, type, NULL);
++      }
+ #endif
+-      if (!(reg = hashbin_lock_find(dongles, type, NULL))) {
+-              ERROR("IrDA: Unable to find requested dongle\n");
+-              return NULL;
++      if (!reg || !try_module_get(reg->owner) ) {
++              ERROR("IrDA: Unable to find requested dongle type %x\n", type);
++              goto out;
+       }
+       /* Allocate dongle info for this instance */
+       dongle = kmalloc(sizeof(dongle_t), GFP_KERNEL);
+       if (!dongle)
+-              return NULL;
++              goto out;
+       memset(dongle, 0, sizeof(dongle_t));
+@@ -441,6 +461,8 @@ dongle_t *irda_device_dongle_init(struct
+       dongle->issue = reg;
+       dongle->dev = dev;
++ out:
++      spin_unlock(&dongles->hb_spinlock);
+       return dongle;
+ }
+@@ -452,7 +474,7 @@ int irda_device_dongle_cleanup(dongle_t 
+       ASSERT(dongle != NULL, return -1;);
+       dongle->issue->close(dongle);
+-
++      module_put(dongle->issue->owner);
+       kfree(dongle);
+       return 0;
+@@ -463,14 +485,16 @@ int irda_device_dongle_cleanup(dongle_t 
+  */
+ int irda_device_register_dongle(struct dongle_reg *new)
+ {
++      spin_lock(&dongles->hb_spinlock);
+       /* Check if this dongle has been registered before */
+-      if (hashbin_lock_find(dongles, new->type, NULL)) {
+-              MESSAGE("%s: Dongle already registered\n", __FUNCTION__);
+-                return 0;
+-        }
+-
+-      /* Insert IrDA dongle into hashbin */
+-      hashbin_insert(dongles, (irda_queue_t *) new, new->type, NULL);
++      if (hashbin_find(dongles, new->type, NULL)) {
++              MESSAGE("%s: Dongle type %x already registered\n", 
++                      __FUNCTION__, new->type);
++        } else {
++              /* Insert IrDA dongle into hashbin */
++              hashbin_insert(dongles, (irda_queue_t *) new, new->type, NULL);
++      }
++      spin_unlock(&dongles->hb_spinlock);
+         return 0;
+ }
+@@ -485,11 +509,11 @@ void irda_device_unregister_dongle(struc
+ {
+       struct dongle *node;
++      spin_lock(&dongles->hb_spinlock);
+       node = hashbin_remove(dongles, dongle->type, NULL);
+-      if (!node) {
++      if (!node) 
+               ERROR("%s: dongle not found!\n", __FUNCTION__);
+-              return;
+-      }
++      spin_unlock(&dongles->hb_spinlock);
+ }
+ /*
+--- linux-2.6.0-test6/net/irda/irsyms.c        2003-09-27 18:57:47.000000000 -0700
++++ 25/net/irda/irsyms.c       2003-10-05 00:33:25.000000000 -0700
+@@ -150,6 +150,7 @@ EXPORT_SYMBOL(irlap_close);
+ EXPORT_SYMBOL(irda_init_max_qos_capabilies);
+ EXPORT_SYMBOL(irda_qos_bits_to_value);
+ EXPORT_SYMBOL(irda_device_setup);
++EXPORT_SYMBOL(alloc_irdadev);
+ EXPORT_SYMBOL(irda_device_set_media_busy);
+ EXPORT_SYMBOL(irda_device_txqueue_empty);
+--- linux-2.6.0-test6/net/Makefile     2003-06-14 12:18:08.000000000 -0700
++++ 25/net/Makefile    2003-10-05 00:33:25.000000000 -0700
+@@ -40,6 +40,5 @@ obj-$(CONFIG_VLAN_8021Q)     += 8021q/
+ obj-$(CONFIG_IP_SCTP)         += sctp/
+ ifeq ($(CONFIG_NET),y)
+-obj-$(CONFIG_MODULES)         += netsyms.o
+ obj-$(CONFIG_SYSCTL)          += sysctl_net.o
+ endif
+--- linux-2.6.0-test6/net/netlink/af_netlink.c 2003-09-27 18:57:47.000000000 -0700
++++ 25/net/netlink/af_netlink.c        2003-10-05 00:33:25.000000000 -0700
+@@ -1133,4 +1133,22 @@ core_initcall(netlink_proto_init);
+ module_exit(netlink_proto_exit);
+ MODULE_LICENSE("GPL");
++
+ MODULE_ALIAS_NETPROTO(PF_NETLINK);
++
++EXPORT_SYMBOL(netlink_ack);
++EXPORT_SYMBOL(netlink_broadcast);
++EXPORT_SYMBOL(netlink_broadcast_deliver);
++EXPORT_SYMBOL(netlink_dump_start);
++EXPORT_SYMBOL(netlink_kernel_create);
++EXPORT_SYMBOL(netlink_register_notifier);
++EXPORT_SYMBOL(netlink_set_err);
++EXPORT_SYMBOL(netlink_set_nonroot);
++EXPORT_SYMBOL(netlink_unicast);
++EXPORT_SYMBOL(netlink_unregister_notifier);
++
++#if defined(CONFIG_NETLINK_DEV) || defined(CONFIG_NETLINK_DEV_MODULE)
++EXPORT_SYMBOL(netlink_attach);
++EXPORT_SYMBOL(netlink_detach);
++EXPORT_SYMBOL(netlink_post);
++#endif
+--- linux-2.6.0-test6/net/netsyms.c    2003-09-27 18:57:47.000000000 -0700
++++ /dev/null  2002-08-30 16:31:37.000000000 -0700
+@@ -1,640 +0,0 @@
+-/*
+- *  linux/net/netsyms.c
+- *
+- *  Symbol table for the linux networking subsystem. Moved here to
+- *  make life simpler in ksyms.c.
+- */
+-
+-#include <linux/config.h>
+-#include <linux/module.h>
+-
+-#include <linux/types.h>
+-#include <linux/net.h>
+-#include <linux/in.h>
+-#include <linux/netdevice.h>
+-#include <linux/inetdevice.h>
+-#include <linux/fddidevice.h>
+-#include <linux/trdevice.h>
+-#include <linux/fcdevice.h>
+-#include <linux/ioport.h>
+-#include <linux/tty.h>
+-#include <linux/ethtool.h>
+-#include <net/neighbour.h>
+-#include <net/snmp.h>
+-#include <net/dst.h>
+-#include <net/checksum.h>
+-#include <linux/etherdevice.h>
+-#include <net/route.h>
+-#ifdef CONFIG_HIPPI
+-#include <linux/hippidevice.h>
+-#endif
+-#include <net/pkt_sched.h>
+-#include <net/scm.h>
+-#include <linux/if_bridge.h>
+-#include <linux/if_vlan.h>
+-#include <linux/random.h>
+-#ifdef CONFIG_NET_DIVERT
+-#include <linux/divert.h>
+-#endif /* CONFIG_NET_DIVERT */
+-
+-#ifdef CONFIG_NET
+-extern __u32 sysctl_wmem_max;
+-extern __u32 sysctl_rmem_max;
+-#endif
+-
+-#ifdef CONFIG_INET
+-#include <linux/ip.h>
+-#include <net/protocol.h>
+-#include <net/arp.h>
+-#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
+-#include <net/atmclip.h>
+-#endif
+-#include <net/ip.h>
+-#include <net/udp.h>
+-#include <net/tcp.h>
+-#include <net/icmp.h>
+-#include <net/inet_common.h>
+-#include <linux/inet.h>
+-#include <linux/mroute.h>
+-#include <linux/igmp.h>
+-#if defined(CONFIG_INET_AH) || defined(CONFIG_INET_AH_MODULE) || defined(CONFIG_INET6_AH) || defined(CONFIG_INET6_AH_MODULE)
+-#include <net/ah.h>
+-#endif
+-#if defined(CONFIG_INET_ESP) || defined(CONFIG_INET_ESP_MODULE) || defined(CONFIG_INET6_ESP) || defined(CONFIG_INET6_ESP_MODULE)
+-#include <net/esp.h>
+-#endif
+-
+-extern struct net_proto_family inet_family_ops;
+-
+-#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) \
+-   || defined (CONFIG_IP_SCTP_MODULE)
+-#include <linux/in6.h>
+-#include <linux/icmpv6.h>
+-#include <net/ipv6.h>
+-#include <net/ndisc.h>
+-#include <net/transp_v6.h>
+-#include <net/addrconf.h>
+-
+-extern int sysctl_local_port_range[2];
+-extern int tcp_port_rover;
+-extern int udp_port_rover;
+-#endif
+-
+-#endif
+-
+-#include <linux/rtnetlink.h>
+-
+-#ifdef CONFIG_IPX_MODULE
+-extern struct datalink_proto   *make_EII_client(void);
+-extern struct datalink_proto   *make_8023_client(void);
+-extern void destroy_EII_client(struct datalink_proto *);
+-extern void destroy_8023_client(struct datalink_proto *);
+-#endif
+-
+-#ifdef CONFIG_ATALK_MODULE
+-#include <net/sock.h>
+-#endif
+-
+-#ifdef CONFIG_SYSCTL
+-extern int sysctl_max_syn_backlog;
+-#endif
+-
+-/* Skbuff symbols. */
+-EXPORT_SYMBOL(skb_over_panic);
+-EXPORT_SYMBOL(skb_under_panic);
+-
+-/* Socket layer registration */
+-EXPORT_SYMBOL(sock_register);
+-EXPORT_SYMBOL(sock_unregister);
+-
+-/* Socket locking */
+-EXPORT_SYMBOL(__lock_sock);
+-EXPORT_SYMBOL(__release_sock);
+-
+-/* Socket layer support routines */
+-EXPORT_SYMBOL(memcpy_fromiovec);
+-EXPORT_SYMBOL(memcpy_tokerneliovec);
+-EXPORT_SYMBOL(sock_create);
+-EXPORT_SYMBOL(sock_alloc);
+-EXPORT_SYMBOL(sock_release);
+-EXPORT_SYMBOL(sock_setsockopt);
+-EXPORT_SYMBOL(sock_getsockopt);
+-EXPORT_SYMBOL(sock_sendmsg);
+-EXPORT_SYMBOL(sock_recvmsg);
+-EXPORT_SYMBOL(sk_alloc);
+-EXPORT_SYMBOL(sk_free);
+-EXPORT_SYMBOL(sk_send_sigurg);
+-EXPORT_SYMBOL(sock_wake_async);
+-EXPORT_SYMBOL(sock_alloc_send_skb);
+-EXPORT_SYMBOL(sock_alloc_send_pskb);
+-EXPORT_SYMBOL(sock_init_data);
+-EXPORT_SYMBOL(sock_no_release);
+-EXPORT_SYMBOL(sock_no_bind);
+-EXPORT_SYMBOL(sock_no_connect);
+-EXPORT_SYMBOL(sock_no_socketpair);
+-EXPORT_SYMBOL(sock_no_accept);
+-EXPORT_SYMBOL(sock_no_getname);
+-EXPORT_SYMBOL(sock_no_poll);
+-EXPORT_SYMBOL(sock_no_ioctl);
+-EXPORT_SYMBOL(sock_no_listen);
+-EXPORT_SYMBOL(sock_no_shutdown);
+-EXPORT_SYMBOL(sock_no_getsockopt);
+-EXPORT_SYMBOL(sock_no_setsockopt);
+-EXPORT_SYMBOL(sock_no_sendmsg);
+-EXPORT_SYMBOL(sock_no_recvmsg);
+-EXPORT_SYMBOL(sock_no_mmap);
+-EXPORT_SYMBOL(sock_no_sendpage);
+-EXPORT_SYMBOL(sock_rfree);
+-EXPORT_SYMBOL(sock_wfree);
+-EXPORT_SYMBOL(sock_wmalloc);
+-EXPORT_SYMBOL(sock_rmalloc);
+-EXPORT_SYMBOL(__skb_linearize);
+-EXPORT_SYMBOL(skb_checksum);
+-EXPORT_SYMBOL(skb_checksum_help);
+-EXPORT_SYMBOL(skb_recv_datagram);
+-EXPORT_SYMBOL(skb_free_datagram);
+-EXPORT_SYMBOL(skb_copy_datagram);
+-EXPORT_SYMBOL(skb_copy_datagram_iovec);
+-EXPORT_SYMBOL(skb_copy_and_csum_datagram_iovec);
+-EXPORT_SYMBOL(skb_copy_bits);
+-EXPORT_SYMBOL(skb_copy_and_csum_bits);
+-EXPORT_SYMBOL(skb_copy_and_csum_dev);
+-EXPORT_SYMBOL(skb_copy_expand);
+-EXPORT_SYMBOL(___pskb_trim);
+-EXPORT_SYMBOL(__pskb_pull_tail);
+-EXPORT_SYMBOL(pskb_expand_head);
+-EXPORT_SYMBOL(pskb_copy);
+-EXPORT_SYMBOL(skb_realloc_headroom);
+-EXPORT_SYMBOL(datagram_poll);
+-EXPORT_SYMBOL(put_cmsg);
+-EXPORT_SYMBOL(sock_kmalloc);
+-EXPORT_SYMBOL(sock_kfree_s);
+-EXPORT_SYMBOL(sock_map_fd);
+-EXPORT_SYMBOL(sockfd_lookup);
+-
+-EXPORT_SYMBOL(sk_run_filter);
+-EXPORT_SYMBOL(sk_chk_filter);
+-
+-EXPORT_SYMBOL(neigh_table_init);
+-EXPORT_SYMBOL(neigh_table_clear);
+-EXPORT_SYMBOL(neigh_resolve_output);
+-EXPORT_SYMBOL(neigh_connected_output);
+-EXPORT_SYMBOL(neigh_update);
+-EXPORT_SYMBOL(neigh_create);
+-EXPORT_SYMBOL(neigh_lookup);
+-EXPORT_SYMBOL(__neigh_event_send);
+-EXPORT_SYMBOL(neigh_event_ns);
+-EXPORT_SYMBOL(neigh_ifdown);
+-#ifdef CONFIG_ARPD
+-EXPORT_SYMBOL(neigh_app_ns);
+-#endif
+-#ifdef CONFIG_SYSCTL
+-EXPORT_SYMBOL(neigh_sysctl_register);
+-EXPORT_SYMBOL(neigh_sysctl_unregister);
+-#endif
+-EXPORT_SYMBOL(pneigh_lookup);
+-EXPORT_SYMBOL(pneigh_enqueue);
+-EXPORT_SYMBOL(neigh_destroy);
+-EXPORT_SYMBOL(neigh_parms_alloc);
+-EXPORT_SYMBOL(neigh_parms_release);
+-EXPORT_SYMBOL(neigh_rand_reach_time);
+-EXPORT_SYMBOL(neigh_compat_output); 
+-EXPORT_SYMBOL(neigh_changeaddr); 
+-
+-/*    dst_entry       */
+-EXPORT_SYMBOL(dst_alloc);
+-EXPORT_SYMBOL(__dst_free);
+-EXPORT_SYMBOL(dst_destroy);
+-
+-/*    misc. support routines */
+-EXPORT_SYMBOL(net_ratelimit);
+-EXPORT_SYMBOL(net_random);
+-EXPORT_SYMBOL(net_srandom);
+-
+-/* Needed by smbfs.o */
+-EXPORT_SYMBOL(__scm_destroy);
+-EXPORT_SYMBOL(__scm_send);
+-
+-/* Needed by unix.o */
+-EXPORT_SYMBOL(scm_fp_dup);
+-EXPORT_SYMBOL(files_stat);
+-EXPORT_SYMBOL(memcpy_toiovec);
+-
+-#ifdef CONFIG_IPX_MODULE
+-EXPORT_SYMBOL(make_8023_client);
+-EXPORT_SYMBOL(destroy_8023_client);
+-EXPORT_SYMBOL(make_EII_client);
+-EXPORT_SYMBOL(destroy_EII_client);
+-#endif
+-
+-/* for 801q VLAN support */
+-#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
+-EXPORT_SYMBOL(dev_change_flags);
+-#endif
+-
+-EXPORT_SYMBOL(scm_detach_fds);
+-
+-#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
+-EXPORT_SYMBOL(br_handle_frame_hook);
+-#endif
+-
+-#ifdef CONFIG_NET_DIVERT
+-EXPORT_SYMBOL(alloc_divert_blk);
+-EXPORT_SYMBOL(free_divert_blk);
+-#endif /* CONFIG_NET_DIVERT */
+-
+-#ifdef CONFIG_INET
+-/* Internet layer registration */
+-EXPORT_SYMBOL(inetdev_lock);
+-EXPORT_SYMBOL(inet_add_protocol);
+-EXPORT_SYMBOL(inet_del_protocol);
+-EXPORT_SYMBOL(inet_register_protosw);
+-EXPORT_SYMBOL(inet_unregister_protosw);
+-EXPORT_SYMBOL(ip_route_output_key);
+-EXPORT_SYMBOL(ip_route_input);
+-EXPORT_SYMBOL(icmp_send);
+-EXPORT_SYMBOL(icmp_statistics);
+-EXPORT_SYMBOL(icmp_err_convert);
+-EXPORT_SYMBOL(ip_options_compile);
+-EXPORT_SYMBOL(ip_options_undo);
+-EXPORT_SYMBOL(arp_send);
+-EXPORT_SYMBOL(arp_broken_ops);
+-EXPORT_SYMBOL(__ip_select_ident);
+-EXPORT_SYMBOL(ip_send_check);
+-EXPORT_SYMBOL(ip_fragment);
+-EXPORT_SYMBOL(inet_family_ops);
+-EXPORT_SYMBOL(in_aton);
+-EXPORT_SYMBOL(ip_mc_inc_group);
+-EXPORT_SYMBOL(ip_mc_dec_group);
+-EXPORT_SYMBOL(ip_mc_join_group);
+-EXPORT_SYMBOL(ip_finish_output);
+-EXPORT_SYMBOL(inet_stream_ops);
+-EXPORT_SYMBOL(inet_dgram_ops);
+-EXPORT_SYMBOL(ip_cmsg_recv);
+-EXPORT_SYMBOL(inet_addr_type); 
+-EXPORT_SYMBOL(inet_select_addr);
+-EXPORT_SYMBOL(ip_dev_find);
+-EXPORT_SYMBOL(inetdev_by_index);
+-EXPORT_SYMBOL(in_dev_finish_destroy);
+-EXPORT_SYMBOL(ip_defrag);
+-EXPORT_SYMBOL(inet_peer_idlock);
+-
+-/* Route manipulation */
+-EXPORT_SYMBOL(ip_rt_ioctl);
+-EXPORT_SYMBOL(devinet_ioctl);
+-EXPORT_SYMBOL(register_inetaddr_notifier);
+-EXPORT_SYMBOL(unregister_inetaddr_notifier);
+-
+-/* proc */
+-#ifdef CONFIG_PROC_FS
+-EXPORT_SYMBOL(udp_proc_register);
+-EXPORT_SYMBOL(udp_proc_unregister);
+-EXPORT_SYMBOL(tcp_proc_register);
+-EXPORT_SYMBOL(tcp_proc_unregister);
+-#endif
+-
+-/* needed for ip_gre -cw */
+-EXPORT_SYMBOL(ip_statistics);
+-#if defined(CONFIG_INET_ESP) || defined(CONFIG_INET_ESP_MODULE) || defined(CONFIG_INET6_ESP) || defined(CONFIG_INET6_ESP_MODULE)
+-EXPORT_SYMBOL_GPL(skb_cow_data);
+-EXPORT_SYMBOL_GPL(pskb_put);
+-EXPORT_SYMBOL_GPL(skb_to_sgvec);
+-#endif
+-
+-EXPORT_SYMBOL(flow_cache_lookup);
+-EXPORT_SYMBOL(flow_cache_genid);
+-
+-#if defined (CONFIG_IPV6_MODULE) || defined (CONFIG_IP_SCTP_MODULE)
+-/* inet functions common to v4 and v6 */
+-EXPORT_SYMBOL(inet_release);
+-EXPORT_SYMBOL(inet_stream_connect);
+-EXPORT_SYMBOL(inet_dgram_connect);
+-EXPORT_SYMBOL(inet_accept);
+-EXPORT_SYMBOL(inet_listen);
+-EXPORT_SYMBOL(inet_shutdown);
+-EXPORT_SYMBOL(inet_setsockopt);
+-EXPORT_SYMBOL(inet_getsockopt);
+-EXPORT_SYMBOL(inet_sendmsg);
+-EXPORT_SYMBOL(inet_recvmsg);
+-#ifdef INET_REFCNT_DEBUG
+-EXPORT_SYMBOL(inet_sock_nr);
+-#endif
+-EXPORT_SYMBOL(inet_sock_destruct);
+-EXPORT_SYMBOL(inet_sock_release);
+-
+-/* Socket demultiplexing. */
+-EXPORT_SYMBOL(tcp_hashinfo);
+-EXPORT_SYMBOL(tcp_listen_wlock);
+-EXPORT_SYMBOL(udp_hash);
+-EXPORT_SYMBOL(udp_hash_lock);
+-
+-EXPORT_SYMBOL(tcp_destroy_sock);
+-EXPORT_SYMBOL(ip_queue_xmit);
+-EXPORT_SYMBOL(memcpy_fromiovecend);
+-EXPORT_SYMBOL(csum_partial_copy_fromiovecend);
+-EXPORT_SYMBOL(tcp_v4_lookup_listener);
+-/* UDP/TCP exported functions for TCPv6 */
+-EXPORT_SYMBOL(udp_ioctl);
+-EXPORT_SYMBOL(udp_connect);
+-EXPORT_SYMBOL(udp_disconnect);
+-EXPORT_SYMBOL(udp_sendmsg);
+-EXPORT_SYMBOL(tcp_bind_hash);
+-EXPORT_SYMBOL(tcp_close);
+-EXPORT_SYMBOL(tcp_disconnect);
+-EXPORT_SYMBOL(tcp_accept);
+-EXPORT_SYMBOL(tcp_write_wakeup);
+-EXPORT_SYMBOL(tcp_write_space);
+-EXPORT_SYMBOL(tcp_poll);
+-EXPORT_SYMBOL(tcp_ioctl);
+-EXPORT_SYMBOL(tcp_shutdown);
+-EXPORT_SYMBOL(tcp_setsockopt);
+-EXPORT_SYMBOL(tcp_getsockopt);
+-EXPORT_SYMBOL(tcp_recvmsg);
+-EXPORT_SYMBOL(tcp_send_synack);
+-EXPORT_SYMBOL(tcp_check_req);
+-EXPORT_SYMBOL(tcp_child_process);
+-EXPORT_SYMBOL(tcp_parse_options);
+-EXPORT_SYMBOL(tcp_rcv_established);
+-EXPORT_SYMBOL(tcp_init_xmit_timers);
+-EXPORT_SYMBOL(tcp_clear_xmit_timers);
+-EXPORT_SYMBOL(tcp_statistics);
+-EXPORT_SYMBOL(tcp_rcv_state_process);
+-EXPORT_SYMBOL(tcp_timewait_state_process);
+-EXPORT_SYMBOL(tcp_timewait_cachep);
+-EXPORT_SYMBOL(tcp_sendmsg);
+-EXPORT_SYMBOL(tcp_v4_rebuild_header);
+-EXPORT_SYMBOL(tcp_v4_send_check);
+-EXPORT_SYMBOL(tcp_v4_conn_request);
+-EXPORT_SYMBOL(tcp_create_openreq_child);
+-EXPORT_SYMBOL(tcp_bucket_create);
+-EXPORT_SYMBOL(tcp_put_port);
+-EXPORT_SYMBOL(tcp_inherit_port);
+-EXPORT_SYMBOL(tcp_v4_syn_recv_sock);
+-EXPORT_SYMBOL(tcp_v4_do_rcv);
+-EXPORT_SYMBOL(tcp_v4_connect);
+-EXPORT_SYMBOL(tcp_unhash);
+-EXPORT_SYMBOL(udp_prot);
+-EXPORT_SYMBOL(tcp_prot);
+-EXPORT_SYMBOL(tcp_openreq_cachep);
+-EXPORT_SYMBOL(ipv4_specific);
+-EXPORT_SYMBOL(tcp_simple_retransmit);
+-EXPORT_SYMBOL(tcp_transmit_skb);
+-EXPORT_SYMBOL(tcp_connect);
+-EXPORT_SYMBOL(tcp_make_synack);
+-EXPORT_SYMBOL(tcp_tw_deschedule);
+-EXPORT_SYMBOL(tcp_delete_keepalive_timer);
+-EXPORT_SYMBOL(tcp_reset_keepalive_timer);
+-EXPORT_SYMBOL(sysctl_local_port_range);
+-EXPORT_SYMBOL(tcp_port_rover);
+-EXPORT_SYMBOL(udp_port_rover);
+-EXPORT_SYMBOL(tcp_sync_mss);
+-EXPORT_SYMBOL(net_statistics); 
+-EXPORT_SYMBOL(__tcp_mem_reclaim);
+-EXPORT_SYMBOL(tcp_sockets_allocated);
+-EXPORT_SYMBOL(sysctl_tcp_reordering);
+-EXPORT_SYMBOL(sysctl_tcp_rmem);
+-EXPORT_SYMBOL(sysctl_tcp_wmem);
+-EXPORT_SYMBOL(sysctl_tcp_ecn);
+-EXPORT_SYMBOL(tcp_cwnd_application_limited);
+-EXPORT_SYMBOL(tcp_sendpage);
+-EXPORT_SYMBOL(sysctl_tcp_low_latency);
+-
+-EXPORT_SYMBOL(tcp_write_xmit);
+-
+-EXPORT_SYMBOL(tcp_v4_remember_stamp); 
+-
+-extern int sysctl_tcp_tw_recycle;
+-
+-#ifdef CONFIG_SYSCTL
+-EXPORT_SYMBOL(sysctl_tcp_tw_recycle); 
+-EXPORT_SYMBOL(sysctl_max_syn_backlog);
+-#endif
+-
+-EXPORT_SYMBOL(ip_generic_getfrag);
+-
+-#endif
+-
+-EXPORT_SYMBOL(tcp_read_sock);
+-
+-#ifdef CONFIG_IP_SCTP_MODULE
+-EXPORT_SYMBOL(ip_setsockopt);
+-EXPORT_SYMBOL(ip_getsockopt);
+-EXPORT_SYMBOL(inet_ioctl);
+-EXPORT_SYMBOL(inet_bind);
+-EXPORT_SYMBOL(inet_getname);
+-#endif /* CONFIG_IP_SCTP_MODULE */
+-
+-EXPORT_SYMBOL(netlink_set_err);
+-EXPORT_SYMBOL(netlink_broadcast);
+-EXPORT_SYMBOL(netlink_unicast);
+-EXPORT_SYMBOL(netlink_kernel_create);
+-EXPORT_SYMBOL(netlink_dump_start);
+-EXPORT_SYMBOL(netlink_ack);
+-EXPORT_SYMBOL(netlink_set_nonroot);
+-EXPORT_SYMBOL(netlink_register_notifier);
+-EXPORT_SYMBOL(netlink_unregister_notifier);
+-#if defined(CONFIG_NETLINK_DEV) || defined(CONFIG_NETLINK_DEV_MODULE)
+-EXPORT_SYMBOL(netlink_attach);
+-EXPORT_SYMBOL(netlink_detach);
+-EXPORT_SYMBOL(netlink_post);
+-#endif
+-
+-EXPORT_SYMBOL(rtattr_parse);
+-EXPORT_SYMBOL(__rta_fill);
+-EXPORT_SYMBOL(neigh_delete);
+-EXPORT_SYMBOL(neigh_add);
+-EXPORT_SYMBOL(neigh_dump_info);
+-
+-
+-/* ABI emulation layers need this */
+-EXPORT_SYMBOL(move_addr_to_kernel);
+-EXPORT_SYMBOL(move_addr_to_user);
+-                  
+-/* Used by at least ipip.c.  */
+-EXPORT_SYMBOL(ipv4_config);
+-
+-/* Used by other modules */
+-EXPORT_SYMBOL(xrlim_allow);
+-
+-EXPORT_SYMBOL(ip_rcv);
+-EXPORT_SYMBOL(arp_rcv);
+-EXPORT_SYMBOL(arp_tbl);
+-#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
+-EXPORT_SYMBOL(clip_tbl_hook);
+-#endif
+-EXPORT_SYMBOL(arp_find);
+-
+-#endif  /* CONFIG_INET */
+-
+-#ifdef CONFIG_TR
+-EXPORT_SYMBOL(tr_source_route);
+-EXPORT_SYMBOL(tr_type_trans);
+-#endif
+-
+-/* Device callback registration */
+-EXPORT_SYMBOL(register_netdevice_notifier);
+-EXPORT_SYMBOL(unregister_netdevice_notifier);
+-EXPORT_SYMBOL(call_netdevice_notifiers);
+-
+-/* support for loadable net drivers */
+-#ifdef CONFIG_NET
+-EXPORT_SYMBOL(loopback_dev);
+-EXPORT_SYMBOL(register_netdevice);
+-EXPORT_SYMBOL(unregister_netdevice);
+-EXPORT_SYMBOL(free_netdev);
+-EXPORT_SYMBOL(synchronize_net);
+-EXPORT_SYMBOL(netdev_state_change);
+-EXPORT_SYMBOL(netdev_boot_setup_check);
+-EXPORT_SYMBOL(dev_new_index);
+-EXPORT_SYMBOL(dev_get_by_flags);
+-EXPORT_SYMBOL(__dev_get_by_flags);
+-EXPORT_SYMBOL(dev_get_by_index);
+-EXPORT_SYMBOL(__dev_get_by_index);
+-EXPORT_SYMBOL(dev_get_by_name);
+-EXPORT_SYMBOL(__dev_get_by_name);
+-EXPORT_SYMBOL(dev_getbyhwaddr);
+-EXPORT_SYMBOL(netdev_set_master);
+-EXPORT_SYMBOL(eth_type_trans);
+-#ifdef CONFIG_FDDI
+-EXPORT_SYMBOL(fddi_type_trans);
+-#endif /* CONFIG_FDDI */
+-#if 0
+-EXPORT_SYMBOL(eth_copy_and_sum);
+-#endif
+-EXPORT_SYMBOL(alloc_skb);
+-EXPORT_SYMBOL(__kfree_skb);
+-EXPORT_SYMBOL(skb_clone);
+-EXPORT_SYMBOL(skb_copy);
+-EXPORT_SYMBOL(skb_pad);
+-EXPORT_SYMBOL(netif_rx);
+-EXPORT_SYMBOL(netif_receive_skb);
+-EXPORT_SYMBOL(dev_add_pack);
+-EXPORT_SYMBOL(dev_remove_pack);
+-EXPORT_SYMBOL(__dev_remove_pack);
+-EXPORT_SYMBOL(__dev_get);
+-EXPORT_SYMBOL(dev_alloc);
+-EXPORT_SYMBOL(dev_alloc_name);
+-EXPORT_SYMBOL(__netdev_watchdog_up);
+-#ifdef CONFIG_KMOD
+-EXPORT_SYMBOL(dev_load);
+-#endif
+-EXPORT_SYMBOL(dev_ioctl);
+-EXPORT_SYMBOL(dev_queue_xmit);
+-#ifdef CONFIG_NET_HW_FLOWCONTROL
+-EXPORT_SYMBOL(netdev_dropping);
+-EXPORT_SYMBOL(netdev_register_fc);
+-EXPORT_SYMBOL(netdev_unregister_fc);
+-EXPORT_SYMBOL(netdev_fc_xoff);
+-#endif
+-EXPORT_SYMBOL(dev_base);
+-EXPORT_SYMBOL(dev_base_lock);
+-EXPORT_SYMBOL(dev_open);
+-EXPORT_SYMBOL(dev_close);
+-EXPORT_SYMBOL(dev_mc_add);
+-EXPORT_SYMBOL(dev_mc_delete);
+-EXPORT_SYMBOL(dev_mc_upload);
+-EXPORT_SYMBOL(dev_set_allmulti);
+-EXPORT_SYMBOL(dev_set_promiscuity);
+-EXPORT_SYMBOL(__kill_fasync);
+-
+-EXPORT_SYMBOL(rtnl);
+-EXPORT_SYMBOL(rtnetlink_links);
+-EXPORT_SYMBOL(rtnetlink_dump_ifinfo);
+-EXPORT_SYMBOL(rtnetlink_put_metrics);
+-EXPORT_SYMBOL(rtnl_sem);
+-EXPORT_SYMBOL(rtnl_lock);
+-EXPORT_SYMBOL(rtnl_unlock);
+-
+-#ifdef CONFIG_HIPPI
+-EXPORT_SYMBOL(hippi_type_trans);
+-#endif
+-
+-#ifdef CONFIG_NET_FASTROUTE
+-EXPORT_SYMBOL(netdev_fastroute);
+-#endif
+-
+-#ifdef CONFIG_SYSCTL
+-EXPORT_SYMBOL(sysctl_wmem_max);
+-EXPORT_SYMBOL(sysctl_rmem_max);
+-#ifdef CONFIG_INET
+-EXPORT_SYMBOL(sysctl_ip_default_ttl);
+-#endif
+-#endif
+-
+-/* Packet scheduler modules want these. */
+-EXPORT_SYMBOL(qdisc_destroy);
+-EXPORT_SYMBOL(qdisc_reset);
+-EXPORT_SYMBOL(qdisc_restart);
+-EXPORT_SYMBOL(qdisc_create_dflt);
+-EXPORT_SYMBOL(noop_qdisc);
+-EXPORT_SYMBOL(qdisc_tree_lock);
+-#ifdef CONFIG_NET_SCHED
+-PSCHED_EXPORTLIST;
+-EXPORT_SYMBOL(pfifo_qdisc_ops);
+-EXPORT_SYMBOL(bfifo_qdisc_ops);
+-EXPORT_SYMBOL(register_qdisc);
+-EXPORT_SYMBOL(unregister_qdisc);
+-EXPORT_SYMBOL(qdisc_get_rtab);
+-EXPORT_SYMBOL(qdisc_put_rtab);
+-EXPORT_SYMBOL(qdisc_copy_stats);
+-#ifdef CONFIG_NET_ESTIMATOR
+-EXPORT_SYMBOL(qdisc_new_estimator);
+-EXPORT_SYMBOL(qdisc_kill_estimator);
+-#endif
+-#ifdef CONFIG_NET_CLS_POLICE
+-EXPORT_SYMBOL(tcf_police);
+-EXPORT_SYMBOL(tcf_police_locate);
+-EXPORT_SYMBOL(tcf_police_destroy);
+-EXPORT_SYMBOL(tcf_police_dump);
+-#endif
+-#endif
+-#ifdef CONFIG_NET_CLS
+-EXPORT_SYMBOL(register_tcf_proto_ops);
+-EXPORT_SYMBOL(unregister_tcf_proto_ops);
+-#endif
+-#ifdef CONFIG_NETFILTER
+-#include <linux/netfilter.h>
+-EXPORT_SYMBOL(nf_register_hook);
+-EXPORT_SYMBOL(nf_unregister_hook);
+-EXPORT_SYMBOL(nf_register_sockopt);
+-EXPORT_SYMBOL(nf_unregister_sockopt);
+-EXPORT_SYMBOL(nf_reinject);
+-EXPORT_SYMBOL(nf_register_queue_handler);
+-EXPORT_SYMBOL(nf_unregister_queue_handler);
+-EXPORT_SYMBOL(nf_hook_slow);
+-EXPORT_SYMBOL(nf_hooks);
+-EXPORT_SYMBOL(nf_setsockopt);
+-EXPORT_SYMBOL(nf_getsockopt);
+-EXPORT_SYMBOL(ip_ct_attach);
+-#ifdef CONFIG_INET
+-#include <linux/netfilter_ipv4.h>
+-EXPORT_SYMBOL(ip_route_me_harder);
+-#endif
+-#endif
+-
+-EXPORT_SYMBOL(register_gifconf);
+-
+-EXPORT_PER_CPU_SYMBOL(softnet_data);
+-
+-#ifdef CONFIG_NET_RADIO
+-#include <net/iw_handler.h>           /* Wireless Extensions driver API */
+-EXPORT_SYMBOL(wireless_send_event);
+-EXPORT_SYMBOL(iw_handler_set_spy);
+-EXPORT_SYMBOL(iw_handler_get_spy);
+-EXPORT_SYMBOL(iw_handler_set_thrspy);
+-EXPORT_SYMBOL(iw_handler_get_thrspy);
+-EXPORT_SYMBOL(wireless_spy_update);
+-#endif        /* CONFIG_NET_RADIO */
+-
+-EXPORT_SYMBOL(linkwatch_fire_event);
+-
+-/* ethtool.c */
+-EXPORT_SYMBOL(ethtool_op_get_link);
+-EXPORT_SYMBOL(ethtool_op_get_tx_csum);
+-EXPORT_SYMBOL(ethtool_op_set_tx_csum);
+-EXPORT_SYMBOL(ethtool_op_get_sg);
+-EXPORT_SYMBOL(ethtool_op_set_sg);
+-EXPORT_SYMBOL(ethtool_op_get_tso);
+-EXPORT_SYMBOL(ethtool_op_set_tso);
+-
+-#endif  /* CONFIG_NET */
+--- linux-2.6.0-test6/net/sched/cls_api.c      2003-06-14 12:18:03.000000000 -0700
++++ 25/net/sched/cls_api.c     2003-10-05 00:33:25.000000000 -0700
+@@ -467,3 +467,6 @@ int __init tc_filter_init(void)
+ #endif
+       return 0;
+ }
++
++EXPORT_SYMBOL(register_tcf_proto_ops);
++EXPORT_SYMBOL(unregister_tcf_proto_ops);
+--- linux-2.6.0-test6/net/sched/estimator.c    2003-09-27 18:57:47.000000000 -0700
++++ 25/net/sched/estimator.c   2003-10-05 00:33:25.000000000 -0700
+@@ -12,6 +12,7 @@
+ #include <asm/uaccess.h>
+ #include <asm/system.h>
+ #include <asm/bitops.h>
++#include <linux/module.h>
+ #include <linux/types.h>
+ #include <linux/kernel.h>
+ #include <linux/jiffies.h>
+@@ -194,3 +195,5 @@ void qdisc_kill_estimator(struct tc_stat
+       }
+ }
++EXPORT_SYMBOL(qdisc_kill_estimator);
++EXPORT_SYMBOL(qdisc_new_estimator);
+--- linux-2.6.0-test6/net/sched/police.c       2003-09-27 18:57:47.000000000 -0700
++++ 25/net/sched/police.c      2003-10-05 00:33:25.000000000 -0700
+@@ -13,6 +13,7 @@
+ #include <asm/system.h>
+ #include <asm/bitops.h>
+ #include <linux/config.h>
++#include <linux/module.h>
+ #include <linux/types.h>
+ #include <linux/kernel.h>
+ #include <linux/sched.h>
+@@ -248,3 +249,12 @@ rtattr_failure:
+       skb_trim(skb, b - skb->data);
+       return -1;
+ }
++
++EXPORT_SYMBOL(tcf_police);
++EXPORT_SYMBOL(tcf_police_destroy);
++EXPORT_SYMBOL(tcf_police_dump);
++EXPORT_SYMBOL(tcf_police_hash);
++EXPORT_SYMBOL(tcf_police_ht);
++EXPORT_SYMBOL(tcf_police_locate);
++EXPORT_SYMBOL(tcf_police_lookup);
++EXPORT_SYMBOL(tcf_police_new_index);
+--- linux-2.6.0-test6/net/sched/sch_api.c      2003-09-27 18:57:47.000000000 -0700
++++ 25/net/sched/sch_api.c     2003-10-05 00:33:25.000000000 -0700
+@@ -1255,3 +1255,10 @@ int __init pktsched_init(void)
+       return 0;
+ }
++
++EXPORT_SYMBOL(qdisc_copy_stats);
++EXPORT_SYMBOL(qdisc_get_rtab);
++EXPORT_SYMBOL(qdisc_put_rtab);
++EXPORT_SYMBOL(register_qdisc);
++EXPORT_SYMBOL(unregister_qdisc);
++PSCHED_EXPORTLIST;
+--- linux-2.6.0-test6/net/sched/sch_fifo.c     2003-07-10 18:50:32.000000000 -0700
++++ 25/net/sched/sch_fifo.c    2003-10-05 00:33:25.000000000 -0700
+@@ -203,3 +203,6 @@ struct Qdisc_ops bfifo_qdisc_ops = {
+       .dump           =       fifo_dump,
+       .owner          =       THIS_MODULE,
+ };
++
++EXPORT_SYMBOL(bfifo_qdisc_ops);
++EXPORT_SYMBOL(pfifo_qdisc_ops);
+--- linux-2.6.0-test6/net/sched/sch_generic.c  2003-09-27 18:57:47.000000000 -0700
++++ 25/net/sched/sch_generic.c 2003-10-05 00:33:25.000000000 -0700
+@@ -531,3 +531,12 @@ void dev_shutdown(struct net_device *dev
+       spin_unlock_bh(&dev->queue_lock);
+       write_unlock(&qdisc_tree_lock);
+ }
++
++EXPORT_SYMBOL(__netdev_watchdog_up);
++EXPORT_SYMBOL(noop_qdisc);
++EXPORT_SYMBOL(noop_qdisc_ops);
++EXPORT_SYMBOL(qdisc_create_dflt);
++EXPORT_SYMBOL(qdisc_destroy);
++EXPORT_SYMBOL(qdisc_reset);
++EXPORT_SYMBOL(qdisc_restart);
++EXPORT_SYMBOL(qdisc_tree_lock);
+--- linux-2.6.0-test6/net/sctp/associola.c     2003-09-08 13:58:59.000000000 -0700
++++ 25/net/sctp/associola.c    2003-10-05 00:33:25.000000000 -0700
+@@ -141,9 +141,9 @@ struct sctp_association *sctp_associatio
+        * socket values.
+        */
+       asoc->max_retrans = sp->assocparams.sasoc_asocmaxrxt;
+-      asoc->rto_initial = sp->rtoinfo.srto_initial * HZ / 1000;
+-      asoc->rto_max = sp->rtoinfo.srto_max * HZ / 1000;
+-      asoc->rto_min = sp->rtoinfo.srto_min * HZ / 1000;
++      asoc->rto_initial = MSECS_TO_JIFFIES(sp->rtoinfo.srto_initial);
++      asoc->rto_max = MSECS_TO_JIFFIES(sp->rtoinfo.srto_max);
++      asoc->rto_min = MSECS_TO_JIFFIES(sp->rtoinfo.srto_min);
+       asoc->overall_error_count = 0;
+@@ -168,7 +168,8 @@ struct sctp_association *sctp_associatio
+       asoc->c.sinit_num_ostreams  = sp->initmsg.sinit_num_ostreams;
+       asoc->max_init_attempts = sp->initmsg.sinit_max_attempts;
+-      asoc->max_init_timeo    = sp->initmsg.sinit_max_init_timeo * HZ / 1000;
++      asoc->max_init_timeo =
++               MSECS_TO_JIFFIES(sp->initmsg.sinit_max_init_timeo);
+       /* Allocate storage for the ssnmap after the inbound and outbound
+        * streams have been negotiated during Init.
+@@ -246,6 +247,11 @@ struct sctp_association *sctp_associatio
+        */
+       asoc->peer.sack_needed = 1;
++      /* Assume that the peer recongizes ASCONF until reported otherwise
++       * via an ERROR chunk.
++       */
++      asoc->peer.asconf_capable = 1;
++
+       /* Create an input queue.  */
+       sctp_inq_init(&asoc->base.inqueue);
+       sctp_inq_set_th_handler(&asoc->base.inqueue,
+@@ -495,7 +501,7 @@ struct sctp_transport *sctp_assoc_add_pe
+       /* Initialize the peer's heartbeat interval based on the
+        * sock configured value.
+        */
+-      peer->hb_interval = sp->paddrparam.spp_hbinterval * HZ;
++      peer->hb_interval = MSECS_TO_JIFFIES(sp->paddrparam.spp_hbinterval);
+       /* Set the path max_retrans.  */
+       peer->max_retrans = asoc->max_retrans;
+--- linux-2.6.0-test6/net/sctp/bind_addr.c     2003-09-08 13:58:59.000000000 -0700
++++ 25/net/sctp/bind_addr.c    2003-10-05 00:33:25.000000000 -0700
+@@ -324,6 +324,43 @@ int sctp_bind_addr_match(struct sctp_bin
+       return 0;
+ }
++/* Find the first address in the bind address list that is not present in
++ * the addrs packed array.
++ */
++union sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr *bp,
++                                      const union sctp_addr   *addrs,
++                                      int                     addrcnt,
++                                      struct sctp_opt         *opt)
++{
++      struct sctp_sockaddr_entry      *laddr;
++      union sctp_addr                 *addr;
++      void                            *addr_buf;
++      struct sctp_af                  *af;
++      struct list_head                *pos;
++      int                             i;
++
++      list_for_each(pos, &bp->address_list) {
++              laddr = list_entry(pos, struct sctp_sockaddr_entry, list);
++              
++              addr_buf = (union sctp_addr *)addrs;
++              for (i = 0; i < addrcnt; i++) {
++                      addr = (union sctp_addr *)addr_buf;
++                      af = sctp_get_af_specific(addr->v4.sin_family);
++                      if (!af) 
++                              return NULL;
++
++                      if (opt->pf->cmp_addr(&laddr->a, addr, opt))
++                              break;
++
++                      addr_buf += af->sockaddr_len;
++              }
++              if (i == addrcnt)
++                      return &laddr->a;
++      }
++
++      return NULL;
++}
++
+ /* Copy out addresses from the global local address list. */
+ static int sctp_copy_one_addr(struct sctp_bind_addr *dest, 
+                             union sctp_addr *addr,
+--- linux-2.6.0-test6/net/sctp/endpointola.c   2003-08-08 22:55:14.000000000 -0700
++++ 25/net/sctp/endpointola.c  2003-10-05 00:33:25.000000000 -0700
+@@ -129,7 +129,7 @@ struct sctp_endpoint *sctp_endpoint_init
+       ep->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] =
+               SCTP_DEFAULT_TIMEOUT_T1_INIT;
+       ep->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] =
+-              sp->rtoinfo.srto_initial * HZ / 1000;
++              MSECS_TO_JIFFIES(sp->rtoinfo.srto_initial);
+       ep->timeouts[SCTP_EVENT_TIMEOUT_T3_RTX] = 0;
+       ep->timeouts[SCTP_EVENT_TIMEOUT_T4_RTO] = 0;
+@@ -138,7 +138,7 @@ struct sctp_endpoint *sctp_endpoint_init
+        * recommended value of 5 times 'RTO.Max'.
+        */
+         ep->timeouts[SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD]
+-              = 5 * (sp->rtoinfo.srto_max * HZ / 1000);
++              = 5 * MSECS_TO_JIFFIES(sp->rtoinfo.srto_max);
+       ep->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] =
+               SCTP_DEFAULT_TIMEOUT_HEARTBEAT;
+--- linux-2.6.0-test6/net/sctp/sm_make_chunk.c 2003-09-08 13:58:59.000000000 -0700
++++ 25/net/sctp/sm_make_chunk.c        2003-10-05 00:33:25.000000000 -0700
+@@ -1,5 +1,5 @@
+ /* SCTP kernel reference Implementation
+- * Copyright (C) IBM Corp. 2001, 2003
++ * (C) Copyright IBM Corp. 2001, 2003
+  * Copyright (c) 1999-2000 Cisco, Inc.
+  * Copyright (c) 1999-2001 Motorola, Inc.
+  * Copyright (c) 2001-2002 Intel Corp.
+@@ -1288,7 +1288,7 @@ sctp_cookie_param_t *sctp_pack_cookie(co
+       /* Set an expiration time for the cookie.  */
+       do_gettimeofday(&cookie->c.expiration);
+-      tv_add(&asoc->cookie_life, &cookie->c.expiration);
++      TIMEVAL_ADD(asoc->cookie_life, cookie->c.expiration);
+       /* Copy the peer's init packet.  */
+       memcpy(&cookie->c.peer_init[0], init_chunk->chunk_hdr,
+@@ -2021,11 +2021,11 @@ struct sctp_chunk *sctp_make_asconf(stru
+       sctp_addiphdr_t asconf;
+       struct sctp_chunk *retval;
+       int length = sizeof(asconf) + vparam_len;
+-      union sctp_params addrparam;
++      union sctp_addr_param addrparam;
+       int addrlen;
+       struct sctp_af *af = sctp_get_af_specific(addr->v4.sin_family);
+-      addrlen = af->to_addr_param(addr, (union sctp_addr_param *)&addrparam);
++      addrlen = af->to_addr_param(addr, &addrparam);
+       if (!addrlen)
+               return NULL;
+       length += addrlen;
+@@ -2046,6 +2046,83 @@ struct sctp_chunk *sctp_make_asconf(stru
+ }
+ /* ADDIP
++ * 3.2.1 Add IP Address
++ *    0                   1                   2                   3
++ *    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++ *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++ *     |        Type = 0xC001          |    Length = Variable          |
++ *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++ *     |               ASCONF-Request Correlation ID                   |
++ *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++ *     |                       Address Parameter                       |
++ *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++ *
++ * 3.2.2 Delete IP Address
++ *    0                   1                   2                   3
++ *    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++ *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++ *     |        Type = 0xC002          |    Length = Variable          |
++ *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++ *     |               ASCONF-Request Correlation ID                   |
++ *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++ *     |                       Address Parameter                       |
++ *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++ *
++ */
++struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc,
++                                            union sctp_addr         *laddr,
++                                            struct sockaddr         *addrs,
++                                            int                     addrcnt,
++                                            int                     flags)
++{
++      sctp_addip_param_t      param;
++      struct sctp_chunk       *retval;
++      union sctp_addr_param   addr_param;
++      union sctp_addr         *addr;
++      void                    *addr_buf;
++      struct sctp_af          *af;
++      int                     paramlen = sizeof(param);
++      int                     addr_param_len = 0;
++      int                     totallen = 0;
++      int                     i;
++
++      /* Get total length of all the address parameters. */
++      addr_buf = addrs;
++      for (i = 0; i < addrcnt; i++) {
++              addr = (union sctp_addr *)addr_buf;
++              af = sctp_get_af_specific(addr->v4.sin_family);
++              addr_param_len = af->to_addr_param(addr, &addr_param);
++
++              totallen += paramlen;
++              totallen += addr_param_len;
++
++              addr_buf += af->sockaddr_len;
++      }
++
++      /* Create an asconf chunk with the required length. */
++      retval = sctp_make_asconf(asoc, laddr, totallen);
++      if (!retval)
++              return NULL;
++
++      /* Add the address parameters to the asconf chunk. */
++      addr_buf = addrs;
++      for (i = 0; i < addrcnt; i++) {
++              addr = (union sctp_addr *)addr_buf;
++              af = sctp_get_af_specific(addr->v4.sin_family);
++              addr_param_len = af->to_addr_param(addr, &addr_param);
++              param.param_hdr.type = flags;
++              param.param_hdr.length = htons(paramlen + addr_param_len);
++              param.crr_id = htonl(i);
++
++              sctp_addto_chunk(retval, paramlen, &param);
++              sctp_addto_chunk(retval, addr_param_len, &addr_param);
++
++              addr_buf += af->sockaddr_len;
++      }
++      return retval;
++}
++
++/* ADDIP
+  * 3.2.4 Set Primary IP Address
+  *    0                   1                   2                   3
+  *    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+@@ -2065,11 +2142,11 @@ struct sctp_chunk *sctp_make_asconf_set_
+       sctp_addip_param_t      param;
+       struct sctp_chunk       *retval;
+       int                     len = sizeof(param);
+-      union sctp_params       addrparam;
++      union sctp_addr_param   addrparam;
+       int                     addrlen;
+       struct sctp_af          *af = sctp_get_af_specific(addr->v4.sin_family);
+-      addrlen = af->to_addr_param(addr, (union sctp_addr_param *)&addrparam);
++      addrlen = af->to_addr_param(addr, &addrparam);
+       if (!addrlen)
+               return NULL;
+       len += addrlen;
+@@ -2089,11 +2166,7 @@ struct sctp_chunk *sctp_make_asconf_set_
+       return retval;
+ }
+-/*
+- * Unpack the parameters in an ASCONF chunk into an association and
+- * generate ASCONF-ACK chunk.
+- *
+- * ADDIP 3.1.2 Address Configuration Acknowledgement Chunk (ASCONF-ACK)
++/* ADDIP 3.1.2 Address Configuration Acknowledgement Chunk (ASCONF-ACK)
+  *      0                   1                   2                   3
+  *      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+  *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+@@ -2110,8 +2183,28 @@ struct sctp_chunk *sctp_make_asconf_set_
+  *     |                 ASCONF Parameter Response#N                   |
+  *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  *
+- * All the parameter respoinces will be added in this function.
++ * Create an ASCONF_ACK chunk with enough space for the parameter responses. 
+  */
++struct sctp_chunk *sctp_make_asconf_ack(struct sctp_association       *asoc,
++                                      int serial, int vparam_len)
++{
++      sctp_addiphdr_t         asconf;
++      struct sctp_chunk       *retval;
++      int                     length = sizeof(asconf) + vparam_len;
++
++      /* Create the chunk.  */
++      retval = sctp_make_chunk(asoc, SCTP_CID_ASCONF_ACK, 0, length);
++      if (!retval)
++              return NULL;
++
++      asconf.serial = serial;
++
++      retval->subh.addip_hdr =
++              sctp_addto_chunk(retval, sizeof(asconf), &asconf);
++
++      return retval;
++}
++
+ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
+                                       struct sctp_chunk *asconf,
+                                       int vparam_len)
+--- linux-2.6.0-test6/net/sctp/sm_sideeffect.c 2003-08-08 22:55:14.000000000 -0700
++++ 25/net/sctp/sm_sideeffect.c        2003-10-05 00:33:25.000000000 -0700
+@@ -1,7 +1,7 @@
+ /* SCTP kernel reference Implementation
++ * (C) Copyright IBM Corp. 2001, 2003
+  * Copyright (c) 1999 Cisco, Inc.
+  * Copyright (c) 1999-2001 Motorola, Inc.
+- * Copyright (c) 2001-2002 International Business Machines Corp.
+  *
+  * This file is part of the SCTP kernel reference Implementation
+  *
+@@ -690,6 +690,44 @@ static void sctp_cmd_setup_t4(sctp_cmd_s
+       chunk->transport = t;
+ }
++/* Process an incoming Operation Error Chunk. */ 
++static void sctp_cmd_process_operr(sctp_cmd_seq_t *cmds,
++                                 struct sctp_association *asoc,
++                                 struct sctp_chunk *chunk)
++{
++      struct sctp_operr_chunk *operr_chunk;
++      struct sctp_errhdr *err_hdr;
++
++      operr_chunk = (struct sctp_operr_chunk *)chunk->chunk_hdr;
++      err_hdr = &operr_chunk->err_hdr;
++
++      switch (err_hdr->cause) {
++      case SCTP_ERROR_UNKNOWN_CHUNK:
++      {
++              struct sctp_chunkhdr *unk_chunk_hdr;
++
++              unk_chunk_hdr = (struct sctp_chunkhdr *)err_hdr->variable;
++              switch (unk_chunk_hdr->type) {
++              /* ADDIP 4.1 A9) If the peer responds to an ASCONF with an
++               * ERROR chunk reporting that it did not recognized the ASCONF
++               * chunk type, the sender of the ASCONF MUST NOT send any
++               * further ASCONF chunks and MUST stop its T-4 timer.
++               */
++              case SCTP_CID_ASCONF:
++                      asoc->peer.asconf_capable = 0;
++                      sctp_add_cmd_sf(cmds, SCTP_CMD_TIMER_STOP,
++                                      SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO));
++                      break;
++              default:
++                      break;
++              }
++              break;
++      }
++      default:
++              break;
++      }
++}
++
+ /* These three macros allow us to pull the debugging code out of the
+  * main flow of sctp_do_sm() to keep attention focused on the real
+  * functionality there.
+@@ -1205,6 +1243,9 @@ int sctp_cmd_interpreter(sctp_event_t ev
+                       sctp_cmd_setup_t4(commands, asoc, cmd->obj.ptr);
+                       break;
++              case SCTP_CMD_PROCESS_OPERR:
++                      sctp_cmd_process_operr(commands, asoc, chunk);
++                      break;
+               default:
+                       printk(KERN_WARNING "Impossible command: %u, %p\n",
+                              cmd->verb, cmd->obj.ptr);
+--- linux-2.6.0-test6/net/sctp/sm_statefuns.c  2003-09-08 13:58:59.000000000 -0700
++++ 25/net/sctp/sm_statefuns.c 2003-10-05 00:33:25.000000000 -0700
+@@ -1,7 +1,7 @@
+ /* SCTP kernel reference Implementation
++ * (C) Copyright IBM Corp. 2001, 2003
+  * Copyright (c) 1999-2000 Cisco, Inc.
+  * Copyright (c) 1999-2001 Motorola, Inc.
+- * Copyright (c) 2001-2002 International Business Machines, Corp.
+  * Copyright (c) 2001-2002 Intel Corp.
+  * Copyright (c) 2002      Nokia Corp.
+  *
+@@ -2864,6 +2864,9 @@ sctp_disposition_t sctp_sf_operr_notify(
+                       sctp_ulpevent_free(ev);
+                       goto nomem;
+               }
++
++              sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_OPERR,
++                              SCTP_CHUNK(chunk));     
+       }
+       return SCTP_DISPOSITION_CONSUME;
+--- linux-2.6.0-test6/net/sctp/socket.c        2003-09-08 13:58:59.000000000 -0700
++++ 25/net/sctp/socket.c       2003-10-05 00:33:25.000000000 -0700
+@@ -97,6 +97,8 @@ static void sctp_wait_for_close(struct s
+ static inline int sctp_verify_addr(struct sock *, union sctp_addr *, int);
+ static int sctp_bindx_add(struct sock *, struct sockaddr *, int);
+ static int sctp_bindx_rem(struct sock *, struct sockaddr *, int);
++static int sctp_send_asconf_add_ip(struct sock *, struct sockaddr *, int);
++static int sctp_send_asconf_del_ip(struct sock *, struct sockaddr *, int);
+ static int sctp_do_bind(struct sock *, union sctp_addr *, int);
+ static int sctp_autobind(struct sock *sk);
+ static void sctp_sock_migrate(struct sock *, struct sock *,
+@@ -349,6 +351,106 @@ err_bindx_add:
+       return retval;
+ }
++/* Send an ASCONF chunk with Add IP address parameters to all the peers of the
++ * associations that are part of the endpoint indicating that a list of local
++ * addresses are added to the endpoint.
++ *
++ * If any of the addresses is already in the bind address list of the 
++ * association, we do not send the chunk for that association.  But it will not
++ * affect other associations.
++ *
++ * Only sctp_setsockopt_bindx() is supposed to call this function.
++ */
++static int sctp_send_asconf_add_ip(struct sock                *sk, 
++                                 struct sockaddr      *addrs,
++                                 int                  addrcnt)
++{
++      struct sctp_opt                 *sp;
++      struct sctp_endpoint            *ep;
++      struct sctp_association         *asoc;
++      struct sctp_bind_addr           *bp;
++      struct sctp_chunk               *chunk;
++      struct sctp_sockaddr_entry      *laddr;
++      union sctp_addr                 *addr;
++      void                            *addr_buf;
++      struct sctp_af                  *af;
++      struct list_head                *pos;
++      struct list_head                *p;
++      int                             i;
++      int                             retval = 0;
++
++      sp = sctp_sk(sk);
++      ep = sp->ep;
++
++      SCTP_DEBUG_PRINTK("%s: (sk: %p, addrs: %p, addrcnt: %d)\n",
++                        __FUNCTION__, sk, addrs, addrcnt);
++
++      list_for_each(pos, &ep->asocs) {
++              asoc = list_entry(pos, struct sctp_association, asocs);
++
++              if (!sctp_state(asoc, ESTABLISHED))
++                      continue;
++
++              if (!asoc->peer.asconf_capable)
++                      continue;
++              
++              /* Check if any address in the packed array of addresses is
++               * in the bind address list of the association. If so, 
++               * do not send the asconf chunk to its peer, but continue with 
++               * other associations.
++               */
++              addr_buf = addrs;
++              for (i = 0; i < addrcnt; i++) {
++                      addr = (union sctp_addr *)addr_buf;
++                      af = sctp_get_af_specific(addr->v4.sin_family);
++                      if (!af) {
++                              retval = -EINVAL;
++                              goto out;
++                      }
++
++                      if (sctp_assoc_lookup_laddr(asoc, addr))                
++                              break;
++                      
++                      addr_buf += af->sockaddr_len;
++              }
++              if (i < addrcnt)
++                      continue;
++
++              /* Use the first address in bind addr list of association as
++               * Address Parameter of ASCONF CHUNK.
++               */
++              sctp_read_lock(&asoc->base.addr_lock);
++              bp = &asoc->base.bind_addr;
++              p = bp->address_list.next;
++              laddr = list_entry(p, struct sctp_sockaddr_entry, list);
++              sctp_read_unlock(&asoc->base.addr_lock);
++
++              chunk = sctp_make_asconf_update_ip(asoc, &laddr->a, addrs,
++                                                 addrcnt, SCTP_PARAM_ADD_IP);
++              if (!chunk) {
++                      retval = -ENOMEM;
++                      goto out;
++              }
++
++              retval = sctp_primitive_ASCONF(asoc, chunk);
++              if (retval) {
++                      sctp_chunk_free(chunk);
++                      goto out;
++              }
++
++              /* FIXME: After sending the add address ASCONF chunk, we 
++               * cannot append the address to the association's binding 
++               * address list, because the new address may be used as the
++               * source of a message sent to the peer before the ASCONF
++               * chunk is received by the peer.  So we should wait until
++               * ASCONF_ACK is received.
++               */
++      }
++
++out:
++      return retval;
++}
++
+ /* Remove a list of addresses from bind addresses list.  Do not remove the
+  * last address.
+  *
+@@ -436,6 +538,106 @@ err_bindx_rem:
+       return retval;
+ }
++/* Send an ASCONF chunk with Delete IP address parameters to all the peers of
++ * the associations that are part of the endpoint indicating that a list of
++ * local addresses are removed from the endpoint.
++ *
++ * If any of the addresses is already in the bind address list of the 
++ * association, we do not send the chunk for that association.  But it will not
++ * affect other associations.
++ *
++ * Only sctp_setsockopt_bindx() is supposed to call this function.
++ */
++static int sctp_send_asconf_del_ip(struct sock                *sk,
++                                 struct sockaddr      *addrs,
++                                 int                  addrcnt)
++{
++      struct sctp_opt         *sp;
++      struct sctp_endpoint    *ep;
++      struct sctp_association *asoc;
++      struct sctp_bind_addr   *bp;
++      struct sctp_chunk       *chunk;
++      union sctp_addr         *laddr;
++      void                    *addr_buf;
++      struct sctp_af          *af;
++      struct list_head        *pos;
++      int                     i;
++      int                     retval = 0;
++
++      sp = sctp_sk(sk);
++      ep = sp->ep;
++
++      SCTP_DEBUG_PRINTK("%s: (sk: %p, addrs: %p, addrcnt: %d)\n",
++                        __FUNCTION__, sk, addrs, addrcnt);
++
++      list_for_each(pos, &ep->asocs) {
++              asoc = list_entry(pos, struct sctp_association, asocs);
++
++              if (!sctp_state(asoc, ESTABLISHED))
++                      continue;
++
++              if (!asoc->peer.asconf_capable)
++                      continue;
++
++              /* Check if any address in the packed array of addresses is
++               * not present in the bind address list of the association.
++               * If so, do not send the asconf chunk to its peer, but
++               * continue with other associations.
++               */
++              addr_buf = addrs;
++              for (i = 0; i < addrcnt; i++) {
++                      laddr = (union sctp_addr *)addr_buf;
++                      af = sctp_get_af_specific(laddr->v4.sin_family);
++                      if (!af) {
++                              retval = -EINVAL;
++                              goto out;
++                      }
++
++                      if (!sctp_assoc_lookup_laddr(asoc, laddr))              
++                              break;
++                      
++                      addr_buf += af->sockaddr_len;
++              }
++              if (i < addrcnt)
++                      continue;
++
++              /* Find one address in the association's bind address list
++               * that is not in the packed array of addresses. This is to
++               * make sure that we do not delete all the addresses in the
++               * association.
++               */
++              sctp_read_lock(&asoc->base.addr_lock);
++              bp = &asoc->base.bind_addr;
++              laddr = sctp_find_unmatch_addr(bp, (union sctp_addr *)addrs,
++                                             addrcnt, sp);
++              sctp_read_unlock(&asoc->base.addr_lock);                
++              if (!laddr)
++                      continue;
++
++              chunk = sctp_make_asconf_update_ip(asoc, laddr, addrs, addrcnt, 
++                                                 SCTP_PARAM_DEL_IP);
++              if (!chunk) {
++                      retval = -ENOMEM;
++                      goto out;
++              }
++
++              retval = sctp_primitive_ASCONF(asoc, chunk);
++              if (retval) {
++                      sctp_chunk_free(chunk);
++                      goto out;
++              }
++
++              /* FIXME: After sending the delete address ASCONF chunk, we
++               * cannot remove the addresses from the association's bind
++               * address list, because there maybe some packet send to
++               * the delete addresses, so we should wait until ASCONF_ACK 
++               * packet is received.
++               */
++      }
++out:
++      return retval;
++}
++
+ /* Helper for tunneling sctp_bindx() requests through sctp_setsockopt()
+  *
+  * API 8.1
+@@ -564,10 +766,16 @@ SCTP_STATIC int sctp_setsockopt_bindx(st
+       switch (op) {
+       case SCTP_BINDX_ADD_ADDR:
+               err = sctp_bindx_add(sk, kaddrs, addrcnt);
++              if (err)
++                      goto out;
++              err = sctp_send_asconf_add_ip(sk, kaddrs, addrcnt);
+               break;
+       case SCTP_BINDX_REM_ADDR:
+               err = sctp_bindx_rem(sk, kaddrs, addrcnt);
++              if (err)
++                      goto out;
++              err = sctp_send_asconf_del_ip(sk, kaddrs, addrcnt);
+               break;
+       default:
+@@ -575,6 +783,7 @@ SCTP_STATIC int sctp_setsockopt_bindx(st
+               break;
+         };
++out:
+       kfree(kaddrs);
+       return err;
+@@ -962,8 +1171,8 @@ SCTP_STATIC int sctp_sendmsg(struct kioc
+                                       = sinit->sinit_max_attempts;
+                       }
+                       if (sinit->sinit_max_init_timeo) {
+-                              asoc->max_init_timeo
+-                                      = sinit->sinit_max_init_timeo * HZ;
++                              asoc->max_init_timeo = 
++                               MSECS_TO_JIFFIES(sinit->sinit_max_init_timeo);
+                       }
+               }
+@@ -1401,7 +1610,8 @@ static int sctp_setsockopt_peer_addr_par
+        */
+               if (params.spp_hbinterval) {
+                       trans->hb_allowed = 1;
+-                      trans->hb_interval = params.spp_hbinterval * HZ / 1000;
++                      trans->hb_interval = 
++                              MSECS_TO_JIFFIES(params.spp_hbinterval);
+               } else
+                       trans->hb_allowed = 0;
+       }
+@@ -1560,11 +1770,12 @@ static int sctp_setsockopt_rtoinfo(struc
+       if (asoc) {
+               if (rtoinfo.srto_initial != 0)
+-                      asoc->rto_initial = rtoinfo.srto_initial * HZ / 1000;
++                      asoc->rto_initial = 
++                              MSECS_TO_JIFFIES(rtoinfo.srto_initial);
+               if (rtoinfo.srto_max != 0)
+-                      asoc->rto_max = rtoinfo.srto_max * HZ / 1000;
++                      asoc->rto_max = MSECS_TO_JIFFIES(rtoinfo.srto_max);
+               if (rtoinfo.srto_min != 0)
+-                      asoc->rto_min = rtoinfo.srto_min * HZ / 1000;
++                      asoc->rto_min = MSECS_TO_JIFFIES(rtoinfo.srto_min);
+       } else {
+               /* If there is no association or the association-id = 0
+                * set the values to the endpoint.
+@@ -2088,14 +2299,14 @@ SCTP_STATIC int sctp_init_sock(struct so
+       sp->initmsg.sinit_num_ostreams   = sctp_max_outstreams;
+       sp->initmsg.sinit_max_instreams  = sctp_max_instreams;
+       sp->initmsg.sinit_max_attempts   = sctp_max_retrans_init;
+-      sp->initmsg.sinit_max_init_timeo = (sctp_rto_max / HZ) * 1000;
++      sp->initmsg.sinit_max_init_timeo = JIFFIES_TO_MSECS(sctp_rto_max);
+       /* Initialize default RTO related parameters.  These parameters can
+        * be modified for with the SCTP_RTOINFO socket option.
+        */
+-      sp->rtoinfo.srto_initial = (sctp_rto_initial / HZ) * 1000;
+-      sp->rtoinfo.srto_max     = (sctp_rto_max / HZ) * 1000;
+-      sp->rtoinfo.srto_min     = (sctp_rto_min / HZ) * 1000;
++      sp->rtoinfo.srto_initial = JIFFIES_TO_MSECS(sctp_rto_initial);
++      sp->rtoinfo.srto_max     = JIFFIES_TO_MSECS(sctp_rto_max);
++      sp->rtoinfo.srto_min     = JIFFIES_TO_MSECS(sctp_rto_min);
+       /* Initialize default association related parameters. These parameters
+        * can be modified with the SCTP_ASSOCINFO socket option.
+@@ -2104,8 +2315,8 @@ SCTP_STATIC int sctp_init_sock(struct so
+       sp->assocparams.sasoc_number_peer_destinations = 0;
+       sp->assocparams.sasoc_peer_rwnd = 0;
+       sp->assocparams.sasoc_local_rwnd = 0;
+-      sp->assocparams.sasoc_cookie_life = (sctp_valid_cookie_life / HZ)
+-                                      * 1000;
++      sp->assocparams.sasoc_cookie_life = 
++              JIFFIES_TO_MSECS(sctp_valid_cookie_life);
+       /* Initialize default event subscriptions. By default, all the
+        * options are off. 
+@@ -2115,7 +2326,7 @@ SCTP_STATIC int sctp_init_sock(struct so
+       /* Default Peer Address Parameters.  These defaults can
+        * be modified via SCTP_PEER_ADDR_PARAMS
+        */
+-      sp->paddrparam.spp_hbinterval = (sctp_hb_interval / HZ) * 1000;
++      sp->paddrparam.spp_hbinterval = JIFFIES_TO_MSECS(sctp_hb_interval);
+       sp->paddrparam.spp_pathmaxrxt = sctp_max_retrans_path;
+       /* If enabled no SCTP message fragmentation will be performed.
+@@ -2265,7 +2476,7 @@ static int sctp_getsockopt_sctp_status(s
+       status.sstat_primary.spinfo_state = transport->active;
+       status.sstat_primary.spinfo_cwnd = transport->cwnd;
+       status.sstat_primary.spinfo_srtt = transport->srtt;
+-      status.sstat_primary.spinfo_rto = (transport->rto / HZ) * 1000;
++      status.sstat_primary.spinfo_rto = JIFFIES_TO_MSECS(transport->rto);
+       status.sstat_primary.spinfo_mtu = transport->pmtu;
+       if (put_user(len, optlen)) {
+@@ -2320,7 +2531,7 @@ static int sctp_getsockopt_peer_addr_inf
+       pinfo.spinfo_state = transport->active;
+       pinfo.spinfo_cwnd = transport->cwnd;
+       pinfo.spinfo_srtt = transport->srtt;
+-      pinfo.spinfo_rto = (transport->rto / HZ) * 1000;
++      pinfo.spinfo_rto = JIFFIES_TO_MSECS(transport->rto);
+       pinfo.spinfo_mtu = transport->pmtu;
+       if (put_user(len, optlen)) {
+@@ -2524,7 +2735,7 @@ static int sctp_getsockopt_peer_addr_par
+       if (!trans->hb_allowed)
+               params.spp_hbinterval = 0;
+       else
+-              params.spp_hbinterval = trans->hb_interval * 1000 / HZ;
++              params.spp_hbinterval = JIFFIES_TO_MSECS(trans->hb_interval);
+       /* spp_pathmaxrxt contains the maximum number of retransmissions
+        * before this address shall be considered unreachable.
+@@ -2582,10 +2793,8 @@ static int sctp_getsockopt_peer_addrs_nu
+       list_for_each(pos, &asoc->peer.transport_addr_list) {
+               cnt ++;
+       }
+-      if (copy_to_user(optval, &cnt, sizeof(int)))
+-              return -EFAULT;
+-      return 0;
++      return cnt;
+ }
+ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len,
+@@ -2666,10 +2875,8 @@ static int sctp_getsockopt_local_addrs_n
+       list_for_each(pos, &bp->address_list) {
+               cnt ++;
+       }
+-      if (copy_to_user(optval, &cnt, sizeof(int)))
+-              return -EFAULT;
+-      return 0;
++      return cnt;
+ }
+ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
+@@ -2879,9 +3086,9 @@ static int sctp_getsockopt_rtoinfo(struc
+       /* Values corresponding to the specific association. */
+       if (asoc) {
+-              rtoinfo.srto_initial = (asoc->rto_initial / HZ) * 1000;
+-              rtoinfo.srto_max = (asoc->rto_max / HZ) * 1000;
+-              rtoinfo.srto_min = (asoc->rto_min / HZ) * 1000;
++              rtoinfo.srto_initial = JIFFIES_TO_MSECS(asoc->rto_initial);
++              rtoinfo.srto_max = JIFFIES_TO_MSECS(asoc->rto_max);
++              rtoinfo.srto_min = JIFFIES_TO_MSECS(asoc->rto_min);
+       } else {
+               /* Values corresponding to the endpoint. */
+               struct sctp_opt *sp = sctp_sk(sk);
+--- linux-2.6.0-test6/net/sctp/sysctl.c        2003-09-08 13:58:59.000000000 -0700
++++ 25/net/sctp/sysctl.c       2003-10-05 00:33:25.000000000 -0700
+@@ -44,7 +44,7 @@
+ #include <linux/sysctl.h>
+ static ctl_handler sctp_sysctl_jiffies_ms;
+-static long rto_timer_min = 0;
++static long rto_timer_min = 1;
+ static long rto_timer_max = 86400000; /* One day */
+ static ctl_table sctp_table[] = {
+--- linux-2.6.0-test6/net/socket.c     2003-09-08 13:58:59.000000000 -0700
++++ 25/net/socket.c    2003-10-05 00:34:03.000000000 -0700
+@@ -394,6 +394,7 @@ int sock_map_fd(struct socket *sock)
+               file->f_dentry->d_op = &sockfs_dentry_operations;
+               d_add(file->f_dentry, SOCK_INODE(sock));
+               file->f_vfsmnt = mntget(sock_mnt);
++              file->f_mapping = file->f_dentry->d_inode->i_mapping;
+               sock->file = file;
+               file->f_op = SOCK_INODE(sock)->i_fop = &socket_file_ops;
+@@ -1989,3 +1990,18 @@ void socket_seq_show(struct seq_file *se
+       seq_printf(seq, "sockets: used %d\n", counter);
+ }
+ #endif /* CONFIG_PROC_FS */
++
++/* ABI emulation layers need these two */
++EXPORT_SYMBOL(move_addr_to_kernel);
++EXPORT_SYMBOL(move_addr_to_user);
++EXPORT_SYMBOL(sock_alloc);
++EXPORT_SYMBOL(sock_alloc_inode);
++EXPORT_SYMBOL(sock_create);
++EXPORT_SYMBOL(sock_map_fd);
++EXPORT_SYMBOL(sock_recvmsg);
++EXPORT_SYMBOL(sock_register);
++EXPORT_SYMBOL(sock_release);
++EXPORT_SYMBOL(sock_sendmsg);
++EXPORT_SYMBOL(sock_unregister);
++EXPORT_SYMBOL(sock_wake_async);
++EXPORT_SYMBOL(sockfd_lookup);
+--- linux-2.6.0-test6/net/unix/af_unix.c       2003-09-08 13:58:59.000000000 -0700
++++ 25/net/unix/af_unix.c      2003-10-05 00:33:25.000000000 -0700
+@@ -448,7 +448,7 @@ static int unix_listen(struct socket *so
+       sk->sk_max_ack_backlog  = backlog;
+       sk->sk_state            = TCP_LISTEN;
+       /* set credentials so connect can copy them */
+-      sk->sk_peercred.pid     = current->pid;
++      sk->sk_peercred.pid     = current->tgid;
+       sk->sk_peercred.uid     = current->euid;
+       sk->sk_peercred.gid     = current->egid;
+       err = 0;
+@@ -983,7 +983,7 @@ restart:
+       unix_peer(newsk)        = sk;
+       newsk->sk_state         = TCP_ESTABLISHED;
+       newsk->sk_type          = SOCK_STREAM;
+-      newsk->sk_peercred.pid  = current->pid;
++      newsk->sk_peercred.pid  = current->tgid;
+       newsk->sk_peercred.uid  = current->euid;
+       newsk->sk_peercred.gid  = current->egid;
+       newu = unix_sk(newsk);
+@@ -1045,7 +1045,7 @@ static int unix_socketpair(struct socket
+       sock_hold(skb);
+       unix_peer(ska)=skb;
+       unix_peer(skb)=ska;
+-      ska->sk_peercred.pid = skb->sk_peercred.pid = current->pid;
++      ska->sk_peercred.pid = skb->sk_peercred.pid = current->tgid;
+       ska->sk_peercred.uid = skb->sk_peercred.uid = current->euid;
+       ska->sk_peercred.gid = skb->sk_peercred.gid = current->egid;
+--- linux-2.6.0-test6/net/x25/af_x25.c 2003-09-08 13:58:59.000000000 -0700
++++ 25/net/x25/af_x25.c        2003-10-05 00:34:48.000000000 -0700
+@@ -345,10 +345,8 @@ void x25_destroy_socket(struct sock *sk)
+       if (atomic_read(&sk->sk_wmem_alloc) ||
+           atomic_read(&sk->sk_rmem_alloc)) {
+               /* Defer: outstanding buffers */
+-              init_timer(&sk->sk_timer);
+               sk->sk_timer.expires  = jiffies + 10 * HZ;
+               sk->sk_timer.function = x25_destroy_timer;
+-              sk->sk_timer.data     = (unsigned long)sk;
+               add_timer(&sk->sk_timer);
+       } else {
+               /* drop last reference so sock_put will free */
+@@ -463,6 +461,8 @@ frees:
+       goto out;
+ }
++void x25_init_timers(struct sock *sk);
++
+ static int x25_create(struct socket *sock, int protocol)
+ {
+       struct sock *sk;
+@@ -481,7 +481,7 @@ static int x25_create(struct socket *soc
+       sock_init_data(sock, sk);
+       sk_set_owner(sk, THIS_MODULE);
+-      init_timer(&x25->timer);
++      x25_init_timers(sk);
+       sock->ops    = &x25_proto_ops;
+       sk->sk_protocol = protocol;
+@@ -537,7 +537,7 @@ static struct sock *x25_make_new(struct 
+       x25->facilities = ox25->facilities;
+       x25->qbitincl   = ox25->qbitincl;
+-      init_timer(&x25->timer);
++      x25_init_timers(sk);
+ out:
+       return sk;
+ }
+--- linux-2.6.0-test6/net/x25/x25_link.c       2003-06-14 12:17:57.000000000 -0700
++++ 25/net/x25/x25_link.c      2003-10-05 00:34:48.000000000 -0700
+@@ -51,15 +51,9 @@ static void x25_t20timer_expiry(unsigned
+ /*
+  *    Linux set/reset timer routines
+  */
+-static void x25_start_t20timer(struct x25_neigh *nb)
++static inline void x25_start_t20timer(struct x25_neigh *nb)
+ {
+-      del_timer(&nb->t20timer);
+-
+-      nb->t20timer.data     = (unsigned long)nb;
+-      nb->t20timer.function = &x25_t20timer_expiry;
+-      nb->t20timer.expires  = jiffies + nb->t20;
+-
+-      add_timer(&nb->t20timer);
++      mod_timer(&nb->t20timer, jiffies + nb->t20);
+ }
+ static void x25_t20timer_expiry(unsigned long param)
+@@ -71,12 +65,12 @@ static void x25_t20timer_expiry(unsigned
+       x25_start_t20timer(nb);
+ }
+-static void x25_stop_t20timer(struct x25_neigh *nb)
++static inline void x25_stop_t20timer(struct x25_neigh *nb)
+ {
+       del_timer(&nb->t20timer);
+ }
+-static int x25_t20timer_pending(struct x25_neigh *nb)
++static inline int x25_t20timer_pending(struct x25_neigh *nb)
+ {
+       return timer_pending(&nb->t20timer);
+ }
+@@ -291,6 +285,8 @@ void x25_link_device_up(struct net_devic
+       skb_queue_head_init(&nb->queue);
+       init_timer(&nb->t20timer);
++      nb->t20timer.data     = (unsigned long)nb;
++      nb->t20timer.function = &x25_t20timer_expiry;
+       dev_hold(dev);
+       nb->dev      = dev;
+--- linux-2.6.0-test6/net/x25/x25_timer.c      2003-06-14 12:17:57.000000000 -0700
++++ 25/net/x25/x25_timer.c     2003-10-05 00:34:48.000000000 -0700
+@@ -43,15 +43,22 @@
+ static void x25_heartbeat_expiry(unsigned long);
+ static void x25_timer_expiry(unsigned long);
+-void x25_start_heartbeat(struct sock *sk)
++void x25_init_timers(struct sock *sk)
+ {
+-      del_timer(&sk->sk_timer);
++      struct x25_opt *x25 = x25_sk(sk);
++      init_timer(&x25->timer);
++      x25->timer.data     = (unsigned long)sk;
++      x25->timer.function = &x25_timer_expiry;
++
++      /* initialized by sock_init_data */
+       sk->sk_timer.data     = (unsigned long)sk;
+       sk->sk_timer.function = &x25_heartbeat_expiry;
+-      sk->sk_timer.expires  = jiffies + 5 * HZ;
++}
+-      add_timer(&sk->sk_timer);
++void x25_start_heartbeat(struct sock *sk)
++{
++      mod_timer(&sk->sk_timer, jiffies + 5 * HZ);
+ }
+ void x25_stop_heartbeat(struct sock *sk)
+@@ -63,52 +70,28 @@ void x25_start_t2timer(struct sock *sk)
+ {
+       struct x25_opt *x25 = x25_sk(sk);
+-      del_timer(&x25->timer);
+-
+-      x25->timer.data     = (unsigned long)sk;
+-      x25->timer.function = &x25_timer_expiry;
+-      x25->timer.expires  = jiffies + x25->t2;
+-
+-      add_timer(&x25->timer);
++      mod_timer(&x25->timer, jiffies + x25->t2);
+ }
+ void x25_start_t21timer(struct sock *sk)
+ {
+       struct x25_opt *x25 = x25_sk(sk);
+-      del_timer(&x25->timer);
+-
+-      x25->timer.data     = (unsigned long)sk;
+-      x25->timer.function = &x25_timer_expiry;
+-      x25->timer.expires  = jiffies + x25->t21;
+-
+-      add_timer(&x25->timer);
++      mod_timer(&x25->timer, jiffies + x25->t21);
+ }
+ void x25_start_t22timer(struct sock *sk)
+ {
+       struct x25_opt *x25 = x25_sk(sk);
+-      del_timer(&x25->timer);
+-
+-      x25->timer.data     = (unsigned long)sk;
+-      x25->timer.function = &x25_timer_expiry;
+-      x25->timer.expires  = jiffies + x25->t22;
+-
+-      add_timer(&x25->timer);
++      mod_timer(&x25->timer, jiffies + x25->t22);
+ }
+ void x25_start_t23timer(struct sock *sk)
+ {
+       struct x25_opt *x25 = x25_sk(sk);
+-      del_timer(&x25->timer);
+-
+-      x25->timer.data     = (unsigned long)sk;
+-      x25->timer.function = &x25_timer_expiry;
+-      x25->timer.expires  = jiffies + x25->t23;
+-
+-      add_timer(&x25->timer);
++      mod_timer(&x25->timer, jiffies + x25->t23);
+ }
+ void x25_stop_timer(struct sock *sk)
+--- linux-2.6.0-test6/net/xfrm/xfrm_algo.c     2003-08-22 19:23:42.000000000 -0700
++++ 25/net/xfrm/xfrm_algo.c    2003-10-05 00:33:25.000000000 -0700
+@@ -8,7 +8,9 @@
+  * Software Foundation; either version 2 of the License, or (at your option) 
+  * any later version.
+  */
++
+ #include <linux/config.h>
++#include <linux/module.h>
+ #include <linux/kernel.h>
+ #include <linux/pfkeyv2.h>
+ #include <net/xfrm.h>
+@@ -617,6 +619,7 @@ skb_to_sgvec(struct sk_buff *skb, struct
+               BUG();
+       return elt;
+ }
++EXPORT_SYMBOL_GPL(skb_to_sgvec);
+ /* Check that skb data bits are writable. If they are not, copy data
+  * to newly created private area. If "tailbits" is given, make sure that
+@@ -717,6 +720,7 @@ int skb_cow_data(struct sk_buff *skb, in
+       return elt;
+ }
++EXPORT_SYMBOL_GPL(skb_cow_data);
+ void *pskb_put(struct sk_buff *skb, struct sk_buff *tail, int len)
+ {
+@@ -726,4 +730,5 @@ void *pskb_put(struct sk_buff *skb, stru
+       }
+       return skb_put(tail, len);
+ }
++EXPORT_SYMBOL_GPL(pskb_put);
+ #endif
+--- linux-2.6.0-test6/scripts/bin2c.c  2003-09-27 18:57:47.000000000 -0700
++++ 25/scripts/bin2c.c 2003-10-05 00:33:25.000000000 -0700
+@@ -1,3 +1,12 @@
++/*
++ * Unloved program to convert a binary on stdin to a C include on stdout
++ *
++ * Jan 1999 Matt Mackall <mpm@selenic.com>
++ *
++ * This software may be used and distributed according to the terms
++ * of the GNU General Public License, incorporated herein by reference.
++ */
++
+ #include <stdio.h>
+ int main(int argc, char *argv[])
+--- linux-2.6.0-test6/scripts/pnmtologo.c      2003-08-08 22:55:14.000000000 -0700
++++ 25/scripts/pnmtologo.c     2003-10-05 00:33:25.000000000 -0700
+@@ -119,7 +119,8 @@ static unsigned int get_number255(FILE *
+ static void read_image(void)
+ {
+     FILE *fp;
+-    int i, j, magic;
++    unsigned int i, j;
++    int magic;
+     unsigned int maxval;
+     /* open image file */
+@@ -274,7 +275,7 @@ static void write_hex(unsigned char byte
+ static void write_logo_mono(void)
+ {
+-    int i, j;
++    unsigned int i, j;
+     unsigned char val, bit;
+     /* validate image */
+@@ -302,7 +303,7 @@ static void write_logo_mono(void)
+ static void write_logo_vga16(void)
+ {
+-    int i, j, k;
++    unsigned int i, j, k;
+     unsigned char val;
+     /* validate image */
+@@ -342,7 +343,7 @@ static void write_logo_vga16(void)
+ static void write_logo_clut224(void)
+ {
+-    int i, j, k;
++    unsigned int i, j, k;
+     /* validate image */
+     for (i = 0; i < logo_height; i++)
+@@ -388,7 +389,7 @@ static void write_logo_clut224(void)
+ static void write_logo_gray256(void)
+ {
+-    int i, j;
++    unsigned int i, j;
+     /* validate image */
+     for (i = 0; i < logo_height; i++)
+--- linux-2.6.0-test6/security/dummy.c 2003-07-10 18:50:32.000000000 -0700
++++ 25/security/dummy.c        2003-10-05 00:33:25.000000000 -0700
+@@ -364,7 +364,7 @@ static int dummy_inode_follow_link (stru
+       return 0;
+ }
+-static int dummy_inode_permission (struct inode *inode, int mask)
++static int dummy_inode_permission (struct inode *inode, int mask, struct nameidata *nd)
+ {
+       return 0;
+ }
+--- linux-2.6.0-test6/security/selinux/hooks.c 2003-09-27 18:57:47.000000000 -0700
++++ 25/security/selinux/hooks.c        2003-10-05 00:33:25.000000000 -0700
+@@ -1730,13 +1730,18 @@ static int selinux_inode_follow_link(str
+       return dentry_has_perm(current, NULL, dentry, FILE__READ);
+ }
+-static int selinux_inode_permission(struct inode *inode, int mask)
++static int selinux_inode_permission(struct inode *inode, int mask,
++                                  struct nameidata *nd)
+ {
+       if (!mask) {
+               /* No permission to check.  Existence test. */
+               return 0;
+       }
++      if (nd && nd->dentry)
++              return dentry_has_perm(current, nd->mnt, nd->dentry,
++                                     file_mask_to_av(inode->i_mode, mask));
++
+       return inode_has_perm(current, inode,
+                              file_mask_to_av(inode->i_mode, mask), NULL, NULL);
+ }
+--- linux-2.6.0-test6/security/selinux/ss/services.c   2003-08-08 22:55:14.000000000 -0700
++++ 25/security/selinux/ss/services.c  2003-10-05 00:33:25.000000000 -0700
+@@ -896,7 +896,7 @@ static int convert_context(u32 key,
+       struct user_datum *usrdatum;
+       char *s;
+       u32 len;
+-      int rc = -EINVAL;
++      int rc;
+       args = p;
+@@ -904,6 +904,8 @@ static int convert_context(u32 key,
+       if (rc)
+               goto out;
++      rc = -EINVAL;
++
+       /* Convert the user. */
+       usrdatum = hashtab_search(args->newp->p_users.table,
+                                 args->oldp->p_user_val_to_name[c->user - 1]);
+--- linux-2.6.0-test6/sound/oss/ac97_codec.c   2003-09-27 18:57:47.000000000 -0700
++++ 25/sound/oss/ac97_codec.c  2003-10-05 00:33:25.000000000 -0700
+@@ -46,7 +46,6 @@
+  *    Isolated from trident.c to support multiple ac97 codec
+  */
+ #include <linux/module.h>
+-#include <linux/version.h>
+ #include <linux/kernel.h>
+ #include <linux/slab.h>
+ #include <linux/string.h>
+--- linux-2.6.0-test6/sound/oss/ali5455.c      2003-09-08 13:58:59.000000000 -0700
++++ 25/sound/oss/ali5455.c     2003-10-05 00:33:25.000000000 -0700
+@@ -47,7 +47,6 @@
+  */
+ #include <linux/module.h>
+-#include <linux/version.h>
+ #include <linux/string.h>
+ #include <linux/ctype.h>
+ #include <linux/ioport.h>
+--- linux-2.6.0-test6/sound/oss/au1000.c       2003-09-08 13:58:59.000000000 -0700
++++ 25/sound/oss/au1000.c      2003-10-05 00:33:25.000000000 -0700
+@@ -50,7 +50,6 @@
+  *                channels [stevel].
+  *
+  */
+-#include <linux/version.h>
+ #include <linux/module.h>
+ #include <linux/string.h>
+ #include <linux/ioport.h>
+@@ -2223,8 +2222,9 @@ static int __init au1000_setup(char *opt
+       if (!options || !*options)
+               return 0;
+-      for(this_opt=strtok(options, ",");
+-          this_opt; this_opt=strtok(NULL, ",")) {
++      while (this_opt = strsep(&options, ",")) {
++              if (!*this_opt)
++                      continue;
+               if (!strncmp(this_opt, "vra", 3)) {
+                       vra = 1;
+               }
+--- linux-2.6.0-test6/sound/oss/btaudio.c      2003-09-08 13:58:59.000000000 -0700
++++ 25/sound/oss/btaudio.c     2003-10-05 00:33:25.000000000 -0700
+@@ -177,8 +177,11 @@ static int alloc_buffer(struct btaudio *
+               bta->risc_size = PAGE_SIZE;
+               bta->risc_cpu = pci_alloc_consistent
+                       (bta->pci, bta->risc_size, &bta->risc_dma);
+-              if (NULL == bta->risc_cpu)
++              if (NULL == bta->risc_cpu) {
++                      pci_free_consistent(bta->pci, bta->buf_size, bta->buf_cpu, bta->buf_dma);
++                      bta->buf_cpu = NULL;
+                       return -ENOMEM;
++              }
+       }
+       return 0;
+ }
+--- linux-2.6.0-test6/sound/oss/dmasound/dac3550a.c    2003-09-27 18:57:48.000000000 -0700
++++ 25/sound/oss/dmasound/dac3550a.c   2003-10-05 00:33:25.000000000 -0700
+@@ -7,7 +7,6 @@
+  *  for more details.
+  */
+-#include <linux/version.h>
+ #include <linux/module.h>
+ #include <linux/slab.h>
+ #include <linux/proc_fs.h>
+--- linux-2.6.0-test6/sound/oss/dmasound/Kconfig       2003-09-27 18:57:47.000000000 -0700
++++ 25/sound/oss/dmasound/Kconfig      2003-10-05 00:33:25.000000000 -0700
+@@ -1,7 +1,7 @@
+-# drivers/sound/dmasound/Config.in
+ config DMASOUND_ATARI
+       tristate "Atari DMA sound support"
+       depends on ATARI && SOUND
++      select DMASOUND
+       help
+         If you want to use the internal audio of your Atari in Linux, answer
+         Y to this question. This will provide a Sun-like /dev/audio,
+@@ -15,6 +15,7 @@ config DMASOUND_ATARI
+ config DMASOUND_PMAC
+       tristate "PowerMac DMA sound support"
+       depends on PPC_PMAC && SOUND && I2C
++      select DMASOUND
+       help
+         If you want to use the internal audio of your PowerMac in Linux,
+         answer Y to this question. This will provide a Sun-like /dev/audio,
+@@ -28,6 +29,7 @@ config DMASOUND_PMAC
+ config DMASOUND_PAULA
+       tristate "Amiga DMA sound support"
+       depends on (AMIGA || APUS) && SOUND
++      select DMASOUND
+       help
+         If you want to use the internal audio of your Amiga in Linux, answer
+         Y to this question. This will provide a Sun-like /dev/audio,
+@@ -41,6 +43,7 @@ config DMASOUND_PAULA
+ config DMASOUND_Q40
+       tristate "Q40 sound support"
+       depends on Q40 && SOUND
++      select DMASOUND
+       help
+         If you want to use the internal audio of your Q40 in Linux, answer
+         Y to this question. This will provide a Sun-like /dev/audio,
+@@ -53,13 +56,3 @@ config DMASOUND_Q40
+ config DMASOUND
+       tristate
+-      depends on SOUND!=n
+-      default m if DMASOUND_ATARI!=y && DMASOUND_AWACS!=y && DMASOUND_PAULA!=y && DMASOUND_Q40!=y && (DMASOUND_ATARI=m || DMASOUND_AWACS=m || DMASOUND_PAULA=m || DMASOUND_Q40=m)
+-      default y if DMASOUND_ATARI=y || DMASOUND_AWACS=y || DMASOUND_PAULA=y || DMASOUND_Q40=y
+-      help
+-        Support built-in audio chips accessible by DMA on various machines
+-        that have them.  Note that this symbol does not affect the kernel
+-        directly; rather, it controls whether configuration questions
+-        enabling DMA sound drivers for various specific machine
+-        architectures will be used.
+-
+--- linux-2.6.0-test6/sound/oss/dmasound/tas3001c.c    2003-09-27 18:57:48.000000000 -0700
++++ 25/sound/oss/dmasound/tas3001c.c   2003-10-05 00:33:25.000000000 -0700
+@@ -15,7 +15,6 @@
+  *
+  */
+-#include <linux/version.h>
+ #include <linux/module.h>
+ #include <linux/slab.h>
+ #include <linux/proc_fs.h>
+--- linux-2.6.0-test6/sound/oss/dmasound/tas3004.c     2003-09-27 18:57:48.000000000 -0700
++++ 25/sound/oss/dmasound/tas3004.c    2003-10-05 00:33:25.000000000 -0700
+@@ -13,7 +13,6 @@
+  *
+  */
+-#include <linux/version.h>
+ #include <linux/module.h>
+ #include <linux/slab.h>
+ #include <linux/proc_fs.h>
+--- linux-2.6.0-test6/sound/oss/dmasound/tas_common.c  2003-09-27 18:57:48.000000000 -0700
++++ 25/sound/oss/dmasound/tas_common.c 2003-10-05 00:33:25.000000000 -0700
+@@ -1,4 +1,3 @@
+-#include <linux/version.h>
+ #include <linux/module.h>
+ #include <linux/slab.h>
+ #include <linux/proc_fs.h>
+--- linux-2.6.0-test6/sound/oss/harmony.c      2003-09-08 13:58:59.000000000 -0700
++++ 25/sound/oss/harmony.c     2003-10-05 00:33:25.000000000 -0700
+@@ -28,14 +28,14 @@ TODO:
+ #include <linux/delay.h>
+ #include <linux/errno.h>
+ #include <linux/init.h>
++#include <linux/interrupt.h>
+ #include <linux/ioport.h>
+ #include <linux/types.h>
+ #include <linux/mm.h>
+ #include <linux/pci.h>
+-#include <asm/gsc.h>
++#include <asm/parisc-device.h>
+ #include <asm/io.h>
+-#include <asm/pgalloc.h>
+ #include "sound_config.h"
+--- linux-2.6.0-test6/sound/oss/ite8172.c      2003-09-08 13:58:59.000000000 -0700
++++ 25/sound/oss/ite8172.c     2003-10-05 00:33:25.000000000 -0700
+@@ -54,7 +54,6 @@
+  *    07.30.2003  Removed initialisation to zero for static variables
+  *               (spdif[NR_DEVICE], i2s_fmt[NR_DEVICE], and devindex)
+  */
+-#include <linux/version.h>
+ #include <linux/module.h>
+ #include <linux/string.h>
+ #include <linux/ioport.h>
+@@ -2238,8 +2237,9 @@ static int __init it8172_setup(char *opt
+       if (!options || !*options)
+               return 0;
+-      for(this_opt=strtok(options, ",");
+-          this_opt; this_opt=strtok(NULL, ",")) {
++      while (this_opt = strsep(&options, ",")) {
++              if (!*this_opt)
++                      continue;
+               if (!strncmp(this_opt, "spdif", 5)) {
+                       spdif[nr_dev] = 1;
+               } else if (!strncmp(this_opt, "i2s:", 4)) {
+--- linux-2.6.0-test6/sound/oss/opl3sa2.c      2003-08-22 19:23:43.000000000 -0700
++++ 25/sound/oss/opl3sa2.c     2003-10-05 00:33:25.000000000 -0700
+@@ -324,15 +324,6 @@ static void opl3sa3_set_treble(opl3sa2_s
+ }
+-static void opl3sa3_set_wide(opl3sa2_state_t* devc, int left, int right)
+-{     
+-      unsigned char wide;
+-
+-      wide = left ? ((unsigned char) (8 * left / 101)) : 0; 
+-      wide |= (right ? ((unsigned char) (8 * right / 101)) : 0) << 4;
+-
+-      opl3sa2_write(devc->cfg_port, OPL3SA3_WIDE, wide);
+-}
+ static void opl3sa2_mixer_reset(opl3sa2_state_t* devc)
+@@ -401,7 +392,7 @@ static inline int ret_vol_stereo(int lef
+ static int opl3sa2_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
+ {
+-      int cmdf = cmd & 0xff;
++      int retval, value, cmdf = cmd & 0xff;
+       opl3sa2_state_t* devc = &opl3sa2_state[dev];
+       
+@@ -422,23 +413,31 @@ static int opl3sa2_mixer_ioctl(int dev, 
+       if (((cmd >> 8) & 0xff) != 'M')
+               return -EINVAL;
+               
++      retval = 0;
+       if (_SIOC_DIR (cmd) & _SIOC_WRITE) {
+               switch (cmdf) {
+                       case SOUND_MIXER_VOLUME:
+-                              arg_to_vol_stereo(*(unsigned int*)arg,
+-                                                &devc->volume_l, &devc->volume_r); 
++                              retval = get_user(value, (unsigned int *) arg);
++                              if (retval)
++                                      break;
++                              arg_to_vol_stereo(value, &devc->volume_l, &devc->volume_r);
+                               opl3sa2_set_volume(devc, devc->volume_l, devc->volume_r);
+-                              *(int*)arg = ret_vol_stereo(devc->volume_l, devc->volume_r);
+-                              return 0;
++                              value = ret_vol_stereo(devc->volume_l, devc->volume_r);
++                              retval = put_user(value, (int *) arg);
++                              break;
+                 
+                       case SOUND_MIXER_MIC:
+-                              arg_to_vol_mono(*(unsigned int*)arg, &devc->mic);
++                              retval = get_user(value, (unsigned int *) arg);
++                              if (retval)
++                                      break;
++                              arg_to_vol_mono(value, &devc->mic);
+                               opl3sa2_set_mic(devc, devc->mic);
+-                              *(int*)arg = ret_vol_mono(devc->mic);
+-                              return 0;
++                              value = ret_vol_mono(devc->mic);
++                              retval = put_user(value, (int *) arg);
++                              break;
+                       default:
+-                              return -EINVAL;
++                              retval = -EINVAL;
+               }
+       }
+       else {
+@@ -447,122 +446,72 @@ static int opl3sa2_mixer_ioctl(int dev, 
+                */
+               switch (cmdf) {
+                       case SOUND_MIXER_DEVMASK:
+-                              *(int*)arg = (SOUND_MASK_VOLUME | SOUND_MASK_MIC);
+-                              return 0;
++                              retval = put_user(SOUND_MASK_VOLUME | SOUND_MASK_MIC, (int *) arg);
++                              break;
+                 
+                       case SOUND_MIXER_STEREODEVS:
+-                              *(int*)arg = SOUND_MASK_VOLUME;
+-                              return 0;
++                              retval = put_user(SOUND_MASK_VOLUME, (int *) arg);
++                              break;
+                 
+                       case SOUND_MIXER_RECMASK:
+                               /* No recording devices */
+-                              return (*(int*)arg = 0);
++                              retval = put_user(0, (int *) arg);
++                              break;
+                       case SOUND_MIXER_CAPS:
+-                              *(int*)arg = SOUND_CAP_EXCL_INPUT;
+-                              return 0;
++                              retval = put_user(SOUND_CAP_EXCL_INPUT, (int *) arg);
++                              break;
+                       case SOUND_MIXER_RECSRC:
+                               /* No recording source */
+-                              return (*(int*)arg = 0);
++                              retval = put_user(0, (int *) arg);
++                              break;
+                       case SOUND_MIXER_VOLUME:
+-                              *(int*)arg = ret_vol_stereo(devc->volume_l, devc->volume_r);
+-                              return 0;
++                              value = ret_vol_stereo(devc->volume_l, devc->volume_r);
++                              retval = put_user(value, (int *) arg);
++                              break;
+                         
+                       case SOUND_MIXER_MIC:
+-                              *(int*)arg = ret_vol_mono(devc->mic);
+-                              return 0;
++                              value = ret_vol_mono(devc->mic);
++                              put_user(value, (int *) arg);
++                              break;
+                       default:
+-                              return -EINVAL;
++                              retval = -EINVAL;
+               }
+       }
++      return retval;
+ }
+ /* opl3sa2_mixer_ioctl end */
+ static int opl3sa3_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
+ {
+-      int cmdf = cmd & 0xff;
++      int value, retval, cmdf = cmd & 0xff;
+       opl3sa2_state_t* devc = &opl3sa2_state[dev];
+       switch (cmdf) {
+-              case SOUND_MIXER_BASS:
+-              case SOUND_MIXER_TREBLE:
+-              case SOUND_MIXER_DIGITAL1:
+-              case SOUND_MIXER_DEVMASK:
+-              case SOUND_MIXER_STEREODEVS: 
+-                      break;
+-
+-              default:
+-                      return opl3sa2_mixer_ioctl(dev, cmd, arg);
+-      }
+-
+-      if (((cmd >> 8) & 0xff) != 'M')
+-              return -EINVAL;
++      case SOUND_MIXER_BASS:
++              value = ret_vol_stereo(devc->bass_l, devc->bass_r);
++              retval = put_user(value, (int *) arg);
++              break;
+               
+-      if (_SIOC_DIR (cmd) & _SIOC_WRITE) {
+-              switch (cmdf) {
+-                      case SOUND_MIXER_BASS:
+-                              arg_to_vol_stereo(*(unsigned int*)arg,
+-                                                &devc->bass_l, &devc->bass_r); 
+-                              opl3sa3_set_bass(devc, devc->bass_l, devc->bass_r);
+-                              *(int*)arg = ret_vol_stereo(devc->bass_l, devc->bass_r);
+-                              return 0;
+-                
+-                      case SOUND_MIXER_TREBLE:
+-                              arg_to_vol_stereo(*(unsigned int*)arg,
+-                                                &devc->treble_l, &devc->treble_r); 
+-                              opl3sa3_set_treble(devc, devc->treble_l, devc->treble_r);
+-                              *(int*)arg = ret_vol_stereo(devc->treble_l, devc->treble_r);
+-                              return 0;
+-
+-                      case SOUND_MIXER_DIGITAL1:
+-                              arg_to_vol_stereo(*(unsigned int*)arg,
+-                                                &devc->wide_l, &devc->wide_r); 
+-                              opl3sa3_set_wide(devc, devc->wide_l, devc->wide_r);
+-                              *(int*)arg = ret_vol_stereo(devc->wide_l, devc->wide_r);
+-                              return 0;
++      case SOUND_MIXER_TREBLE:
++              value = ret_vol_stereo(devc->treble_l, devc->treble_r);
++              retval = put_user(value, (int *) arg);
++              break;
+-                      default:
+-                              return -EINVAL;
+-              }
+-      }
+-      else                    
+-      {
+-              /*
+-               * Return parameters
+-               */
+-              switch (cmdf) {
+-                      case SOUND_MIXER_DEVMASK:
+-                              *(int*)arg = (SOUND_MASK_VOLUME | SOUND_MASK_MIC |
+-                                            SOUND_MASK_BASS | SOUND_MASK_TREBLE |
+-                                            SOUND_MASK_DIGITAL1);
+-                              return 0;
+-                
+-                      case SOUND_MIXER_STEREODEVS:
+-                              *(int*)arg = (SOUND_MASK_VOLUME | SOUND_MASK_BASS |
+-                                            SOUND_MASK_TREBLE | SOUND_MASK_DIGITAL1);
+-                              return 0;
+-                
+-                      case SOUND_MIXER_BASS:
+-                              *(int*)arg = ret_vol_stereo(devc->bass_l, devc->bass_r);
+-                              return 0;
+-                        
+-                      case SOUND_MIXER_TREBLE:
+-                              *(int*)arg = ret_vol_stereo(devc->treble_l, devc->treble_r);
+-                              return 0;
+-
+-                      case SOUND_MIXER_DIGITAL1:
+-                              *(int*)arg = ret_vol_stereo(devc->wide_l, devc->wide_r);
+-                              return 0;
++      case SOUND_MIXER_DIGITAL1:
++              value = ret_vol_stereo(devc->wide_l, devc->wide_r);
++              retval = put_user(value, (int *) arg);
++              break;
+-                      default:
+-                              return -EINVAL;
+-              }
++      default:
++              retval = -EINVAL;
+       }
++      return retval;
+ }
+ /* opl3sa3_mixer_ioctl end */
+--- linux-2.6.0-test6/sound/oss/swarm_cs4297a.c        2003-09-08 13:58:59.000000000 -0700
++++ 25/sound/oss/swarm_cs4297a.c       2003-10-05 00:33:25.000000000 -0700
+@@ -59,7 +59,6 @@
+ *******************************************************************************/
+ #include <linux/list.h>
+-#include <linux/version.h>
+ #include <linux/module.h>
+ #include <linux/string.h>
+ #include <linux/ioport.h>
+--- linux-2.6.0-test6/sound/oss/via82cxxx_audio.c      2003-09-08 13:58:59.000000000 -0700
++++ 25/sound/oss/via82cxxx_audio.c     2003-10-05 00:36:10.000000000 -0700
+@@ -1844,6 +1844,7 @@ static void via_ac97_cleanup (struct via
+ /**
+  *    via_intr_channel - handle an interrupt for a single channel
++ *      @card: unused
+  *    @chan: handle interrupt for this channel
+  *
+  *    This is the "meat" of the interrupt handler,
+--- linux-2.6.0-test6/sound/parisc/harmony.c   2003-08-22 19:23:43.000000000 -0700
++++ 25/sound/parisc/harmony.c  2003-10-05 00:33:25.000000000 -0700
+@@ -66,6 +66,7 @@
+ #include <linux/delay.h>
+ #include <sound/driver.h>
+ #include <linux/init.h>
++#include <linux/interrupt.h>
+ #include <linux/slab.h>
+ #include <linux/time.h>
+ #include <linux/wait.h>
+@@ -77,8 +78,8 @@
+ #include <sound/initval.h>
+ #include <sound/info.h>
+ #include <asm/hardware.h>
+-#include <asm/gsc.h>
+ #include <asm/io.h>
++#include <asm/parisc-device.h>
+ MODULE_AUTHOR("Laurent Canet <canetl@esiee.fr>");
+ MODULE_DESCRIPTION("ALSA Harmony sound driver");
+@@ -709,8 +710,8 @@ static int snd_card_harmony_playback_ope
+        * harmony is not "real" pci, but we need a pci_dev
+        * to alloc PCI DMA pages
+        */
+-      substream->dma_private = harmony->fake_pci_dev;
+-      substream->dma_type = SNDRV_PCM_DMA_TYPE_PCI;
++      substream->runtime->dma_private = harmony->fake_pci_dev;
++//    substream->dma_type = SNDRV_PCM_DMA_TYPE_PCI;
+       
+       harmony->playback_substream = substream;
+       runtime->hw = snd_card_harmony_playback;
+@@ -733,8 +734,8 @@ static int snd_card_harmony_capture_open
+        * harmony is not "real" pci, but we need a pci_dev
+        * to alloc PCI DMA pages
+        */
+-      substream->dma_private = harmony->fake_pci_dev;
+-      substream->dma_type = SNDRV_PCM_DMA_TYPE_PCI;
++      substream->runtime->dma_private = harmony->fake_pci_dev;
++//    substream->dma_type = SNDRV_PCM_DMA_TYPE_PCI;
+       harmony->capture_substream = substream;
+       runtime->hw = snd_card_harmony_capture;
+--- linux-2.6.0-test6/sound/pci/cmipci.c       2003-08-08 22:55:15.000000000 -0700
++++ 25/sound/pci/cmipci.c      2003-10-05 00:33:25.000000000 -0700
+@@ -2791,6 +2791,7 @@ static int __devinit snd_cmipci_mixer_ne
+  * proc interface
+  */
++#ifdef CONFIG_PROC_FS
+ static void snd_cmipci_proc_read(snd_info_entry_t *entry, 
+                                snd_info_buffer_t *buffer)
+ {
+@@ -2817,6 +2818,9 @@ static void __devinit snd_cmipci_proc_in
+       if (! snd_card_proc_new(cm->card, "cmipci", &entry))
+               snd_info_set_text_ops(entry, cm, snd_cmipci_proc_read);
+ }
++#else /* !CONFIG_PROC_FS */
++static inline void snd_cmipci_proc_init(cmipci_t *cm) {}
++#endif
+ static struct pci_device_id snd_cmipci_ids[] = {
+--- linux-2.6.0-test6/sound/pci/intel8x0.c     2003-09-27 18:57:48.000000000 -0700
++++ 25/sound/pci/intel8x0.c    2003-10-05 00:34:31.000000000 -0700
+@@ -2271,10 +2271,8 @@ static void __devinit intel8x0_measure_a
+       t = stop_time.tv_sec - start_time.tv_sec;
+       t *= 1000000;
+-      if (stop_time.tv_usec < start_time.tv_usec)
+-              t -= start_time.tv_usec - stop_time.tv_usec;
+-      else
+-              t += stop_time.tv_usec - start_time.tv_usec;
++      t += stop_time.tv_usec - start_time.tv_usec;
++      printk(KERN_INFO "%s: measured %lu usecs\n", __FUNCTION__, t);
+       if (t == 0) {
+               snd_printk(KERN_ERR "?? calculation error..\n");
+               return;
+--- linux-2.6.0-test6/sound/pci/Kconfig        2003-09-27 18:57:48.000000000 -0700
++++ 25/sound/pci/Kconfig       2003-10-05 00:34:45.000000000 -0700
+@@ -17,7 +17,8 @@ config SND_AZT3328
+ config SND_CS46XX
+       tristate "Cirrus Logic (Sound Fusion) CS4280/CS461x/CS462x/CS463x"
+-      depends on SND && GAMEPORT
++      depends on SND
++      select GAMEPORT
+       help
+         Say 'Y' or 'M' to include support for Cirrus Logic CS4610 / CS4612 /
+         CS4614 / CS4615 / CS4622 / CS4624 / CS4630 / CS4280 chips.
+@@ -30,7 +31,8 @@ config SND_CS46XX_NEW_DSP
+ config SND_CS4281
+       tristate "Cirrus Logic (Sound Fusion) CS4281"
+-      depends on SND && GAMEPORT
++      depends on SND
++      select GAMEPORT
+       help
+         Say 'Y' or 'M' to include support for Cirrus Logic CS4281.
+@@ -83,7 +85,8 @@ config SND_HDSP
+ config SND_TRIDENT
+       tristate "Trident 4D-Wave DX/NX; SiS 7018"
+-      depends on SND && GAMEPORT
++      depends on SND
++      select GAMEPORT
+       help
+         Say 'Y' or 'M' to include support for Trident 4D-Wave DX/NX and
+         SiS 7018 soundcards.
+@@ -110,20 +113,23 @@ config SND_CMIPCI
+ config SND_ENS1370
+       tristate "(Creative) Ensoniq AudioPCI 1370"
+-      depends on SND && GAMEPORT
++      depends on SND
++      select GAMEPORT
+       help
+         Say 'Y' or 'M' to include support for Ensoniq AudioPCI ES1370.
+ config SND_ENS1371
+       tristate "(Creative) Ensoniq AudioPCI 1371/1373"
+-      depends on SND && GAMEPORT
++      depends on SND
++      select GAMEPORT
+       help
+         Say 'Y' or 'M' to include support for Ensoniq AudioPCI ES1371 and
+         Sound Blaster PCI 64 or 128 soundcards.
+ config SND_ES1938
+       tristate "ESS ES1938/1946/1969 (Solo-1)"
+-      depends on SND && GAMEPORT
++      depends on SND
++      select GAMEPORT
+       help
+         Say 'Y' or 'M' to include support for ESS Solo-1 (ES1938, ES1946, ES1969)
+         soundcard.
+@@ -173,7 +179,8 @@ config SND_INTEL8X0
+ config SND_SONICVIBES
+       tristate "S3 SonicVibes"
+-      depends on SND && GAMEPORT
++      depends on SND
++      select GAMEPORT
+       help
+         Say 'Y' or 'M' to include support for S3 SonicVibes based soundcards.
diff --git a/lustre/kernel_patches/patches/export_symbols-2.6.0-test6.patch b/lustre/kernel_patches/patches/export_symbols-2.6.0-test6.patch
new file mode 100644 (file)
index 0000000..93aa5ff
--- /dev/null
@@ -0,0 +1,68 @@
+Index: linux-2.6.0-test6/fs/filesystems.c
+===================================================================
+--- linux-2.6.0-test6.orig/fs/filesystems.c    2003-09-28 08:50:40.000000000 +0800
++++ linux-2.6.0-test6/fs/filesystems.c 2003-10-07 18:07:58.000000000 +0800
+@@ -27,7 +27,7 @@
+  */
+ static struct file_system_type *file_systems;
+-static rwlock_t file_systems_lock = RW_LOCK_UNLOCKED;
++rwlock_t file_systems_lock = RW_LOCK_UNLOCKED;
+ /* WARNING: This can be used only if we _already_ own a reference */
+ void get_filesystem(struct file_system_type *fs)
+Index: linux-2.6.0-test6/include/linux/fs.h
+===================================================================
+--- linux-2.6.0-test6.orig/include/linux/fs.h  2003-10-07 16:09:11.000000000 +0800
++++ linux-2.6.0-test6/include/linux/fs.h       2003-10-09 19:47:24.996871688 +0800
+@@ -1385,6 +1385,7 @@
+ extern struct file_operations generic_ro_fops;
++extern rwlock_t file_systems_lock;
+ #define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m))
+ extern int vfs_readlink(struct dentry *, char __user *, int, const char *);
+Index: linux-2.6.0-test6/kernel/ksyms.c
+===================================================================
+--- linux-2.6.0-test6.orig/kernel/ksyms.c      2003-10-07 16:09:09.000000000 +0800
++++ linux-2.6.0-test6/kernel/ksyms.c   2003-10-07 18:07:58.000000000 +0800
+@@ -393,3 +393,4 @@
+ EXPORT_SYMBOL(dump_oncpu);
+ EXPORT_SYMBOL(dump_function_ptr);
+ #endif
++EXPORT_SYMBOL(file_systems_lock);
+Index: linux-2.6.0-test6/include/linux/ext2_fs_sb.h
+===================================================================
+--- linux-2.6.0-test6.orig/include/linux/ext2_fs_sb.h  2003-09-28 08:50:57.000000000 +0800
++++ linux-2.6.0-test6/include/linux/ext2_fs_sb.h       2003-10-07 18:07:58.000000000 +0800
+@@ -16,9 +16,11 @@
+ #ifndef _LINUX_EXT2_FS_SB
+ #define _LINUX_EXT2_FS_SB
++#ifndef EXT_INCLUDE
++#define EXT_INCLUDE
+ #include <linux/blockgroup_lock.h>
+ #include <linux/percpu_counter.h>
+-
++#endif
+ /*
+  * second extended-fs super-block data in memory
+  */
+Index: linux-2.6.0-test6/include/linux/ext3_fs_sb.h
+===================================================================
+--- linux-2.6.0-test6.orig/include/linux/ext3_fs_sb.h  2003-09-28 08:51:00.000000000 +0800
++++ linux-2.6.0-test6/include/linux/ext3_fs_sb.h       2003-10-07 18:07:58.000000000 +0800
+@@ -19,9 +19,12 @@
+ #ifdef __KERNEL__
+ #include <linux/timer.h>
+ #include <linux/wait.h>
++#ifndef EXT_INCLUDE
++#define EXT_INCLUDE
+ #include <linux/blockgroup_lock.h>
+ #include <linux/percpu_counter.h>
+ #endif
++#endif
+ /*
+  * third extended-fs super-block data in memory
diff --git a/lustre/kernel_patches/patches/ext3-ea-in-inode-2.4.22-rh.patch b/lustre/kernel_patches/patches/ext3-ea-in-inode-2.4.22-rh.patch
new file mode 100644 (file)
index 0000000..d48fbd2
--- /dev/null
@@ -0,0 +1,766 @@
+ fs/ext3/ialloc.c          |    6 
+ fs/ext3/inode.c           |   12 
+ fs/ext3/super.c           |    6 
+ fs/ext3/xattr.c           |  600 +++++++++++++++++++++++++++++++++++++++++++++-
+ include/linux/ext3_fs.h   |    2 
+ include/linux/ext3_fs_i.h |    3 
+ 6 files changed, 616 insertions(+), 13 deletions(-)
+
+--- linux-2.4.22-ac1/fs/ext3/ialloc.c~ext3-ea-in-inode-2.4.22-rh       2003-10-08 13:57:56.000000000 +0400
++++ linux-2.4.22-ac1-alexey/fs/ext3/ialloc.c   2003-10-08 15:13:31.000000000 +0400
+@@ -715,6 +715,12 @@ have_bit_and_group:
+       insert_inode_hash(inode);
+       inode->i_generation = sb->u.ext3_sb.s_next_generation++;
++      if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE) {
++              inode->u.ext3_i.i_extra_isize = sizeof(__u16)   /* i_extra_isize */
++                              + sizeof(__u16);        /* i_pad1 */
++      } else
++              inode->u.ext3_i.i_extra_isize = 0;
++
+       inode->u.ext3_i.i_state = EXT3_STATE_NEW;
+       err = ext3_get_inode_loc_new(inode, &iloc, 1);
+       if (err) goto fail;
+--- linux-2.4.22-ac1/fs/ext3/inode.c~ext3-ea-in-inode-2.4.22-rh        2003-10-08 13:57:57.000000000 +0400
++++ linux-2.4.22-ac1-alexey/fs/ext3/inode.c    2003-10-08 15:14:57.000000000 +0400
+@@ -2229,6 +2229,12 @@ void ext3_read_inode(struct inode * inod
+               inode->u.ext3_i.i_data[block] = iloc.raw_inode->i_block[block];
+       INIT_LIST_HEAD(&inode->u.ext3_i.i_orphan);
++      if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE)
++              inode->u.ext3_i.i_extra_isize =
++                      le16_to_cpu(raw_inode->i_extra_isize);
++      else
++              inode->u.ext3_i.i_extra_isize = 0;
++
+       if (S_ISREG(inode->i_mode)) {
+               inode->i_op = &ext3_file_inode_operations;
+               inode->i_fop = &ext3_file_operations;
+@@ -2277,6 +2283,8 @@ static int ext3_do_update_inode(handle_t
+               if (err)
+                       goto out_brelse;
+       }
++      if (EXT3_I(inode)->i_state & EXT3_STATE_NEW)
++              memset(raw_inode, 0, EXT3_INODE_SIZE(inode->i_sb)); 
+       raw_inode->i_mode = cpu_to_le16(inode->i_mode);
+       if(!(test_opt(inode->i_sb, NO_UID32))) {
+               raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid));
+@@ -2360,6 +2368,10 @@ static int ext3_do_update_inode(handle_t
+       else for (block = 0; block < EXT3_N_BLOCKS; block++)
+               raw_inode->i_block[block] = inode->u.ext3_i.i_data[block];
++      if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE)
++              raw_inode->i_extra_isize =
++                      cpu_to_le16(EXT3_I(inode)->i_extra_isize);
++
+       BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
+       rc = ext3_journal_dirty_metadata(handle, bh);
+       if (!err)
+--- linux-2.4.22-ac1/fs/ext3/super.c~ext3-ea-in-inode-2.4.22-rh        2003-10-08 13:57:57.000000000 +0400
++++ linux-2.4.22-ac1-alexey/fs/ext3/super.c    2003-10-08 15:13:31.000000000 +0400
+@@ -1299,8 +1299,10 @@ struct super_block * ext3_read_super (st
+       } else {
+               sbi->s_inode_size = le16_to_cpu(es->s_inode_size);
+               sbi->s_first_ino = le32_to_cpu(es->s_first_ino);
+-              if (sbi->s_inode_size != EXT3_GOOD_OLD_INODE_SIZE) {
+-                      printk (KERN_ERR
++              if ((sbi->s_inode_size < EXT3_GOOD_OLD_INODE_SIZE) ||
++                              (sbi->s_inode_size & (sbi->s_inode_size - 1)) ||
++                              (sbi->s_inode_size > blocksize)) {
++                      printk (KERN_ERR
+                               "EXT3-fs: unsupported inode size: %d\n",
+                               sbi->s_inode_size);
+                       goto failed_mount;
+--- linux-2.4.22-ac1/fs/ext3/xattr.c~ext3-ea-in-inode-2.4.22-rh        2003-10-08 13:57:56.000000000 +0400
++++ linux-2.4.22-ac1-alexey/fs/ext3/xattr.c    2003-10-08 15:13:31.000000000 +0400
+@@ -100,6 +100,9 @@
+ static int ext3_xattr_set2(handle_t *, struct inode *, struct buffer_head *,
+                          struct ext3_xattr_header *);
++int ext3_xattr_block_set(handle_t *, struct inode *, int, const char *,
++                      const void *, size_t, int);
++
+ #ifdef CONFIG_EXT3_FS_XATTR_SHARING
+ static int ext3_xattr_cache_insert(struct buffer_head *);
+@@ -348,17 +351,12 @@ ext3_removexattr(struct dentry *dentry, 
+ }
+ /*
+- * ext3_xattr_get()
+- *
+- * Copy an extended attribute into the buffer
+- * provided, or compute the buffer size required.
+- * Buffer is NULL to compute the size of the buffer required.
++ * ext3_xattr_block_get()
+  *
+- * Returns a negative error number on failure, or the number of bytes
+- * used / required on success.
++ * routine looks for attribute in EA block and returns it's value and size
+  */
+ int
+-ext3_xattr_get(struct inode *inode, int name_index, const char *name,
++ext3_xattr_block_get(struct inode *inode, int name_index, const char *name,
+              void *buffer, size_t buffer_size)
+ {
+       struct buffer_head *bh = NULL;
+@@ -447,6 +445,94 @@ cleanup:
+ }
+ /*
++ * ext3_xattr_ibode_get()
++ *
++ * routine looks for attribute in inode body and returns it's value and size
++ */
++int
++ext3_xattr_ibody_get(struct inode *inode, int name_index, const char *name,
++             void *buffer, size_t buffer_size)
++{
++      int size, name_len = strlen(name), storage_size;
++      struct ext3_xattr_entry *last;
++      struct ext3_inode *raw_inode;
++      struct ext3_iloc iloc;
++      char *start, *end;
++      int ret = -ENOENT;
++      
++      if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
++              return -ENOENT;
++
++      ret = ext3_get_inode_loc(inode, &iloc);
++      if (ret)
++              return ret;
++      raw_inode = iloc.raw_inode;
++
++      storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
++                              EXT3_GOOD_OLD_INODE_SIZE -
++                              EXT3_I(inode)->i_extra_isize -
++                              sizeof(__u32);
++      start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
++                      EXT3_I(inode)->i_extra_isize;
++      if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) {
++              brelse(iloc.bh);
++              return -ENOENT;
++      }
++      start += sizeof(__u32);
++      end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
++
++      last = (struct ext3_xattr_entry *) start;
++      while (!IS_LAST_ENTRY(last)) {
++              struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
++              if (le32_to_cpu(last->e_value_size) > storage_size ||
++                              (char *) next >= end) {
++                      ext3_error(inode->i_sb, "ext3_xattr_ibody_get",
++                              "inode %ld", inode->i_ino);
++                      brelse(iloc.bh);
++                      return -EIO;
++              }
++              if (name_index == last->e_name_index &&
++                  name_len == last->e_name_len &&
++                  !memcmp(name, last->e_name, name_len))
++                      goto found;
++              last = next;
++      }
++
++      /* can't find EA */
++      brelse(iloc.bh);
++      return -ENOENT;
++      
++found:
++      size = le32_to_cpu(last->e_value_size);
++      if (buffer) {
++              ret = -ERANGE;
++              if (buffer_size >= size) {
++                      memcpy(buffer, start + le16_to_cpu(last->e_value_offs),
++                      size);
++                      ret = size;
++              }
++      } else
++              ret = size;
++      brelse(iloc.bh);
++      return ret;
++}
++
++int ext3_xattr_get(struct inode *inode, int name_index, const char *name,
++                      void *buffer, size_t buffer_size)
++{
++      int err;
++
++      /* try to find attribute in inode body */
++      err = ext3_xattr_ibody_get(inode, name_index, name,
++                                      buffer, buffer_size);
++      if (err < 0) 
++              /* search was unsuccessful, try to find EA in dedicated block */
++              err = ext3_xattr_block_get(inode, name_index, name,
++                              buffer, buffer_size);
++      return err;
++}
++
++/*
+  * ext3_xattr_list()
+  *
+  * Copy a list of attribute names into the buffer
+@@ -457,7 +543,7 @@ cleanup:
+  * used / required on success.
+  */
+ int
+-ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
++ext3_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size)
+ {
+       struct buffer_head *bh = NULL;
+       struct ext3_xattr_entry *entry;
+@@ -530,6 +616,131 @@ cleanup:
+       return error;
+ }
++/* ext3_xattr_ibody_list()
++ *
++ * generate list of attributes stored in inode body
++ */
++int
++ext3_xattr_ibody_list(struct inode *inode, char *buffer, size_t buffer_size)
++{
++      struct ext3_xattr_entry *last;
++      struct ext3_inode *raw_inode;
++      char *start, *end, *buf;
++      struct ext3_iloc iloc;
++      int storage_size;
++      int ret;
++      int size = 0;
++      
++      if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
++              return 0;
++
++      ret = ext3_get_inode_loc(inode, &iloc);
++      if (ret) 
++              return ret;
++      raw_inode = iloc.raw_inode;
++
++      storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
++                              EXT3_GOOD_OLD_INODE_SIZE -
++                              EXT3_I(inode)->i_extra_isize -
++                              sizeof(__u32);
++      start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
++                      EXT3_I(inode)->i_extra_isize;
++      if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) {
++              brelse(iloc.bh);
++              return 0;
++      }
++      start += sizeof(__u32);
++      end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
++
++      last = (struct ext3_xattr_entry *) start;
++      while (!IS_LAST_ENTRY(last)) {
++              struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
++              struct ext3_xattr_handler *handler;
++              if (le32_to_cpu(last->e_value_size) > storage_size ||
++                              (char *) next >= end) {
++                      ext3_error(inode->i_sb, "ext3_xattr_ibody_list",
++                              "inode %ld", inode->i_ino);
++                      brelse(iloc.bh);
++                      return -EIO;
++              }
++              handler = ext3_xattr_handler(last->e_name_index);
++              if (handler)
++                      size += handler->list(NULL, inode, last->e_name,
++                                            last->e_name_len);
++              last = next;
++      }
++
++      if (!buffer) {
++              ret = size;
++              goto cleanup;
++      } else {
++              ret = -ERANGE;
++              if (size > buffer_size)
++                      goto cleanup;
++      }
++
++      last = (struct ext3_xattr_entry *) start;
++      buf = buffer;
++      while (!IS_LAST_ENTRY(last)) {
++              struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
++              struct ext3_xattr_handler *handler;
++              handler = ext3_xattr_handler(last->e_name_index);
++              if (handler)
++                      buf += handler->list(buf, inode, last->e_name,
++                                            last->e_name_len);
++              last = next;
++      }
++      ret = size;
++cleanup:
++      brelse(iloc.bh);
++      return ret;
++}
++
++/*
++ * ext3_xattr_list()
++ *
++ * Copy a list of attribute names into the buffer
++ * provided, or compute the buffer size required.
++ * Buffer is NULL to compute the size of the buffer required.
++ *
++ * Returns a negative error number on failure, or the number of bytes
++ * used / required on success.
++ */
++int
++ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
++{
++      int error;
++      int size = buffer_size;
++
++      /* get list of attributes stored in inode body */
++      error = ext3_xattr_ibody_list(inode, buffer, buffer_size);
++      if (error < 0) {
++              /* some error occured while collecting 
++               * attributes in inode body */
++              size = 0;
++              goto cleanup;
++      }
++      size = error;
++
++      /* get list of attributes stored in dedicated block */
++      if (buffer) {
++              buffer_size -= error;
++              if (buffer_size <= 0) {
++                      buffer = NULL;
++                      buffer_size = 0;
++              } else 
++                      buffer += error;
++      }
++
++      error = ext3_xattr_block_list(inode, buffer, buffer_size);
++      if (error < 0) 
++              /* listing was successful, so we return len */
++              size = 0;
++
++cleanup:
++      return error + size;
++}
++
+ /*
+  * If the EXT3_FEATURE_COMPAT_EXT_ATTR feature of this file system is
+  * not set, set it.
+@@ -553,6 +764,279 @@ static void ext3_xattr_update_super_bloc
+ }
+ /*
++ * ext3_xattr_ibody_find()
++ *
++ * search attribute and calculate free space in inode body
++ * NOTE: free space includes space our attribute hold
++ */
++int
++ext3_xattr_ibody_find(struct inode *inode, int name_index, 
++              const char *name, struct ext3_xattr_entry *rentry, int *free)
++{
++      struct ext3_xattr_entry *last;
++      struct ext3_inode *raw_inode;
++      int name_len = strlen(name);
++      int err, storage_size;
++      struct ext3_iloc iloc;
++      char *start, *end;
++      int ret = -ENOENT;
++      
++      if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
++              return ret;
++
++      err = ext3_get_inode_loc(inode, &iloc);
++      if (err) 
++              return -EIO;
++      raw_inode = iloc.raw_inode;
++
++      storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
++                              EXT3_GOOD_OLD_INODE_SIZE -
++                              EXT3_I(inode)->i_extra_isize -
++                              sizeof(__u32);
++      *free = storage_size - sizeof(__u32);
++      start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
++                      EXT3_I(inode)->i_extra_isize;
++      if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) {
++              brelse(iloc.bh);
++              return -ENOENT;
++      }
++      start += sizeof(__u32);
++      end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
++
++      last = (struct ext3_xattr_entry *) start;
++      while (!IS_LAST_ENTRY(last)) {
++              struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
++              if (le32_to_cpu(last->e_value_size) > storage_size ||
++                              (char *) next >= end) {
++                      ext3_error(inode->i_sb, "ext3_xattr_ibody_find",
++                              "inode %ld", inode->i_ino);
++                      brelse(iloc.bh);
++                      return -EIO;
++              }
++
++              if (name_index == last->e_name_index &&
++                  name_len == last->e_name_len &&
++                  !memcmp(name, last->e_name, name_len)) {
++                      memcpy(rentry, last, sizeof(struct ext3_xattr_entry));
++                      ret = 0;
++              } else {
++                      *free -= EXT3_XATTR_LEN(last->e_name_len);
++                      *free -= le32_to_cpu(last->e_value_size);
++              }
++              last = next;
++      }
++      
++      brelse(iloc.bh);
++      return ret;
++}
++
++/*
++ * ext3_xattr_block_find()
++ *
++ * search attribute and calculate free space in EA block (if it allocated)
++ * NOTE: free space includes space our attribute hold
++ */
++int
++ext3_xattr_block_find(struct inode *inode, int name_index, const char *name,
++             struct ext3_xattr_entry *rentry, int *free)
++{
++      struct buffer_head *bh = NULL;
++      struct ext3_xattr_entry *entry;
++      char *end;
++      int name_len, error = -ENOENT;
++
++      if (!EXT3_I(inode)->i_file_acl) {
++              *free = inode->i_sb->s_blocksize -
++                      sizeof(struct ext3_xattr_header) -
++                      sizeof(__u32);
++              return -ENOENT;
++      }
++      ea_idebug(inode, "reading block %d", EXT3_I(inode)->i_file_acl);
++      bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl);
++      if (!bh)
++              return -EIO;
++      ea_bdebug(bh, "b_count=%d, refcount=%d",
++              atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount));
++      end = bh->b_data + bh->b_size;
++      if (HDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) ||
++          HDR(bh)->h_blocks != cpu_to_le32(1)) {
++bad_block:    ext3_error(inode->i_sb, "ext3_xattr_get",
++                      "inode %ld: bad block %d", inode->i_ino,
++                      EXT3_I(inode)->i_file_acl);
++              brelse(bh);
++              return -EIO;
++      }
++      /* find named attribute */
++      name_len = strlen(name);
++      *free = bh->b_size - sizeof(__u32);
++
++      entry = FIRST_ENTRY(bh);
++      while (!IS_LAST_ENTRY(entry)) {
++              struct ext3_xattr_entry *next =
++                      EXT3_XATTR_NEXT(entry);
++              if ((char *)next >= end)
++                      goto bad_block;
++              if (name_index == entry->e_name_index &&
++                  name_len == entry->e_name_len &&
++                  memcmp(name, entry->e_name, name_len) == 0) {
++                      memcpy(rentry, entry, sizeof(struct ext3_xattr_entry));
++                      error = 0;
++              } else {
++                      *free -= EXT3_XATTR_LEN(entry->e_name_len);
++                      *free -= le32_to_cpu(entry->e_value_size);
++              }
++              entry = next;
++      }
++      brelse(bh);
++
++      return error;
++}
++
++/*
++ * ext3_xattr_inode_set()
++ * 
++ * this routine add/remove/replace attribute in inode body
++ */
++int
++ext3_xattr_ibody_set(handle_t *handle, struct inode *inode, int name_index,
++                    const char *name, const void *value, size_t value_len,
++                    int flags)
++{
++      struct ext3_xattr_entry *last, *next, *here = NULL;
++      struct ext3_inode *raw_inode;
++      int name_len = strlen(name);
++      int esize = EXT3_XATTR_LEN(name_len);
++      struct buffer_head *bh;
++      int err, storage_size;
++      struct ext3_iloc iloc;
++      int free, min_offs;
++      char *start, *end;
++      
++      if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
++              return -ENOSPC;
++
++      err = ext3_get_inode_loc(inode, &iloc);
++      if (err)
++              return err;
++      raw_inode = iloc.raw_inode;
++      bh = iloc.bh;
++
++      storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
++                              EXT3_GOOD_OLD_INODE_SIZE -
++                              EXT3_I(inode)->i_extra_isize -
++                              sizeof(__u32);
++      start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
++                      EXT3_I(inode)->i_extra_isize;
++      if ((*(__u32*) start) != EXT3_XATTR_MAGIC) {
++              /* inode had no attributes before */
++              *((__u32*) start) = cpu_to_le32(EXT3_XATTR_MAGIC);
++      }
++      start += sizeof(__u32);
++      end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
++      min_offs = storage_size;
++      free = storage_size - sizeof(__u32);
++
++      last = (struct ext3_xattr_entry *) start;       
++      while (!IS_LAST_ENTRY(last)) {
++              next = EXT3_XATTR_NEXT(last);
++              if (le32_to_cpu(last->e_value_size) > storage_size ||
++                              (char *) next >= end) {
++                      ext3_error(inode->i_sb, "ext3_xattr_ibody_set",
++                              "inode %ld", inode->i_ino);
++                      brelse(bh);
++                      return -EIO;
++              }
++              
++              if (last->e_value_size) {
++                      int offs = le16_to_cpu(last->e_value_offs);
++                      if (offs < min_offs)
++                              min_offs = offs;
++              }
++              if (name_index == last->e_name_index &&
++                      name_len == last->e_name_len &&
++                      !memcmp(name, last->e_name, name_len)) 
++                      here = last;
++              else {
++                      /* we calculate all but our attribute
++                       * because it will be removed before changing */
++                      free -= EXT3_XATTR_LEN(last->e_name_len);
++                      free -= le32_to_cpu(last->e_value_size);
++              }
++              last = next;
++      }
++
++      if (value && (esize + value_len > free)) {
++              brelse(bh);
++              return -ENOSPC;
++      }
++      
++      err = ext3_reserve_inode_write(handle, inode, &iloc);
++      if (err) {
++              brelse(bh);     
++              return err;
++      }
++
++      if (here) {
++              /* time to remove old value */
++              struct ext3_xattr_entry *e;
++              int size = le32_to_cpu(here->e_value_size);
++              int border = le16_to_cpu(here->e_value_offs);
++              char *src;
++
++              /* move tail */
++              memmove(start + min_offs + size, start + min_offs,
++                              border - min_offs);
++
++              /* recalculate offsets */
++              e = (struct ext3_xattr_entry *) start;
++              while (!IS_LAST_ENTRY(e)) {
++                      struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(e);
++                      int offs = le16_to_cpu(e->e_value_offs); 
++                      if (offs < border) 
++                              e->e_value_offs = 
++                                      cpu_to_le16(offs + size);
++                      e = next;
++              }
++              min_offs += size;
++
++              /* remove entry */
++              border = EXT3_XATTR_LEN(here->e_name_len);
++              src = (char *) here + EXT3_XATTR_LEN(here->e_name_len);
++              size = (char *) last - src;
++              if ((char *) here + size > end)
++                      printk("ALERT at %s:%d: 0x%p + %d > 0x%p\n",
++                                      __FILE__, __LINE__, here, size, end);
++              memmove(here, src, size);
++              last = (struct ext3_xattr_entry *) ((char *) last - border);
++              *((__u32 *) last) = 0;
++      }
++      
++      if (value) {
++              int offs = min_offs - value_len;
++              /* use last to create new entry */
++              last->e_name_len = strlen(name);
++              last->e_name_index = name_index;
++              last->e_value_offs = cpu_to_le16(offs);
++              last->e_value_size = cpu_to_le32(value_len);
++              last->e_hash = last->e_value_block = 0;
++              memset(last->e_name, 0, esize);
++              memcpy(last->e_name, name, last->e_name_len);
++              if (start + offs + value_len > end)
++                      printk("ALERT at %s:%d: 0x%p + %d + %d > 0x%p\n",
++                                      __FILE__, __LINE__, start, offs,
++                                      value_len, end);
++              memcpy(start + offs, value, value_len);
++              last = EXT3_XATTR_NEXT(last);
++              *((__u32 *) last) = 0;
++      }
++      
++      ext3_mark_iloc_dirty(handle, inode, &iloc);
++      brelse(bh);
++
++      return 0;
++}
++
++/*
+  * ext3_xattr_set()
+  *
+  * Create, replace or remove an extended attribute for this inode. Buffer
+@@ -566,6 +1050,102 @@ static void ext3_xattr_update_super_bloc
+  */
+ int
+ ext3_xattr_set(handle_t *handle, struct inode *inode, int name_index,
++              const char *name, const void *value, size_t value_len, int flags)
++{
++      struct ext3_xattr_entry entry;
++      int err, where = 0, found = 0, total;
++      int free1 = -1, free2 = -1;
++      int name_len;
++      
++      ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld",
++                name_index, name, value, (long)value_len);
++
++      if (IS_RDONLY(inode))
++              return -EROFS;
++      if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
++              return -EPERM;
++      if (value == NULL)
++              value_len = 0;
++      if (name == NULL)
++              return -EINVAL;
++      name_len = strlen(name);
++      if (name_len > 255 || value_len > inode->i_sb->s_blocksize)
++              return -ERANGE;
++      down(&ext3_xattr_sem);
++
++      /* try to find attribute in inode body */
++      err = ext3_xattr_ibody_find(inode, name_index, name, &entry, &free1);
++      if (err == 0) {
++              /* found EA in inode */
++              found = 1;
++              where = 0;
++      } else if (err == -ENOENT) {
++              /* there is no such attribute in inode body */
++              /* try to find attribute in dedicated block */
++              err = ext3_xattr_block_find(inode, name_index, name,
++                                              &entry, &free2);
++              if (err != 0 && err != -ENOENT) {
++                      /* not found EA in block */
++                      goto finish;    
++              }
++              /* found EA in block */
++              where = 1;
++              found = 1;
++      } else
++              goto finish;
++
++      /* check flags: may replace? may create ? */
++      if (found && (flags & XATTR_CREATE)) {
++              err = -EEXIST;
++              goto finish;
++      } else if (!found && (flags & XATTR_REPLACE)) {
++              err = -ENODATA;
++              goto finish;
++      }
++
++      /* check if we have enough space to store attribute */
++      total = EXT3_XATTR_LEN(strlen(name)) + value_len;
++      if (free1 >= 0 && total > free1 && free2 >= 0 && total > free2) {
++              /* have no enough space */
++              err = -ENOSPC;
++              goto finish;
++      }
++      
++      /* time to remove attribute */
++      if (found) {
++              if (where == 0) {
++                      /* EA is stored in inode body */
++                      ext3_xattr_ibody_set(handle, inode, name_index, name,
++                                      NULL, 0, flags);
++              } else {
++                      /* EA is stored in separated block */
++                      ext3_xattr_block_set(handle, inode, name_index, name,
++                                      NULL, 0, flags);
++              }
++      }
++
++      /* try to store EA in inode body */
++      err = ext3_xattr_ibody_set(handle, inode, name_index, name,
++                              value, value_len, flags);
++      if (err) {
++              /* can't store EA in inode body */
++              /* try to store in block */
++              err = ext3_xattr_block_set(handle, inode, name_index,
++                                      name, value, value_len, flags); 
++      }
++
++finish:       
++      up(&ext3_xattr_sem);
++      return err;
++}
++
++/*
++ * ext3_xattr_block_set()
++ * 
++ * this routine add/remove/replace attribute in EA block
++ */
++int
++ext3_xattr_block_set(handle_t *handle, struct inode *inode, int name_index,
+              const char *name, const void *value, size_t value_len, int flags)
+ {
+       struct super_block *sb = inode->i_sb;
+@@ -603,7 +1183,6 @@ ext3_xattr_set(handle_t *handle, struct 
+       name_len = strlen(name);
+       if (name_len > 255 || value_len > sb->s_blocksize)
+               return -ERANGE;
+-      down(&ext3_xattr_sem);
+       if (block) {
+               /* The inode already has an extended attribute block. */
+@@ -801,7 +1380,6 @@ cleanup:
+       brelse(bh);
+       if (!(bh && header == HDR(bh)))
+               kfree(header);
+-      up(&ext3_xattr_sem);
+       return error;
+ }
+--- linux-2.4.22-ac1/include/linux/ext3_fs.h~ext3-ea-in-inode-2.4.22-rh        2003-10-08 13:57:57.000000000 +0400
++++ linux-2.4.22-ac1-alexey/include/linux/ext3_fs.h    2003-10-08 15:13:31.000000000 +0400
+@@ -265,6 +265,8 @@ struct ext3_inode {
+                       __u32   m_i_reserved2[2];
+               } masix2;
+       } osd2;                         /* OS dependent 2 */
++      __u16   i_extra_isize;
++      __u16   i_pad1;
+ };
+ #define i_size_high   i_dir_acl
+--- linux-2.4.22-ac1/include/linux/ext3_fs_i.h~ext3-ea-in-inode-2.4.22-rh      2003-09-26 00:54:44.000000000 +0400
++++ linux-2.4.22-ac1-alexey/include/linux/ext3_fs_i.h  2003-10-08 15:13:31.000000000 +0400
+@@ -62,6 +62,9 @@ struct ext3_inode_info {
+        */
+       loff_t  i_disksize;
++      /* on-disk additional lenght */
++      __u16 i_extra_isize;
++
+       /*
+        * truncate_sem is for serialising ext3_truncate() against
+        * ext3_getblock().  In the 2.4 ext2 design, great chunks of inode's
+
+_
index 6fd0735..3230853 100644 (file)
 +      data1 = bh2->b_data;
 +
 +      /* The 0th block becomes the root, move the dirents out */
-+      de = &root->dotdot;
++      de = (struct ext3_dir_entry_2 *) &root->dotdot;
 +      de = (struct ext3_dir_entry_2 *) ((char *)de + de->rec_len);
 +      len = ((char *) root) + blocksize - (char *) de;
 +      memcpy (data1, de, len);
index adae2c2..1c1c1ad 100644 (file)
 +      data1 = bh2->b_data;
 +
 +      /* The 0th block becomes the root, move the dirents out */
-+      de = &root->dotdot;
++      de = (struct ext3_dir_entry_2 *) &root->dotdot;
 +      de = (struct ext3_dir_entry_2 *) ((char *)de + de->rec_len);
 +      len = ((char *) root) + blocksize - (char *) de;
 +      memcpy (data1, de, len);
diff --git a/lustre/kernel_patches/patches/iopen-2.6.0-test6.patch b/lustre/kernel_patches/patches/iopen-2.6.0-test6.patch
new file mode 100644 (file)
index 0000000..3d99db8
--- /dev/null
@@ -0,0 +1,424 @@
+ Documentation/filesystems/ext2.txt |   16 ++
+ fs/ext3/Makefile                   |    2 
+ fs/ext3/inode.c                    |    3 
+ fs/ext3/iopen.c                    |  239 +++++++++++++++++++++++++++++++++++++
+ fs/ext3/iopen.h                    |   15 ++
+ fs/ext3/namei.c                    |   13 ++
+ fs/ext3/super.c                    |   11 +
+ include/linux/ext3_fs.h            |    2 
+ 8 files changed, 300 insertions(+), 1 deletion(-)
+
+Index: linux-2.6.0-test6/Documentation/filesystems/ext2.txt
+===================================================================
+--- linux-2.6.0-test6.orig/Documentation/filesystems/ext2.txt  2003-10-07 16:19:10.593048704 +0800
++++ linux-2.6.0-test6/Documentation/filesystems/ext2.txt       2003-10-07 16:19:49.129190320 +0800
+@@ -35,6 +35,22 @@
+ sb=n                          Use alternate superblock at this location.
++iopen                         Makes an invisible pseudo-directory called 
++                              __iopen__ available in the root directory
++                              of the filesystem.  Allows open-by-inode-
++                              number.  i.e., inode 3145 can be accessed
++                              via /mntpt/__iopen__/3145
++
++iopen_nopriv                  This option makes the iopen directory be
++                              world-readable.  This may be safer since it
++                              allows daemons to run as an unprivileged user,
++                              however it significantly changes the security
++                              model of a Unix filesystem, since previously
++                              all files under a mode 700 directory were not
++                              generally avilable even if the
++                              permissions on the file itself is
++                              world-readable.
++
+ grpquota,noquota,quota,usrquota       Quota options are silently ignored by ext2.
+Index: linux-2.6.0-test6/fs/ext3/inode.c
+===================================================================
+--- linux-2.6.0-test6.orig/fs/ext3/inode.c     2003-10-07 16:19:10.595048400 +0800
++++ linux-2.6.0-test6/fs/ext3/inode.c  2003-10-07 16:19:49.131190016 +0800
+@@ -37,6 +37,7 @@
+ #include <linux/mpage.h>
+ #include <linux/uio.h>
+ #include "xattr.h"
++#include "iopen.h"
+ #include "acl.h"
+ /*
+@@ -2479,6 +2480,8 @@
+       ei->i_acl = EXT3_ACL_NOT_CACHED;
+       ei->i_default_acl = EXT3_ACL_NOT_CACHED;
+ #endif
++      if (ext3_iopen_get_inode(inode))
++              return;
+       if (ext3_get_inode_loc(inode, &iloc, 0))
+               goto bad_inode;
+       bh = iloc.bh;
+Index: linux-2.6.0-test6/fs/ext3/iopen.c
+===================================================================
+--- linux-2.6.0-test6.orig/fs/ext3/iopen.c     2003-10-07 16:19:49.109193360 +0800
++++ linux-2.6.0-test6/fs/ext3/iopen.c  2003-10-07 16:19:49.132189864 +0800
+@@ -0,0 +1,239 @@
++
++
++/*
++ * linux/fs/ext3/iopen.c
++ *
++ * Special support for open by inode number
++ *
++ * Copyright (C) 2001 by Theodore Ts'o (tytso@alum.mit.edu).
++ * 
++ * This file may be redistributed under the terms of the GNU General
++ * Public License.
++ */
++
++#include <linux/sched.h>
++#include <linux/fs.h>
++#include <linux/ext3_jbd.h>
++#include <linux/jbd.h>
++#include <linux/ext3_fs.h>
++#include <linux/smp_lock.h>
++#include "iopen.h"
++
++#ifndef assert
++#define assert(test) J_ASSERT(test)
++#endif
++
++#define IOPEN_NAME_LEN        32
++
++/*
++ * This implements looking up an inode by number.
++ */
++static struct dentry *iopen_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
++{
++      struct inode * inode;
++      unsigned long ino;
++        struct list_head *lp;
++        struct dentry *alternate;
++      char buf[IOPEN_NAME_LEN];
++      
++      if (dentry->d_name.len >= IOPEN_NAME_LEN)
++              return ERR_PTR(-ENAMETOOLONG);
++
++      memcpy(buf, dentry->d_name.name, dentry->d_name.len);
++      buf[dentry->d_name.len] = 0;
++
++      if (strcmp(buf, ".") == 0)
++              ino = dir->i_ino;
++      else if (strcmp(buf, "..") == 0)
++              ino = EXT3_ROOT_INO;
++      else
++              ino = simple_strtoul(buf, 0, 0);
++
++      if ((ino != EXT3_ROOT_INO &&
++           //ino != EXT3_ACL_IDX_INO &&
++           //ino != EXT3_ACL_DATA_INO &&
++           ino < EXT3_FIRST_INO(dir->i_sb)) ||
++          ino > le32_to_cpu(EXT3_SB(dir->i_sb)->s_es->s_inodes_count))
++              return ERR_PTR(-ENOENT);
++
++      inode = iget(dir->i_sb, ino);
++      if (!inode)
++              return ERR_PTR(-EACCES);
++      if (is_bad_inode(inode)) {
++              iput(inode);
++              return ERR_PTR(-ENOENT);
++      }
++
++        /* preferrably return a connected dentry */
++        spin_lock(&dcache_lock);
++        list_for_each(lp, &inode->i_dentry) {
++                alternate = list_entry(lp, struct dentry, d_alias);
++                assert(!(alternate->d_flags & DCACHE_DISCONNECTED));
++        }
++
++        if (!list_empty(&inode->i_dentry)) {
++                alternate = list_entry(inode->i_dentry.next, 
++                                       struct dentry, d_alias);
++                dget_locked(alternate);
++                alternate->d_vfs_flags |= DCACHE_REFERENCED;
++                iput(inode);
++                spin_unlock(&dcache_lock);
++                return alternate;
++        }
++        dentry->d_flags |= DCACHE_DISCONNECTED;
++        spin_unlock(&dcache_lock);
++
++      d_add(dentry, inode);
++      return NULL;
++}
++
++#define do_switch(x,y) do { \
++      __typeof__ (x) __tmp = x; \
++      x = y; y = __tmp; } while (0)
++
++static inline void switch_names(struct dentry * dentry, struct dentry * target)
++{
++      const unsigned char *old_name, *new_name;
++
++      memcpy(dentry->d_iname, target->d_iname, DNAME_INLINE_LEN); 
++      old_name = target->d_name.name;
++      new_name = dentry->d_name.name;
++      if (old_name == target->d_iname)
++              old_name = dentry->d_iname;
++      if (new_name == dentry->d_iname)
++              new_name = target->d_iname;
++      target->d_name.name = new_name;
++      dentry->d_name.name = old_name;
++}
++
++
++struct dentry *iopen_connect_dentry(struct dentry *de, struct inode *inode)
++{
++        struct dentry *tmp, *goal = NULL;
++        struct list_head *lp;
++
++        /* preferrably return a connected dentry */
++        spin_lock(&dcache_lock);
++        /* verify this dentry is really new */
++        assert(!de->d_inode);
++        assert(list_empty(&de->d_subdirs));
++        assert(list_empty(&de->d_alias));
++
++
++        list_for_each(lp, &inode->i_dentry) {
++                tmp = list_entry(lp, struct dentry, d_alias);
++                if (tmp->d_flags & DCACHE_DISCONNECTED) {
++                        assert(tmp->d_alias.next == &inode->i_dentry);
++                        assert(tmp->d_alias.prev == &inode->i_dentry);
++                        goal = tmp;
++                        dget_locked(goal);
++                        break;
++                }
++        }
++
++        if (!goal) { 
++                spin_unlock(&dcache_lock);
++                return NULL; 
++        }
++
++        /* Move the goal to the de hash queue */
++        goal->d_flags &= ~DCACHE_DISCONNECTED;
++      hlist_add_before(&goal->d_hash, &de->d_hash);
++      hlist_del(&goal->d_hash);
++
++      list_del(&goal->d_child);
++      list_del(&de->d_child);
++
++      /* Switch the parents and the names.. */
++      switch_names(goal, de);
++      do_switch(goal->d_parent, de->d_parent);
++      do_switch(goal->d_name.len, de->d_name.len);
++      do_switch(goal->d_name.hash, de->d_name.hash);
++
++      /* And add them back to the (new) parent lists */
++      list_add(&goal->d_child, &goal->d_parent->d_subdirs);
++      list_add(&de->d_child, &de->d_parent->d_subdirs);
++
++        spin_unlock(&dcache_lock);
++        return goal;
++}
++
++/*
++ * These are the special structures for the iopen pseudo directory.
++ */
++
++static struct inode_operations iopen_inode_operations = {
++      lookup:         iopen_lookup,           /* BKL held */
++};
++
++static struct file_operations iopen_file_operations = {
++      read:           generic_read_dir,
++};
++
++static int match_dentry(struct dentry *dentry, const char *name)
++{
++      int     len;
++
++      len = strlen(name);
++      if (dentry->d_name.len != len)
++              return 0;
++      if (strncmp(dentry->d_name.name, name, len))
++              return 0;
++      return 1;
++}
++
++/*
++ * This function is spliced into ext3_lookup and returns 1 the file
++ * name is __iopen__ and dentry has been filled in appropriately.
++ */
++int ext3_check_for_iopen(struct inode * dir, struct dentry *dentry)
++{
++      struct inode * inode;
++
++      if (dir->i_ino != EXT3_ROOT_INO ||
++          !test_opt(dir->i_sb, IOPEN) ||
++          !match_dentry(dentry, "__iopen__"))
++              return 0;
++
++      inode = iget(dir->i_sb, EXT3_BAD_INO);
++
++      if (!inode) 
++              return 0;
++      d_add(dentry, inode);
++      return 1;
++}
++
++/*
++ * This function is spliced into read_inode; it returns 1 if inode
++ * number is the one for /__iopen__, in which case the inode is filled
++ * in appropriately.  Otherwise, this fuction returns 0.
++ */
++int ext3_iopen_get_inode(struct inode * inode)
++{
++      if (inode->i_ino != EXT3_BAD_INO)
++              return 0;
++
++      inode->i_mode = S_IFDIR | S_IRUSR | S_IXUSR;
++      if (test_opt(inode->i_sb, IOPEN_NOPRIV))
++              inode->i_mode |= 0777;
++      inode->i_uid = 0;
++      inode->i_gid = 0;
++      inode->i_nlink = 1;
++      inode->i_size = 4096;
++      inode->i_atime = CURRENT_TIME;
++      inode->i_ctime = CURRENT_TIME;
++      inode->i_mtime = CURRENT_TIME;
++      EXT3_I(inode)->i_dtime = 0;
++      inode->i_blksize = PAGE_SIZE;   /* This is the optimal IO size
++                                       * (for stat), not the fs block
++                                       * size */  
++      inode->i_blocks = 0;
++      inode->i_version = 1;
++      inode->i_generation = 0;
++
++      inode->i_op = &iopen_inode_operations;
++      inode->i_fop = &iopen_file_operations;
++      inode->i_mapping->a_ops = 0;
++
++      return 1;
++}
+Index: linux-2.6.0-test6/fs/ext3/iopen.h
+===================================================================
+--- linux-2.6.0-test6.orig/fs/ext3/iopen.h     2003-10-07 16:19:49.109193360 +0800
++++ linux-2.6.0-test6/fs/ext3/iopen.h  2003-10-07 16:19:49.132189864 +0800
+@@ -0,0 +1,15 @@
++/*
++ * iopen.h
++ *
++ * Special support for opening files by inode number.
++ * 
++ * Copyright (C) 2001 by Theodore Ts'o (tytso@alum.mit.edu).
++ * 
++ * This file may be redistributed under the terms of the GNU General
++ * Public License.
++ */
++
++extern int ext3_check_for_iopen(struct inode * dir, struct dentry *dentry);
++extern int ext3_iopen_get_inode(struct inode * inode);
++
++
+Index: linux-2.6.0-test6/fs/ext3/namei.c
+===================================================================
+--- linux-2.6.0-test6.orig/fs/ext3/namei.c     2003-10-07 16:19:10.597048096 +0800
++++ linux-2.6.0-test6/fs/ext3/namei.c  2003-10-07 16:19:49.133189712 +0800
+@@ -37,6 +37,7 @@
+ #include <linux/buffer_head.h>
+ #include <linux/smp_lock.h>
+ #include "xattr.h"
++#include "iopen.h"
+ #include "acl.h"
+ /*
+@@ -970,15 +971,21 @@
+ }
+ #endif
++struct dentry *iopen_connect_dentry(struct dentry *de, struct inode *inode);
++ 
+ static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
+ {
+       struct inode * inode;
+       struct ext3_dir_entry_2 * de;
+       struct buffer_head * bh;
++      struct dentry *alternate = NULL;
+       if (dentry->d_name.len > EXT3_NAME_LEN)
+               return ERR_PTR(-ENAMETOOLONG);
++      if (ext3_check_for_iopen(dir, dentry))
++              return NULL;
++
+       bh = ext3_find_entry(dentry, &de);
+       inode = NULL;
+       if (bh) {
+@@ -991,6 +998,12 @@
+       }
+       if (inode)
+               return d_splice_alias(inode, dentry);
++
++      if (inode && (alternate = iopen_connect_dentry(dentry, inode))) {
++              iput(inode);
++              return alternate;
++      }
++
+       d_add(dentry, inode);
+       return NULL;
+ }
+Index: linux-2.6.0-test6/fs/ext3/super.c
+===================================================================
+--- linux-2.6.0-test6.orig/fs/ext3/super.c     2003-10-07 16:19:10.599047792 +0800
++++ linux-2.6.0-test6/fs/ext3/super.c  2003-10-07 16:25:14.799680880 +0800
+@@ -534,7 +534,7 @@
+       Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, Opt_noload,
+       Opt_commit, Opt_journal_update, Opt_journal_inum,
+       Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
+-      Opt_ignore, Opt_err,
++      Opt_ignore, Opt_err, Opt_iopen, Opt_noiopen, Opt_iopen_nopriv,
+ };
+ static match_table_t tokens = {
+@@ -573,6 +573,9 @@
+       {Opt_ignore, "noquota"},
+       {Opt_ignore, "quota"},
+       {Opt_ignore, "usrquota"},
++      {Opt_iopen,  "iopen"},
++      {Opt_noiopen,  "noiopen"},
++      {Opt_iopen_nopriv,  "iopen_nopriv"},
+       {Opt_err, NULL}
+ };
+@@ -760,6 +763,18 @@
+               case Opt_abort:
+                       set_opt(sbi->s_mount_opt, ABORT);
+                       break;
++              case Opt_iopen:
++                      set_opt (sbi->s_mount_opt, IOPEN);
++                      clear_opt (sbi->s_mount_opt, IOPEN_NOPRIV);
++                      break;
++              case Opt_noiopen:
++                      clear_opt (sbi->s_mount_opt, IOPEN);
++                      clear_opt (sbi->s_mount_opt, IOPEN_NOPRIV);
++                      break;
++              case Opt_iopen_nopriv:
++                      set_opt (sbi->s_mount_opt, IOPEN);
++                      set_opt (sbi->s_mount_opt, IOPEN_NOPRIV);
++                      break;
+               case Opt_ignore:
+                       break;
+               default:
+Index: linux-2.6.0-test6/include/linux/ext3_fs.h
+===================================================================
+--- linux-2.6.0-test6.orig/include/linux/ext3_fs.h     2003-10-07 16:19:10.600047640 +0800
++++ linux-2.6.0-test6/include/linux/ext3_fs.h  2003-10-07 16:19:49.136189256 +0800
+@@ -324,6 +324,8 @@
+ #define EXT3_MOUNT_NO_UID32           0x2000  /* Disable 32-bit UIDs */
+ #define EXT3_MOUNT_XATTR_USER         0x4000  /* Extended user attributes */
+ #define EXT3_MOUNT_POSIX_ACL          0x8000  /* POSIX Access Control Lists */
++#define EXT3_MOUNT_IOPEN             0x10000  /* Allow access via iopen */
++#define EXT3_MOUNT_IOPEN_NOPRIV              0x20000  /* Make iopen world-readable */
+ /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
+ #ifndef _LINUX_EXT2_FS_H
diff --git a/lustre/kernel_patches/patches/kexec-2.6.0-test6-full.patch b/lustre/kernel_patches/patches/kexec-2.6.0-test6-full.patch
new file mode 100644 (file)
index 0000000..ea09f12
--- /dev/null
@@ -0,0 +1,1481 @@
+ 0 files changed
+
+Index: linux-2.6.0-test6/MAINTAINERS
+===================================================================
+--- linux-2.6.0-test6.orig/MAINTAINERS 2003-10-07 16:08:42.000000000 +0800
++++ linux-2.6.0-test6/MAINTAINERS      2003-10-07 16:09:00.000000000 +0800
+@@ -1174,6 +1174,17 @@
+ W:    http://www.cse.unsw.edu.au/~neilb/patches/linux-devel/
+ S:    Maintained
++KEXEC
++P:    Eric Biederman
++M:    ebiederm@xmission.com
++M:    ebiederman@lnxi.com
++W:    http://www.xmission.com/~ebiederm/files/kexec/
++P:    Andy Pfiffer
++M:    andyp@osdl.org
++W:    http://www.osdl.org/archive/andyp/bloom/Code/Linux/Kexec/
++L:    linux-kernel@vger.kernel.org
++S:    Maintained
++
+ LANMEDIA WAN CARD DRIVER
+ P:    Andrew Stanley-Jones
+ M:    asj@lanmedia.com
+Index: linux-2.6.0-test6/arch/i386/Kconfig
+===================================================================
+--- linux-2.6.0-test6.orig/arch/i386/Kconfig   2003-10-07 16:08:59.000000000 +0800
++++ linux-2.6.0-test6/arch/i386/Kconfig        2003-10-07 16:09:00.000000000 +0800
+@@ -845,6 +845,23 @@
+ # depends on (((X86_SUMMIT || X86_GENERICARCH) && NUMA)) || X86_GENERICARCH
+       default y
++config KEXEC
++      bool "kexec system call (EXPERIMENTAL)"
++      depends on EXPERIMENTAL
++      help
++        kexec is a system call that implements the ability to  shutdown your
++        current kernel, and to start another kernel.  It is like a reboot
++        but it is indepedent of the system firmware.   And like a reboot
++        you can start any kernel with it not just Linux.  
++      
++        The name comes from the similiarity to the exec system call. 
++      
++        It is on an going process to be certain the hardware in a machine
++        is properly shutdown, so do not be surprised if this code does not
++        initially work for you.  It may help to enable device hotplugging
++        support.  As of this writing the exact hardware interface is
++        strongly in flux, so no good recommendation can be made.
++
+ endmenu
+Index: linux-2.6.0-test6/arch/i386/defconfig
+===================================================================
+--- linux-2.6.0-test6.orig/arch/i386/defconfig 2003-10-07 15:47:25.000000000 +0800
++++ linux-2.6.0-test6/arch/i386/defconfig      2003-10-07 16:09:00.000000000 +0800
+@@ -82,6 +82,7 @@
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_SMP=y
+ CONFIG_NR_CPUS=8
++CONFIG_KEXEC=y
+ CONFIG_PREEMPT=y
+ CONFIG_X86_LOCAL_APIC=y
+ CONFIG_X86_IO_APIC=y
+Index: linux-2.6.0-test6/arch/i386/kernel/Makefile
+===================================================================
+--- linux-2.6.0-test6.orig/arch/i386/kernel/Makefile   2003-10-07 16:08:34.000000000 +0800
++++ linux-2.6.0-test6/arch/i386/kernel/Makefile        2003-10-07 16:09:00.000000000 +0800
+@@ -24,6 +24,7 @@
+ obj-$(CONFIG_X86_MPPARSE)     += mpparse.o
+ obj-$(CONFIG_X86_LOCAL_APIC)  += apic.o nmi.o
+ obj-$(CONFIG_X86_IO_APIC)     += io_apic.o
++obj-$(CONFIG_KEXEC)           += machine_kexec.o relocate_kernel.o
+ obj-$(CONFIG_X86_NUMAQ)               += numaq.o
+ obj-$(CONFIG_X86_SUMMIT)      += summit.o
+ obj-$(CONFIG_EDD)                     += edd.o
+Index: linux-2.6.0-test6/arch/i386/kernel/apic.c
+===================================================================
+--- linux-2.6.0-test6.orig/arch/i386/kernel/apic.c     2003-10-07 15:47:25.000000000 +0800
++++ linux-2.6.0-test6/arch/i386/kernel/apic.c  2003-10-07 16:09:01.000000000 +0800
+@@ -26,6 +26,7 @@
+ #include <linux/mc146818rtc.h>
+ #include <linux/kernel_stat.h>
+ #include <linux/sysdev.h>
++#include <linux/reboot.h>
+ #include <asm/atomic.h>
+ #include <asm/smp.h>
+@@ -183,6 +184,39 @@
+               outb(0x70, 0x22);
+               outb(0x00, 0x23);
+       }
++#ifdef        CONFIG_KEXEC
++      else {
++              /* Go back to Virtual Wire compatibility mode */
++              unsigned long value;
++
++              /* For the spurious interrupt use vector F, and enable it */
++              value = apic_read(APIC_SPIV);
++              value &= ~APIC_VECTOR_MASK; 
++              value |= APIC_SPIV_APIC_ENABLED;
++              value |= 0xf;
++              apic_write_around(APIC_SPIV, value);
++
++              /* For LVT0 make it edge triggered, active high, external and enabled */
++              value = apic_read(APIC_LVT0);
++              value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING | 
++                      APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR | 
++                      APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED );
++              value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING;
++              value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_EXINT);
++              apic_write_around(APIC_LVT0, value);
++              
++              /* For LVT1 make it edge triggered, active high, nmi and enabled */
++              value = apic_read(APIC_LVT1);
++              value &= ~(
++                      APIC_MODE_MASK | APIC_SEND_PENDING | 
++                      APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR | 
++                      APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED);
++              value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING;
++              value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_NMI);
++              apic_write_around(APIC_LVT1, value);
++      }
++#endif        /* CONFIG_KEXEC */
++
+ }
+ void disable_local_APIC(void)
+@@ -1147,6 +1181,26 @@
+       irq_exit();
+ }
++void stop_apics(void)
++{
++      /* By resetting the APIC's we disable the nmi watchdog */
++#if CONFIG_SMP
++      /*
++       * Stop all CPUs and turn off local APICs and the IO-APIC, so
++       * other OSs see a clean IRQ state.
++       */
++      smp_send_stop();
++#else
++      disable_local_APIC();
++#endif
++#if defined(CONFIG_X86_IO_APIC)
++      if (smp_found_config) {
++              disable_IO_APIC();
++      }
++#endif
++      disconnect_bsp_APIC();
++}
++
+ /*
+  * This initializes the IO-APIC and APIC hardware if this is
+  * a UP kernel.
+Index: linux-2.6.0-test6/arch/i386/kernel/dmi_scan.c
+===================================================================
+--- linux-2.6.0-test6.orig/arch/i386/kernel/dmi_scan.c 2003-10-07 16:08:34.000000000 +0800
++++ linux-2.6.0-test6/arch/i386/kernel/dmi_scan.c      2003-10-07 16:09:01.000000000 +0800
+@@ -222,31 +222,6 @@
+       return 0;
+ }
+-/*
+- * Some machines require the "reboot=s"  commandline option, this quirk makes that automatic.
+- */
+-static __init int set_smp_reboot(struct dmi_blacklist *d)
+-{
+-#ifdef CONFIG_SMP
+-      extern int reboot_smp;
+-      if (reboot_smp == 0)
+-      {
+-              reboot_smp = 1;
+-              printk(KERN_INFO "%s series board detected. Selecting SMP-method for reboots.\n", d->ident);
+-      }
+-#endif
+-      return 0;
+-}
+-
+-/*
+- * Some machines require the "reboot=b,s"  commandline option, this quirk makes that automatic.
+- */
+-static __init int set_smp_bios_reboot(struct dmi_blacklist *d)
+-{
+-      set_smp_reboot(d);
+-      set_bios_reboot(d);
+-      return 0;
+-}
+ /*
+  * Some bioses have a broken protected mode poweroff and need to use realmode
+@@ -581,7 +556,7 @@
+                       MATCH(DMI_BIOS_VERSION, "4.60 PGMA"),
+                       MATCH(DMI_BIOS_DATE, "134526184"), NO_MATCH
+                       } },
+-      { set_smp_bios_reboot, "Dell PowerEdge 1300", { /* Handle problems with rebooting on Dell 1300's */
++      { set_bios_reboot, "Dell PowerEdge 1300", {     /* Handle problems with rebooting on Dell 1300's */
+                       MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
+                       MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/"),
+                       NO_MATCH, NO_MATCH
+Index: linux-2.6.0-test6/arch/i386/kernel/entry.S
+===================================================================
+--- linux-2.6.0-test6.orig/arch/i386/kernel/entry.S    2003-10-07 16:08:34.000000000 +0800
++++ linux-2.6.0-test6/arch/i386/kernel/entry.S 2003-10-07 16:09:01.000000000 +0800
+@@ -1046,6 +1046,7 @@
+       .long sys_utimes
+       .long sys_fadvise64_64
+       .long sys_ni_syscall    /* sys_vserver */
++        .long sys_kexec_load
+ nr_syscalls=(.-sys_call_table)/4
+Index: linux-2.6.0-test6/arch/i386/kernel/i8259.c
+===================================================================
+--- linux-2.6.0-test6.orig/arch/i386/kernel/i8259.c    2003-10-07 16:08:34.000000000 +0800
++++ linux-2.6.0-test6/arch/i386/kernel/i8259.c 2003-10-07 16:09:01.000000000 +0800
+@@ -244,9 +244,21 @@
+       return 0;
+ }
++static int i8259A_shutdown(struct sys_device *dev)
++{
++      /* Put the i8259A into a quiescent state that
++       * the kernel initialization code can get it
++       * out of.
++       */
++      outb(0xff, 0x21);       /* mask all of 8259A-1 */
++      outb(0xff, 0xA1);       /* mask all of 8259A-1 */
++      return 0;
++}
++
+ static struct sysdev_class i8259_sysdev_class = {
+       set_kset_name("i8259"),
+       .resume = i8259A_resume,
++      .shutdown = i8259A_shutdown,
+ };
+ static struct sys_device device_i8259A = {
+Index: linux-2.6.0-test6/arch/i386/kernel/io_apic.c
+===================================================================
+--- linux-2.6.0-test6.orig/arch/i386/kernel/io_apic.c  2003-10-07 16:08:34.000000000 +0800
++++ linux-2.6.0-test6/arch/i386/kernel/io_apic.c       2003-10-07 16:09:01.000000000 +0800
+@@ -1629,8 +1629,6 @@
+        * Clear the IO-APIC before rebooting:
+        */
+       clear_IO_APIC();
+-
+-      disconnect_bsp_APIC();
+ }
+ /*
+Index: linux-2.6.0-test6/arch/i386/kernel/machine_kexec.c
+===================================================================
+--- linux-2.6.0-test6.orig/arch/i386/kernel/machine_kexec.c    2003-10-07 16:09:00.000000000 +0800
++++ linux-2.6.0-test6/arch/i386/kernel/machine_kexec.c 2003-10-07 16:09:01.000000000 +0800
+@@ -0,0 +1,116 @@
++#include <linux/config.h>
++#include <linux/mm.h>
++#include <linux/kexec.h>
++#include <linux/delay.h>
++#include <asm/pgtable.h>
++#include <asm/pgalloc.h>
++#include <asm/tlbflush.h>
++#include <asm/mmu_context.h>
++#include <asm/io.h>
++#include <asm/apic.h>
++
++
++/*
++ * machine_kexec
++ * =======================
++ */
++
++
++static void set_idt(void *newidt, __u16 limit)
++{
++      unsigned char curidt[6];
++
++      /* ia32 supports unaliged loads & stores */
++      (*(__u16 *)(curidt)) = limit;
++      (*(__u32 *)(curidt +2)) = (unsigned long)(newidt);
++
++      __asm__ __volatile__ (
++              "lidt %0\n" 
++              : "=m" (curidt)
++              );
++};
++
++
++static void set_gdt(void *newgdt, __u16 limit)
++{
++      unsigned char curgdt[6];
++
++      /* ia32 supports unaliged loads & stores */
++      (*(__u16 *)(curgdt)) = limit;
++      (*(__u32 *)(curgdt +2)) = (unsigned long)(newgdt);
++
++      __asm__ __volatile__ (
++              "lgdt %0\n" 
++              : "=m" (curgdt)
++              );
++};
++
++static void load_segments(void)
++{
++#define __STR(X) #X
++#define STR(X) __STR(X)
++
++      __asm__ __volatile__ (
++              "\tljmp $"STR(__KERNEL_CS)",$1f\n"
++              "\t1:\n"
++              "\tmovl $"STR(__KERNEL_DS)",%eax\n"
++              "\tmovl %eax,%ds\n"
++              "\tmovl %eax,%es\n"
++              "\tmovl %eax,%fs\n"
++              "\tmovl %eax,%gs\n"
++              "\tmovl %eax,%ss\n"
++              );
++#undef STR
++#undef __STR
++}
++
++typedef void (*relocate_new_kernel_t)(
++      unsigned long indirection_page, unsigned long reboot_code_buffer,
++      unsigned long start_address);
++
++const extern unsigned char relocate_new_kernel[];
++extern void relocate_new_kernel_end(void);
++const extern unsigned int relocate_new_kernel_size;
++extern void use_mm(struct mm_struct *mm);
++
++void machine_kexec(struct kimage *image)
++{
++      unsigned long indirection_page;
++      unsigned long reboot_code_buffer;
++      relocate_new_kernel_t rnk;
++
++      /* switch to an mm where the reboot_code_buffer is identity mapped */
++      use_mm(&init_mm);
++      stop_apics();
++
++      /* Interrupts aren't acceptable while we reboot */
++      local_irq_disable();
++      reboot_code_buffer = page_to_pfn(image->reboot_code_pages) << PAGE_SHIFT;
++      indirection_page = image->head & PAGE_MASK;
++
++      /* copy it out */
++      memcpy((void *)reboot_code_buffer, relocate_new_kernel, relocate_new_kernel_size);
++
++      /* The segment registers are funny things, they are
++       * automatically loaded from a table, in memory wherever you
++       * set them to a specific selector, but this table is never
++       * accessed again you set the segment to a different selector.
++       *
++       * The more common model is are caches where the behide
++       * the scenes work is done, but is also dropped at arbitrary
++       * times.
++       *
++       * I take advantage of this here by force loading the
++       * segments, before I zap the gdt with an invalid value.
++       */
++      load_segments();
++      /* The gdt & idt are now invalid.
++       * If you want to load them you must set up your own idt & gdt.
++       */
++      set_gdt(phys_to_virt(0),0);
++      set_idt(phys_to_virt(0),0);
++
++      /* now call it */
++      rnk = (relocate_new_kernel_t) reboot_code_buffer;
++      (*rnk)(indirection_page, reboot_code_buffer, image->start);
++}
+Index: linux-2.6.0-test6/arch/i386/kernel/reboot.c
+===================================================================
+--- linux-2.6.0-test6.orig/arch/i386/kernel/reboot.c   2003-10-07 16:08:34.000000000 +0800
++++ linux-2.6.0-test6/arch/i386/kernel/reboot.c        2003-10-07 16:09:01.000000000 +0800
+@@ -21,8 +21,7 @@
+ int reboot_thru_bios;
+ #ifdef CONFIG_SMP
+-int reboot_smp = 0;
+-static int reboot_cpu = -1;
++int reboot_cpu = -1;    /* specifies the internal linux cpu id, not the apicid */
+ /* shamelessly grabbed from lib/vsprintf.c for readability */
+ #define is_digit(c)   ((c) >= '0' && (c) <= '9')
+ #endif
+@@ -44,7 +43,6 @@
+                       break;
+ #ifdef CONFIG_SMP
+               case 's': /* "smp" reboot by executing reset on BSP or other CPU*/
+-                      reboot_smp = 1;
+                       if (is_digit(*(str+1))) {
+                               reboot_cpu = (int) (*(str+1) - '0');
+                               if (is_digit(*(str+2))) 
+@@ -217,51 +215,7 @@
+ void machine_restart(char * __unused)
+ {
+-#ifdef CONFIG_SMP
+-      int cpuid;
+-      
+-      cpuid = GET_APIC_ID(apic_read(APIC_ID));
+-
+-      if (reboot_smp) {
+-
+-              /* check to see if reboot_cpu is valid 
+-                 if its not, default to the BSP */
+-              if ((reboot_cpu == -1) ||  
+-                    (reboot_cpu > (NR_CPUS -1))  || 
+-                    !physid_isset(cpuid, phys_cpu_present_map))
+-                      reboot_cpu = boot_cpu_physical_apicid;
+-
+-              reboot_smp = 0;  /* use this as a flag to only go through this once*/
+-              /* re-run this function on the other CPUs
+-                 it will fall though this section since we have 
+-                 cleared reboot_smp, and do the reboot if it is the
+-                 correct CPU, otherwise it halts. */
+-              if (reboot_cpu != cpuid)
+-                      smp_call_function((void *)machine_restart , NULL, 1, 0);
+-      }
+-
+-      /* if reboot_cpu is still -1, then we want a tradional reboot, 
+-         and if we are not running on the reboot_cpu,, halt */
+-      if ((reboot_cpu != -1) && (cpuid != reboot_cpu)) {
+-              for (;;)
+-              __asm__ __volatile__ ("hlt");
+-      }
+-      /*
+-       * Stop all CPUs and turn off local APICs and the IO-APIC, so
+-       * other OSs see a clean IRQ state.
+-       */
+-      smp_send_stop();
+-#elif defined(CONFIG_X86_LOCAL_APIC)
+-      if (cpu_has_apic) {
+-              local_irq_disable();
+-              disable_local_APIC();
+-              local_irq_enable();
+-      }
+-#endif
+-#ifdef CONFIG_X86_IO_APIC
+-      disable_IO_APIC();
+-#endif
+-
++        stop_apics();
+       if (!reboot_thru_bios) {
+               if (efi_enabled) {
+                       efi.reset_system(EFI_RESET_COLD, EFI_SUCCESS, 0, 0);
+@@ -284,11 +238,13 @@
+ }
+ void machine_halt(void)
+-{
++{ 
++      stop_apics();
+ }
+ void machine_power_off(void)
+ {
++      stop_apics();
+       if (efi_enabled)
+               efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, 0);
+       if (pm_power_off)
+Index: linux-2.6.0-test6/arch/i386/kernel/relocate_kernel.S
+===================================================================
+--- linux-2.6.0-test6.orig/arch/i386/kernel/relocate_kernel.S  2003-10-07 16:09:00.000000000 +0800
++++ linux-2.6.0-test6/arch/i386/kernel/relocate_kernel.S       2003-10-07 16:09:01.000000000 +0800
+@@ -0,0 +1,107 @@
++#include <linux/config.h>
++#include <linux/linkage.h>
++
++      /* Must be relocatable PIC code callable as a C function, that once
++       * it starts can not use the previous processes stack.
++       *
++       */
++      .globl relocate_new_kernel
++relocate_new_kernel:
++      /* read the arguments and say goodbye to the stack */
++      movl  4(%esp), %ebx /* indirection_page */
++      movl  8(%esp), %ebp /* reboot_code_buffer */
++      movl  12(%esp), %edx /* start address */
++
++      /* zero out flags, and disable interrupts */
++      pushl $0
++      popfl
++
++      /* set a new stack at the bottom of our page... */
++      lea   4096(%ebp), %esp
++
++      /* store the parameters back on the stack */
++      pushl   %edx /* store the start address */
++
++      /* Set cr0 to a known state:
++       * 31 0 == Paging disabled
++       * 18 0 == Alignment check disabled
++       * 16 0 == Write protect disabled
++       * 3  0 == No task switch
++       * 2  0 == Don't do FP software emulation.
++       * 0  1 == Proctected mode enabled
++       */
++      movl    %cr0, %eax
++      andl    $~((1<<31)|(1<<18)|(1<<16)|(1<<3)|(1<<2)), %eax
++      orl     $(1<<0), %eax
++      movl    %eax, %cr0
++      
++      /* Set cr4 to a known state:
++       * Setting everything to zero seems safe.
++       */
++      movl    %cr4, %eax
++      andl    $0, %eax
++      movl    %eax, %cr4
++      
++      jmp 1f
++1:    
++
++      /* Flush the TLB (needed?) */
++      xorl    %eax, %eax
++      movl    %eax, %cr3
++
++      /* Do the copies */
++      cld
++0:    /* top, read another word for the indirection page */
++      movl    %ebx, %ecx
++      movl    (%ebx), %ecx
++      addl    $4, %ebx
++      testl   $0x1,   %ecx  /* is it a destination page */
++      jz      1f
++      movl    %ecx,   %edi
++      andl    $0xfffff000, %edi
++      jmp     0b
++1:
++      testl   $0x2,   %ecx  /* is it an indirection page */
++      jz      1f
++      movl    %ecx,   %ebx
++      andl    $0xfffff000, %ebx
++      jmp     0b
++1:
++      testl   $0x4,   %ecx /* is it the done indicator */
++      jz      1f
++      jmp     2f
++1:
++      testl   $0x8,   %ecx /* is it the source indicator */
++      jz      0b           /* Ignore it otherwise */
++      movl    %ecx,   %esi /* For every source page do a copy */
++      andl    $0xfffff000, %esi
++
++      movl    $1024, %ecx
++      rep ; movsl
++      jmp     0b
++
++2:
++
++      /* To be certain of avoiding problems with self modifying code
++       * I need to execute a serializing instruction here.
++       * So I flush the TLB, it's handy, and not processor dependent.
++       */
++      xorl    %eax, %eax
++      movl    %eax, %cr3
++      
++      /* set all of the registers to known values */
++      /* leave %esp alone */
++      
++      xorl    %eax, %eax
++      xorl    %ebx, %ebx
++      xorl    %ecx, %ecx
++      xorl    %edx, %edx
++      xorl    %esi, %esi
++      xorl    %edi, %edi
++      xorl    %ebp, %ebp
++      ret
++relocate_new_kernel_end:
++
++      .globl relocate_new_kernel_size
++relocate_new_kernel_size:     
++      .long relocate_new_kernel_end - relocate_new_kernel
+Index: linux-2.6.0-test6/arch/i386/kernel/smp.c
+===================================================================
+--- linux-2.6.0-test6.orig/arch/i386/kernel/smp.c      2003-10-07 16:08:59.000000000 +0800
++++ linux-2.6.0-test6/arch/i386/kernel/smp.c   2003-10-07 16:09:01.000000000 +0800
+@@ -577,6 +577,30 @@
+ void smp_send_stop(void)
+ {
++      extern int reboot_cpu;
++      int reboot_cpu_id;
++      
++      /* The boot cpu is always logical cpu 0 */
++      reboot_cpu_id = 0;
++
++      /* See if there has been give a command line override .
++       */
++      if ((reboot_cpu != -1) && !(reboot_cpu >= NR_CPUS) && 
++              test_bit(reboot_cpu, &cpu_online_map)) {
++              reboot_cpu_id = reboot_cpu;
++      }
++       
++      /* Make certain the the cpu I'm rebooting on is online */
++      if (!test_bit(reboot_cpu_id, &cpu_online_map)) {
++              reboot_cpu_id = smp_processor_id();
++      }
++
++      /* Make certain I only run on the appropriate processor */
++      set_cpus_allowed(current, cpumask_of_cpu(reboot_cpu_id));
++
++      /* O.k. Now that I'm on the appropriate processor stop
++       * all of the others.
++       */
+       smp_call_function(stop_this_cpu, NULL, 1, 0);
+       local_irq_disable();
+Index: linux-2.6.0-test6/include/asm-i386/apic.h
+===================================================================
+--- linux-2.6.0-test6.orig/include/asm-i386/apic.h     2003-10-07 15:47:25.000000000 +0800
++++ linux-2.6.0-test6/include/asm-i386/apic.h  2003-10-07 16:09:01.000000000 +0800
+@@ -99,6 +99,9 @@
+ #define NMI_LOCAL_APIC        2
+ #define NMI_INVALID   3
++extern void stop_apics(void);
++#else
++static inline void stop_apics(void) { }
+ #endif /* CONFIG_X86_LOCAL_APIC */
+ #endif /* __ASM_APIC_H */
+Index: linux-2.6.0-test6/include/asm-i386/apicdef.h
+===================================================================
+--- linux-2.6.0-test6.orig/include/asm-i386/apicdef.h  2003-10-07 15:47:25.000000000 +0800
++++ linux-2.6.0-test6/include/asm-i386/apicdef.h       2003-10-07 16:09:01.000000000 +0800
+@@ -86,6 +86,7 @@
+ #define                       APIC_LVT_REMOTE_IRR             (1<<14)
+ #define                       APIC_INPUT_POLARITY             (1<<13)
+ #define                       APIC_SEND_PENDING               (1<<12)
++#define                       APIC_MODE_MASK                  0x700
+ #define                       GET_APIC_DELIVERY_MODE(x)       (((x)>>8)&0x7)
+ #define                       SET_APIC_DELIVERY_MODE(x,y)     (((x)&~0x700)|((y)<<8))
+ #define                               APIC_MODE_FIXED         0x0
+Index: linux-2.6.0-test6/include/asm-i386/kexec.h
+===================================================================
+--- linux-2.6.0-test6.orig/include/asm-i386/kexec.h    2003-10-07 16:09:00.000000000 +0800
++++ linux-2.6.0-test6/include/asm-i386/kexec.h 2003-10-07 16:09:01.000000000 +0800
+@@ -0,0 +1,23 @@
++#ifndef _I386_KEXEC_H
++#define _I386_KEXEC_H
++
++#include <asm/fixmap.h>
++
++/*
++ * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return.
++ * I.e. Maximum page that is mapped directly into kernel memory,
++ * and kmap is not required.
++ *
++ * Someone correct me if FIXADDR_START - PAGEOFFSET is not the correct
++ * calculation for the amount of memory directly mappable into the
++ * kernel memory space.
++ */
++
++/* Maximum physical address we can use pages from */
++#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL)
++/* Maximum address we can reach in physical address mode */
++#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL)
++
++#define KEXEC_REBOOT_CODE_SIZE        4096
++
++#endif /* _I386_KEXEC_H */
+Index: linux-2.6.0-test6/include/asm-i386/unistd.h
+===================================================================
+--- linux-2.6.0-test6.orig/include/asm-i386/unistd.h   2003-10-07 16:08:41.000000000 +0800
++++ linux-2.6.0-test6/include/asm-i386/unistd.h        2003-10-07 16:09:01.000000000 +0800
+@@ -279,8 +279,9 @@
+ #define __NR_utimes           271
+ #define __NR_fadvise64_64     272
+ #define __NR_vserver          273
+-
+-#define NR_syscalls 274
++#define __NR_sys_kexec_load   274
++    
++#define NR_syscalls 275
+ /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
+Index: linux-2.6.0-test6/include/linux/kexec.h
+===================================================================
+--- linux-2.6.0-test6.orig/include/linux/kexec.h       2003-10-07 16:09:00.000000000 +0800
++++ linux-2.6.0-test6/include/linux/kexec.h    2003-10-07 16:09:01.000000000 +0800
+@@ -0,0 +1,54 @@
++#ifndef LINUX_KEXEC_H
++#define LINUX_KEXEC_H
++
++#if CONFIG_KEXEC
++#include <linux/types.h>
++#include <linux/list.h>
++#include <asm/kexec.h>
++
++/* 
++ * This structure is used to hold the arguments that are used when loading
++ * kernel binaries.
++ */
++
++typedef unsigned long kimage_entry_t;
++#define IND_DESTINATION  0x1
++#define IND_INDIRECTION  0x2
++#define IND_DONE         0x4
++#define IND_SOURCE       0x8
++
++#define KEXEC_SEGMENT_MAX 8
++struct kexec_segment {
++      void *buf;
++      size_t bufsz;
++      void *mem;
++      size_t memsz;
++};
++
++struct kimage {
++      kimage_entry_t head;
++      kimage_entry_t *entry;
++      kimage_entry_t *last_entry;
++
++      unsigned long destination;
++      unsigned long offset;
++
++      unsigned long start;
++      struct page *reboot_code_pages;
++
++      unsigned long nr_segments;
++      struct kexec_segment segment[KEXEC_SEGMENT_MAX+1];
++
++      struct list_head dest_pages;
++      struct list_head unuseable_pages;
++};
++
++
++/* kexec interface functions */
++extern void machine_kexec(struct kimage *image);
++extern asmlinkage long sys_kexec(unsigned long entry, long nr_segments, 
++      struct kexec_segment *segments);
++extern struct kimage *kexec_image;
++#endif
++#endif /* LINUX_KEXEC_H */
++
+Index: linux-2.6.0-test6/include/linux/reboot.h
+===================================================================
+--- linux-2.6.0-test6.orig/include/linux/reboot.h      2003-10-07 15:47:25.000000000 +0800
++++ linux-2.6.0-test6/include/linux/reboot.h   2003-10-07 16:09:01.000000000 +0800
+@@ -22,6 +22,7 @@
+  * POWER_OFF   Stop OS and remove all power from system, if possible.
+  * RESTART2    Restart system using given command string.
+  * SW_SUSPEND  Suspend system using software suspend if compiled in.
++ * KEXEC       Restart the system using a different kernel.
+  */
+ #define       LINUX_REBOOT_CMD_RESTART        0x01234567
+@@ -31,6 +32,7 @@
+ #define       LINUX_REBOOT_CMD_POWER_OFF      0x4321FEDC
+ #define       LINUX_REBOOT_CMD_RESTART2       0xA1B2C3D4
+ #define       LINUX_REBOOT_CMD_SW_SUSPEND     0xD000FCE2
++#define LINUX_REBOOT_CMD_KEXEC                0x45584543
+ #ifdef __KERNEL__
+Index: linux-2.6.0-test6/kernel/Makefile
+===================================================================
+--- linux-2.6.0-test6.orig/kernel/Makefile     2003-10-07 16:08:42.000000000 +0800
++++ linux-2.6.0-test6/kernel/Makefile  2003-10-07 16:09:01.000000000 +0800
+@@ -17,6 +17,7 @@
+ obj-$(CONFIG_KALLSYMS) += kallsyms.o
+ obj-$(CONFIG_PM) += power/
+ obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
++obj-$(CONFIG_KEXEC) += kexec.o
+ obj-$(CONFIG_COMPAT) += compat.o
+ obj-$(CONFIG_IKCONFIG) += configs.o
+ obj-$(CONFIG_IKCONFIG_PROC) += configs.o
+Index: linux-2.6.0-test6/kernel/kexec.c
+===================================================================
+--- linux-2.6.0-test6.orig/kernel/kexec.c      2003-10-07 16:09:00.000000000 +0800
++++ linux-2.6.0-test6/kernel/kexec.c   2003-10-07 16:09:01.000000000 +0800
+@@ -0,0 +1,629 @@
++#include <linux/mm.h>
++#include <linux/file.h>
++#include <linux/slab.h>
++#include <linux/fs.h>
++#include <linux/version.h>
++#include <linux/compile.h>
++#include <linux/kexec.h>
++#include <linux/spinlock.h>
++#include <linux/list.h>
++#include <linux/highmem.h>
++#include <net/checksum.h>
++#include <asm/page.h>
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <asm/system.h>
++
++/* When kexec transitions to the new kernel there is a one to one
++ * mapping between physical and virtual addresses.  On processors
++ * where you can disable the MMU this is trivial, and easy.  For
++ * others it is still a simple predictable page table to setup.
++ *
++ * In that environment kexec copies the new kernel to it's final
++ * resting place.  This means I can only support memory whose
++ * physical address can fit in an unsigned long.  In particular
++ * addresses where (pfn << PAGE_SHIFT) > ULONG_MAX cannot be handled.
++ * If the assembly stub has more restrictive requirements
++ * KEXEC_SOURCE_MEMORY_LIMIT and KEXEC_DEST_MEMORY_LIMIT can be
++ * defined more restrictively in <asm/kexec.h>.
++ *
++ * The code for the transition from the current kernel to the 
++ * the new kernel is placed in the reboot_code_buffer, whose size
++ * is given by KEXEC_REBOOT_CODE_SIZE.  In the best case only a single
++ * page of memory is necessary, but some architectures require more.
++ * Because this memory must be identity mapped in the transition from
++ * virtual to physical addresses it must live in the range
++ * 0 - TASK_SIZE, as only the user space mappings are arbitrarily
++ * modifyable.
++ *
++ * The assembly stub in the reboot code buffer is passed a linked list
++ * of descriptor pages detailing the source pages of the new kernel,
++ * and the destination addresses of those source pages.  As this data
++ * structure is not used in the context of the current OS, it must
++ * be self contained.
++ *
++ * The code has been made to work with highmem pages and will use a
++ * destination page in it's final resting place (if it happens 
++ * to allocate it).  The end product of this is that most of the
++ * physical address space, and most of ram can be used.
++ *
++ * Future directions include:
++ *  - allocating a page table with the reboot code buffer identity
++ *    mapped, to simplify machine_kexec and make kexec_on_panic, more
++ *    reliable.  
++ *  - allocating the pages for a page table for machines that cannot
++ *    disable their MMUs.  (Hammer, Alpha...)
++ */
++
++/* KIMAGE_NO_DEST is an impossible destination address..., for
++ * allocating pages whose destination address we do not care about.
++ */
++#define KIMAGE_NO_DEST (-1UL)
++
++static int kimage_is_destination_range(
++      struct kimage *image, unsigned long start, unsigned long end);
++static struct page *kimage_alloc_reboot_code_pages(struct kimage *image);
++static struct page *kimage_alloc_page(struct kimage *image, unsigned int gfp_mask, unsigned long dest);
++
++
++static int kimage_alloc(struct kimage **rimage, 
++      unsigned long nr_segments, struct kexec_segment *segments)
++{
++      int result;
++      struct kimage *image;
++      size_t segment_bytes;
++      struct page *reboot_pages;
++      unsigned long i;
++
++      /* Allocate a controlling structure */
++      result = -ENOMEM;
++      image = kmalloc(sizeof(*image), GFP_KERNEL);
++      if (!image) {
++              goto out;
++      }
++      memset(image, 0, sizeof(*image));
++      image->head = 0;
++      image->entry = &image->head;
++      image->last_entry = &image->head;
++
++      /* Initialize the list of destination pages */
++      INIT_LIST_HEAD(&image->dest_pages);
++
++      /* Initialize the list of unuseable pages */
++      INIT_LIST_HEAD(&image->unuseable_pages);
++
++      /* Read in the segments */
++      image->nr_segments = nr_segments;
++      segment_bytes = nr_segments * sizeof*segments;
++      result = copy_from_user(image->segment, segments, segment_bytes);
++      if (result) 
++              goto out;
++
++      /* Verify we have good destination addresses.  The caller is
++       * responsible for making certain we don't attempt to load
++       * the new image into invalid or reserved areas of RAM.  This
++       * just verifies it is an address we can use. 
++       */
++      result = -EADDRNOTAVAIL;
++      for(i = 0; i < nr_segments; i++) {
++              unsigned long mend;
++              mend = ((unsigned long)(image->segment[i].mem)) + 
++                      image->segment[i].memsz;
++              if (mend >= KEXEC_DESTINATION_MEMORY_LIMIT)
++                      goto out;
++      }
++
++      /* Find a location for the reboot code buffer, and add it
++       * the vector of segments so that it's pages will also be
++       * counted as destination pages.  
++       */
++      result = -ENOMEM;
++      reboot_pages = kimage_alloc_reboot_code_pages(image);
++      if (!reboot_pages) {
++              printk(KERN_ERR "Could not allocate reboot_code_buffer\n");
++              goto out;
++      }
++      image->reboot_code_pages = reboot_pages;
++      image->segment[nr_segments].buf = 0;
++      image->segment[nr_segments].bufsz = 0;
++      image->segment[nr_segments].mem = (void *)(page_to_pfn(reboot_pages) << PAGE_SHIFT);
++      image->segment[nr_segments].memsz = KEXEC_REBOOT_CODE_SIZE;
++      image->nr_segments++;
++
++      result = 0;
++ out:
++      if (result == 0) {
++              *rimage = image;
++      } else {
++              kfree(image);
++      }
++      return result;
++}
++
++static int kimage_is_destination_range(
++      struct kimage *image, unsigned long start, unsigned long end)
++{
++      unsigned long i;
++      for(i = 0; i < image->nr_segments; i++) {
++              unsigned long mstart, mend;
++              mstart = (unsigned long)image->segment[i].mem;
++              mend   = mstart + image->segment[i].memsz;
++              if ((end > mstart) && (start < mend)) {
++                      return 1;
++              }
++      }
++      return 0;
++}
++
++#ifdef CONFIG_MMU
++static int identity_map_pages(struct page *pages, int order)
++{
++      struct mm_struct *mm;
++      struct vm_area_struct *vma;
++      int error;
++      mm = &init_mm;
++      vma = 0;
++
++      down_write(&mm->mmap_sem);
++      error = -ENOMEM;
++      vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
++      if (!vma) {
++              goto out;
++      }
++
++      memset(vma, 0, sizeof(vma));
++      vma->vm_mm = mm;
++      vma->vm_start = page_to_pfn(pages) << PAGE_SHIFT;
++      vma->vm_end = vma->vm_start + (1 << (order + PAGE_SHIFT));
++      vma->vm_ops = 0;
++      vma->vm_flags = VM_SHARED \
++              | VM_READ | VM_WRITE | VM_EXEC \
++              | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC \
++              | VM_DONTCOPY | VM_RESERVED;
++      vma->vm_page_prot = protection_map[vma->vm_flags & 0xf];
++      vma->vm_file = NULL;
++      vma->vm_private_data = NULL;
++      INIT_LIST_HEAD(&vma->shared);
++      insert_vm_struct(mm, vma);
++      
++      error = remap_page_range(vma, vma->vm_start, vma->vm_start,
++              vma->vm_end - vma->vm_start, vma->vm_page_prot);
++      if (error) {
++              goto out;
++      }
++
++      error = 0;
++ out:
++      if (error && vma) {
++              kmem_cache_free(vm_area_cachep, vma);
++              vma = 0;
++      }
++      up_write(&mm->mmap_sem);
++
++      return error;
++}
++#else
++#define identity_map_pages(pages, order) 0
++#endif
++
++struct page *kimage_alloc_reboot_code_pages(struct kimage *image)
++{
++      /* The reboot code buffer is special.  It is the only set of
++       * pages that must be allocated in their final resting place,
++       * and the only set of pages whose final resting place we can
++       * pick. 
++       *
++       * At worst this runs in O(N) of the image size.
++       */
++      struct list_head extra_pages, *pos, *next;
++      struct page *pages;
++      unsigned long addr;
++      int order, count;
++      order = get_order(KEXEC_REBOOT_CODE_SIZE);
++      count = 1 << order;
++      INIT_LIST_HEAD(&extra_pages);
++      do {
++              int i;
++              pages = alloc_pages(GFP_HIGHUSER, order);
++              if (!pages)
++                      break;
++              for(i = 0; i < count; i++) {
++                      SetPageReserved(pages +i);
++              }
++              addr = page_to_pfn(pages) << PAGE_SHIFT;
++              if ((page_to_pfn(pages) >= (TASK_SIZE >> PAGE_SHIFT)) ||
++                      kimage_is_destination_range(image, addr, addr + KEXEC_REBOOT_CODE_SIZE)) {
++                      list_add(&pages->list, &extra_pages);
++                      pages = 0;
++              }
++      } while(!pages);
++      if (pages) {
++              int result;
++              result = identity_map_pages(pages, order);
++              if (result < 0) {
++                      list_add(&pages->list, &extra_pages);
++                      pages = 0;
++              }
++      }
++      /* If I could convert a multi page allocation into a buch of
++       * single page allocations I could add these pages to
++       * image->dest_pages.  For now it is simpler to just free the
++       * pages again.
++       */
++      list_for_each_safe(pos, next, &extra_pages) {
++              struct page *page;
++              int i;
++              page = list_entry(pos, struct page, list);
++              for(i = 0; i < count; i++) {
++                      ClearPageReserved(pages +i);
++              }
++              list_del(&extra_pages);
++              __free_pages(page, order);
++      }
++      return pages;
++}
++
++static int kimage_add_entry(struct kimage *image, kimage_entry_t entry)
++{
++      if (image->offset != 0) {
++              image->entry++;
++      }
++      if (image->entry == image->last_entry) {
++              kimage_entry_t *ind_page;
++              struct page *page;
++              page = kimage_alloc_page(image, GFP_KERNEL, KIMAGE_NO_DEST);
++              if (!page) {
++                      return -ENOMEM;
++              }
++              ind_page = page_address(page);
++              *image->entry = virt_to_phys(ind_page) | IND_INDIRECTION;
++              image->entry = ind_page;
++              image->last_entry = 
++                      ind_page + ((PAGE_SIZE/sizeof(kimage_entry_t)) - 1);
++      }
++      *image->entry = entry;
++      image->entry++;
++      image->offset = 0;
++      return 0;
++}
++
++static int kimage_set_destination(
++      struct kimage *image, unsigned long destination) 
++{
++      int result;
++      destination &= PAGE_MASK;
++      result = kimage_add_entry(image, destination | IND_DESTINATION);
++      if (result == 0) {
++              image->destination = destination;
++      }
++      return result;
++}
++
++
++static int kimage_add_page(struct kimage *image, unsigned long page)
++{
++      int result;
++      page &= PAGE_MASK;
++      result = kimage_add_entry(image, page | IND_SOURCE);
++      if (result == 0) {
++              image->destination += PAGE_SIZE;
++      }
++      return result;
++}
++
++
++static void kimage_free_extra_pages(struct kimage *image)
++{
++      /* Walk through and free any extra destination pages I may have */
++      struct list_head *pos, *next;
++      list_for_each_safe(pos, next, &image->dest_pages) {
++              struct page *page;
++              page = list_entry(pos, struct page, list);
++              list_del(&page->list);
++              ClearPageReserved(page);
++              __free_page(page);
++      }
++      /* Walk through and free any unuseable pages I have cached */
++      list_for_each_safe(pos, next, &image->unuseable_pages) {
++              struct page *page;
++              page = list_entry(pos, struct page, list);
++              list_del(&page->list);
++              ClearPageReserved(page);
++              __free_page(page);
++      }
++
++}
++static int kimage_terminate(struct kimage *image)
++{
++      int result;
++      result = kimage_add_entry(image, IND_DONE);
++      if (result == 0) {
++              /* Point at the terminating element */
++              image->entry--;
++              kimage_free_extra_pages(image);
++      }
++      return result;
++}
++
++#define for_each_kimage_entry(image, ptr, entry) \
++      for (ptr = &image->head; (entry = *ptr) && !(entry & IND_DONE); \
++              ptr = (entry & IND_INDIRECTION)? \
++                      phys_to_virt((entry & PAGE_MASK)): ptr +1)
++
++static void kimage_free(struct kimage *image)
++{
++      kimage_entry_t *ptr, entry;
++      kimage_entry_t ind = 0;
++      int i, count, order;
++      if (!image)
++              return;
++      kimage_free_extra_pages(image);
++      for_each_kimage_entry(image, ptr, entry) {
++              if (entry & IND_INDIRECTION) {
++                      /* Free the previous indirection page */
++                      if (ind & IND_INDIRECTION) {
++                              free_page((unsigned long)phys_to_virt(ind & PAGE_MASK));
++                      }
++                      /* Save this indirection page until we are
++                       * done with it.
++                       */
++                      ind = entry;
++              }
++              else if (entry & IND_SOURCE) {
++                      free_page((unsigned long)phys_to_virt(entry & PAGE_MASK));
++              }
++      }
++      order = get_order(KEXEC_REBOOT_CODE_SIZE);
++      count = 1 << order;
++      do_munmap(&init_mm, 
++              page_to_pfn(image->reboot_code_pages) << PAGE_SHIFT, 
++              count << PAGE_SHIFT);
++      for(i = 0; i < count; i++) {
++              ClearPageReserved(image->reboot_code_pages + i);
++      }
++      __free_pages(image->reboot_code_pages, order);
++      kfree(image);
++}
++
++static kimage_entry_t *kimage_dst_used(struct kimage *image, unsigned long page)
++{
++      kimage_entry_t *ptr, entry;
++      unsigned long destination = 0;
++      for_each_kimage_entry(image, ptr, entry) {
++              if (entry & IND_DESTINATION) {
++                      destination = entry & PAGE_MASK;
++              }
++              else if (entry & IND_SOURCE) {
++                      if (page == destination) {
++                              return ptr;
++                      }
++                      destination += PAGE_SIZE;
++              }
++      }
++      return 0;
++}
++
++static struct page *kimage_alloc_page(struct kimage *image, unsigned int gfp_mask, unsigned long destination)
++{
++      /* Here we implment safe guards to ensure that a source page
++       * is not copied to it's destination page before the data on
++       * the destination page is no longer useful.
++       *
++       * To do this we maintain the invariant that a source page is
++       * either it's own destination page, or it is not a
++       * destination page at all.  
++       *
++       * That is slightly stronger than required, but the proof
++       * that no problems will not occur is trivial, and the
++       * implemenation is simply to verify.
++       *
++       * When allocating all pages normally this algorithm will run
++       * in O(N) time, but in the worst case it will run in O(N^2)
++       * time.   If the runtime is a problem the data structures can
++       * be fixed.
++       */
++      struct page *page;
++      unsigned long addr;
++
++      /* Walk through the list of destination pages, and see if I
++       * have a match.
++       */
++      list_for_each_entry(page, &image->dest_pages, list) {
++              addr = page_to_pfn(page) << PAGE_SHIFT;
++              if (addr == destination) {
++                      list_del(&page->list);
++                      return page;
++              }
++      }
++      page = 0;
++      while(1) {
++              kimage_entry_t *old;
++              /* Allocate a page, if we run out of memory give up */
++              page = alloc_page(gfp_mask);
++              if (!page) {
++                      return 0;
++              }
++              SetPageReserved(page);
++              /* If the page cannot be used file it away */
++              if (page_to_pfn(page) > (KEXEC_SOURCE_MEMORY_LIMIT >> PAGE_SHIFT)) {
++                      list_add(&page->list, &image->unuseable_pages);
++                      continue;
++              }
++              addr = page_to_pfn(page) << PAGE_SHIFT;
++
++              /* If it is the destination page we want use it */
++              if (addr == destination)
++                      break;
++
++              /* If the page is not a destination page use it */
++              if (!kimage_is_destination_range(image, addr, addr + PAGE_SIZE))
++                      break;
++
++              /* I know that the page is someones destination page.
++               * See if there is already a source page for this
++               * destination page.  And if so swap the source pages.
++               */
++              old = kimage_dst_used(image, addr);
++              if (old) {
++                      /* If so move it */
++                      unsigned long old_addr;
++                      struct page *old_page;
++                      
++                      old_addr = *old & PAGE_MASK;
++                      old_page = pfn_to_page(old_addr >> PAGE_SHIFT);
++                      copy_highpage(page, old_page);
++                      *old = addr | (*old & ~PAGE_MASK);
++
++                      /* The old page I have found cannot be a
++                       * destination page, so return it.
++                       */
++                      addr = old_addr;
++                      page = old_page;
++                      break;
++              }
++              else {
++                      /* Place the page on the destination list I
++                       * will use it later.
++                       */
++                      list_add(&page->list, &image->dest_pages);
++              }
++      }
++      return page;
++}
++
++static int kimage_load_segment(struct kimage *image,
++      struct kexec_segment *segment)
++{     
++      unsigned long mstart;
++      int result;
++      unsigned long offset;
++      unsigned long offset_end;
++      unsigned char *buf;
++
++      result = 0;
++      buf = segment->buf;
++      mstart = (unsigned long)segment->mem;
++
++      offset_end = segment->memsz;
++
++      result = kimage_set_destination(image, mstart);
++      if (result < 0) {
++              goto out;
++      }
++      for(offset = 0;  offset < segment->memsz; offset += PAGE_SIZE) {
++              struct page *page;
++              char *ptr;
++              size_t size, leader;
++              page = kimage_alloc_page(image, GFP_HIGHUSER, mstart + offset);
++              if (page == 0) {
++                      result  = -ENOMEM;
++                      goto out;
++              }
++              result = kimage_add_page(image, page_to_pfn(page) << PAGE_SHIFT);
++              if (result < 0) {
++                      goto out;
++              }
++              ptr = kmap(page);
++              if (segment->bufsz < offset) {
++                      /* We are past the end zero the whole page */
++                      memset(ptr, 0, PAGE_SIZE);
++                      kunmap(page);
++                      continue;
++              }
++              size = PAGE_SIZE;
++              leader = 0;
++              if ((offset == 0)) {
++                      leader = mstart & ~PAGE_MASK;
++              }
++              if (leader) {
++                      /* We are on the first page zero the unused portion */
++                      memset(ptr, 0, leader);
++                      size -= leader;
++                      ptr += leader;
++              }
++              if (size > (segment->bufsz - offset)) {
++                      size = segment->bufsz - offset;
++              }
++              if (size < (PAGE_SIZE - leader)) {
++                      /* zero the trailing part of the page */
++                      memset(ptr + size, 0, (PAGE_SIZE - leader) - size);
++              }
++              result = copy_from_user(ptr, buf + offset, size);
++              kunmap(page);
++              if (result) {
++                      result = (result < 0)?result : -EIO;
++                      goto out;
++              }
++      }
++ out:
++      return result;
++}
++
++/*
++ * Exec Kernel system call: for obvious reasons only root may call it.
++ * 
++ * This call breaks up into three pieces.  
++ * - A generic part which loads the new kernel from the current
++ *   address space, and very carefully places the data in the
++ *   allocated pages.
++ *
++ * - A generic part that interacts with the kernel and tells all of
++ *   the devices to shut down.  Preventing on-going dmas, and placing
++ *   the devices in a consistent state so a later kernel can
++ *   reinitialize them.
++ *
++ * - A machine specific part that includes the syscall number
++ *   and the copies the image to it's final destination.  And
++ *   jumps into the image at entry.
++ *
++ * kexec does not sync, or unmount filesystems so if you need
++ * that to happen you need to do that yourself.
++ */
++struct kimage *kexec_image = 0;
++
++asmlinkage long sys_kexec_load(unsigned long entry, unsigned long nr_segments, 
++      struct kexec_segment *segments, unsigned long flags)
++{
++      struct kimage *image;
++      int result;
++              
++      /* We only trust the superuser with rebooting the system. */
++      if (!capable(CAP_SYS_ADMIN))
++              return -EPERM;
++
++      /* In case we need just a little bit of special behavior for
++       * reboot on panic 
++       */
++      if (flags != 0)
++              return -EINVAL;
++
++      if (nr_segments > KEXEC_SEGMENT_MAX)
++              return -EINVAL;
++      image = 0;
++
++      result = 0;
++      if (nr_segments > 0) {
++              unsigned long i;
++              result = kimage_alloc(&image, nr_segments, segments);
++              if (result) {
++                      goto out;
++              }
++              image->start = entry;
++              for(i = 0; i < nr_segments; i++) {
++                      result = kimage_load_segment(image, &segments[i]);
++                      if (result) {
++                              goto out;
++                      }
++              }
++              result = kimage_terminate(image);
++              if (result) {
++                      goto out;
++              }
++      }
++
++      image = xchg(&kexec_image, image);
++
++ out:
++      kimage_free(image);
++      return result;
++}
+Index: linux-2.6.0-test6/kernel/sys.c
+===================================================================
+--- linux-2.6.0-test6.orig/kernel/sys.c        2003-10-07 16:08:42.000000000 +0800
++++ linux-2.6.0-test6/kernel/sys.c     2003-10-09 18:38:57.000000000 +0800
+@@ -17,6 +17,7 @@
+ #include <linux/init.h>
+ #include <linux/highuid.h>
+ #include <linux/fs.h>
++#include <linux/kexec.h>
+ #include <linux/workqueue.h>
+ #include <linux/device.h>
+ #include <linux/times.h>
+@@ -94,6 +95,7 @@
+ int notifier_chain_register(struct notifier_block **list, struct notifier_block *n)
+ {
+       write_lock(&notifier_lock);
++      printk(KERN_EMERG"add noitifier nb %p \n", n);
+       while(*list)
+       {
+               if(n->priority > (*list)->priority)
+@@ -156,6 +158,7 @@
+       while(nb)
+       {
++              printk("nb %p notifier_call %p \n", nb, nb->notifier_call);
+               ret=nb->notifier_call(nb,val,v);
+               if(ret&NOTIFY_STOP_MASK)
+               {
+@@ -208,6 +211,7 @@
+ cond_syscall(sys_lookup_dcookie)
+ cond_syscall(sys_swapon)
+ cond_syscall(sys_swapoff)
++cond_syscall(sys_kexec_load)
+ cond_syscall(sys_init_module)
+ cond_syscall(sys_delete_module)
+ cond_syscall(sys_socketpair)
+@@ -454,6 +458,27 @@
+               machine_restart(buffer);
+               break;
++#ifdef CONFIG_KEXEC
++      case LINUX_REBOOT_CMD_KEXEC:
++      {
++              struct kimage *image;
++              if (arg) {
++                      unlock_kernel();
++                      return -EINVAL;
++              }
++              image = xchg(&kexec_image, 0);
++              if (!image) {
++                      unlock_kernel();
++                      return -EINVAL;
++              }
++              notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL);
++              system_running = 0;
++              device_shutdown();
++              printk(KERN_EMERG "Starting new kernel\n");
++              machine_kexec(image);
++              break;
++      }
++#endif
+ #ifdef CONFIG_SOFTWARE_SUSPEND
+       case LINUX_REBOOT_CMD_SW_SUSPEND:
+               if (!software_suspend_enabled) {
+Index: linux-2.6.0-test6/fs/aio.c
+===================================================================
+--- linux-2.6.0-test6.orig/fs/aio.c    2003-10-07 16:08:40.000000000 +0800
++++ linux-2.6.0-test6/fs/aio.c 2003-10-07 16:09:01.000000000 +0800
+@@ -560,7 +560,7 @@
+  *    (Note: this routine is intended to be called only
+  *    from a kernel thread context)
+  */
+-static void use_mm(struct mm_struct *mm)
++void use_mm(struct mm_struct *mm)
+ {
+       struct mm_struct *active_mm;
+       struct task_struct *tsk = current;
diff --git a/lustre/kernel_patches/patches/lkcd-cvs-2.6.0-test6.patch b/lustre/kernel_patches/patches/lkcd-cvs-2.6.0-test6.patch
new file mode 100644 (file)
index 0000000..d9f7145
--- /dev/null
@@ -0,0 +1,6496 @@
+ 0 files changed
+
+Index: linux-2.6.0-test5/drivers/dump/Makefile
+===================================================================
+--- linux-2.6.0-test5.orig/drivers/dump/Makefile       2003-09-26 14:26:34.000000000 +0800
++++ linux-2.6.0-test5/drivers/dump/Makefile    2003-09-26 14:26:34.000000000 +0800
+@@ -0,0 +1,14 @@
++#
++# Makefile for the dump device drivers.
++#
++
++dump-y                                        := dump_setup.o dump_fmt.o dump_filters.o dump_scheme.o dump_execute.o
++dump-$(CONFIG_X86)                    += dump_i386.o
++dump-$(CONFIG_CRASH_DUMP_MEMDEV)      += dump_memdev.o dump_overlay.o
++dump-objs                             += $(dump-y)
++
++obj-$(CONFIG_CRASH_DUMP)              += dump.o
++obj-$(CONFIG_CRASH_DUMP_BLOCKDEV)     += dump_blockdev.o
++obj-$(CONFIG_CRASH_DUMP_NETDEV)       += dump_netdev.o
++obj-$(CONFIG_CRASH_DUMP_COMPRESS_RLE) += dump_rle.o
++obj-$(CONFIG_CRASH_DUMP_COMPRESS_GZIP)        += dump_gzip.o
+Index: linux-2.6.0-test5/drivers/dump/dump_blockdev.c
+===================================================================
+--- linux-2.6.0-test5.orig/drivers/dump/dump_blockdev.c        2003-09-26 14:26:34.000000000 +0800
++++ linux-2.6.0-test5/drivers/dump/dump_blockdev.c     2003-09-26 14:29:10.000000000 +0800
+@@ -0,0 +1,461 @@
++/*
++ * Implements the dump driver interface for saving a dump to 
++ * a block device through the kernel's generic low level block i/o
++ * routines.
++ *
++ * Started: June 2002 - Mohamed Abbas <mohamed.abbas@intel.com>
++ *    Moved original lkcd kiobuf dump i/o code from dump_base.c
++ *    to use generic dump device interfaces
++ *
++ * Sept 2002 - Bharata B. Rao <bharata@in.ibm.com>
++ *    Convert dump i/o to directly use bio instead of kiobuf for 2.5
++ *
++ * Oct 2002  - Suparna Bhattacharya <suparna@in.ibm.com>
++ *    Rework to new dumpdev.h structures, implement open/close/
++ *    silence, misc fixes (blocknr removal, bio_add_page usage)  
++ *
++ * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
++ * Copyright (C) 2001 - 2002 Matt D. Robinson.  All rights reserved.
++ * Copyright (C) 2002 International Business Machines Corp. 
++ *
++ * This code is released under version 2 of the GNU GPL.
++ */
++
++#include <linux/types.h>
++#include <linux/proc_fs.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/bio.h>
++#include <asm/hardirq.h>
++#include <linux/dump.h>
++#include "dump_methods.h"
++
++extern void *dump_page_buf;
++
++/* The end_io callback for dump i/o completion */
++static int
++dump_bio_end_io(struct bio *bio, unsigned int bytes_done, int error)
++{
++      struct dump_blockdev *dump_bdev;
++
++      if (bio->bi_size) {
++              /* some bytes still left to transfer */
++              return 1; /* not complete */
++      }
++
++      dump_bdev = (struct dump_blockdev *)bio->bi_private;
++      if (error) {
++              printk("IO error while writing the dump, aborting\n");
++      }
++
++      dump_bdev->err = error;
++
++      /* no wakeup needed, since caller polls for completion */
++      return 0;
++}
++
++/* Check if the dump bio is already mapped to the specified buffer */
++static int
++dump_block_map_valid(struct dump_blockdev *dev, struct page *page, 
++      int len) 
++{
++      struct bio *bio = dev->bio;
++      unsigned long bsize = 0;
++
++      if (!bio->bi_vcnt)
++              return 0; /* first time, not mapped */
++
++
++      if ((bio_page(bio) != page) || (len > bio->bi_vcnt << PAGE_SHIFT))
++              return 0; /* buffer not mapped */
++
++      bsize = bdev_hardsect_size(bio->bi_bdev);
++      if ((len & (PAGE_SIZE - 1)) || (len & bsize))
++              return 0; /* alignment checks needed */
++
++      /* quick check to decide if we need to redo bio_add_page */
++      if (bdev_get_queue(bio->bi_bdev)->merge_bvec_fn)
++              return 0; /* device may have other restrictions */
++
++      return 1; /* already mapped */
++}
++
++/* 
++ * Set up the dump bio for i/o from the specified buffer 
++ * Return value indicates whether the full buffer could be mapped or not
++ */
++static int
++dump_block_map(struct dump_blockdev *dev, void *buf, int len)
++{
++      struct page *page = virt_to_page(buf);
++      struct bio *bio = dev->bio;
++      unsigned long bsize = 0;
++
++      bio->bi_bdev = dev->bdev;
++      bio->bi_sector = (dev->start_offset + dev->ddev.curr_offset) >> 9;
++      bio->bi_idx = 0; /* reset index to the beginning */
++
++      if (dump_block_map_valid(dev, page, len)) {
++              /* already mapped and usable rightaway */
++              bio->bi_size = len; /* reset size to the whole bio */
++      } else {
++              /* need to map the bio */
++              bio->bi_size = 0;
++              bio->bi_vcnt = 0;
++              bsize = bdev_hardsect_size(bio->bi_bdev);
++
++              /* first a few sanity checks */
++              if (len < bsize) {
++                      printk("map: len less than hardsect size \n");
++                      return -EINVAL;
++              }
++
++              if ((unsigned long)buf & bsize) {
++                      printk("map: not aligned \n");
++                      return -EINVAL;
++              }
++
++              /* assume contig. page aligned low mem buffer( no vmalloc) */
++              if ((page_address(page) != buf) || (len & (PAGE_SIZE - 1))) {
++                      printk("map: invalid buffer alignment!\n");
++                      return -EINVAL; 
++              }
++              /* finally we can go ahead and map it */
++              while (bio->bi_size < len)
++                      if (bio_add_page(bio, page++, PAGE_SIZE, 0) == 0) {
++                              break;
++                      }
++
++              bio->bi_end_io = dump_bio_end_io;
++              bio->bi_private = dev;
++      }
++
++      if (bio->bi_size != len) {
++              printk("map: bio size = %d not enough for len = %d!\n",
++                      bio->bi_size, len);
++              return -E2BIG;
++      }
++      return 0;
++}
++
++static void
++dump_free_bio(struct bio *bio)
++{
++      if (bio)
++              kfree(bio->bi_io_vec);
++      kfree(bio);
++}
++
++/*
++ * Prepares the dump device so we can take a dump later. 
++ * The caller is expected to have filled up the kdev_id field in the 
++ * block dump dev structure.
++ *
++ * At dump time when dump_block_write() is invoked it will be too 
++ * late to recover, so as far as possible make sure obvious errors 
++ * get caught right here and reported back to the caller.
++ */
++static int
++dump_block_open(struct dump_dev *dev, unsigned long arg)
++{
++      struct dump_blockdev *dump_bdev = DUMP_BDEV(dev);
++      struct block_device *bdev;
++      int retval = 0;
++      struct bio_vec *bvec;
++
++      /* make sure this is a valid block device */
++      if (!arg) {
++              retval = -EINVAL;
++              goto err;
++      }
++
++      /* get a corresponding block_dev struct for this */
++      bdev = bdget((dev_t)arg);
++      if (!bdev) {
++              retval = -ENODEV;
++              goto err;
++      }
++
++      /* get the block device opened */
++      if ((retval = blkdev_get(bdev, O_RDWR | O_LARGEFILE, 0, BDEV_RAW))) {
++              goto err1;
++      }
++
++      if ((dump_bdev->bio = kmalloc(sizeof(struct bio), GFP_KERNEL)) 
++              == NULL) {
++              printk("Cannot allocate bio\n");
++              retval = -ENOMEM;
++              goto err2;
++      }
++
++      bio_init(dump_bdev->bio);
++
++      if ((bvec = kmalloc(sizeof(struct bio_vec) * 
++              (DUMP_BUFFER_SIZE >> PAGE_SHIFT), GFP_KERNEL)) == NULL) {
++              retval = -ENOMEM;
++              goto err3;
++      }
++
++      /* assign the new dump dev structure */
++      dump_bdev->kdev_id = new_decode_dev((dev_t)arg);
++      dump_bdev->bdev = bdev;
++
++      /* make a note of the limit */
++      dump_bdev->limit = bdev->bd_inode->i_size;
++      
++      /* now make sure we can map the dump buffer */
++      dump_bdev->bio->bi_io_vec = bvec;
++      dump_bdev->bio->bi_max_vecs = DUMP_BUFFER_SIZE >> PAGE_SHIFT;
++
++      retval = dump_block_map(dump_bdev, dump_config.dumper->dump_buf, 
++              DUMP_BUFFER_SIZE);
++              
++      if (retval) {
++              printk("open: dump_block_map failed, ret %d\n", retval);
++              goto err3;
++      }
++
++      printk("Block device (%d,%d) successfully configured for dumping\n",
++             MAJOR(dump_bdev->kdev_id),
++             MINOR(dump_bdev->kdev_id));
++
++
++      /* after opening the block device, return */
++      return retval;
++
++err3: dump_free_bio(dump_bdev->bio);
++      dump_bdev->bio = NULL;
++err2: if (bdev) blkdev_put(bdev, BDEV_RAW);
++              goto err;
++err1: if (bdev) bdput(bdev);
++      dump_bdev->bdev = NULL;
++err:  return retval;
++}
++
++/*
++ * Close the dump device and release associated resources
++ * Invoked when unconfiguring the dump device.
++ */
++static int
++dump_block_release(struct dump_dev *dev)
++{
++      struct dump_blockdev *dump_bdev = DUMP_BDEV(dev);
++
++      /* release earlier bdev if present */
++      if (dump_bdev->bdev) {
++              blkdev_put(dump_bdev->bdev, BDEV_RAW);
++              dump_bdev->bdev = NULL;
++      }
++
++      dump_free_bio(dump_bdev->bio);
++      dump_bdev->bio = NULL;
++
++      return 0;
++}
++
++
++/*
++ * Prepare the dump device for use (silence any ongoing activity
++ * and quiesce state) when the system crashes.
++ */
++static int
++dump_block_silence(struct dump_dev *dev)
++{
++      struct dump_blockdev *dump_bdev = DUMP_BDEV(dev);
++      struct request_queue *q = bdev_get_queue(dump_bdev->bdev);
++      int ret;
++
++      /* If we can't get request queue lock, refuse to take the dump */
++      if (!spin_trylock(q->queue_lock))
++              return -EBUSY;
++
++      ret = elv_queue_empty(q);
++      spin_unlock(q->queue_lock);
++
++      /* For now we assume we have the device to ourselves */
++      /* Just a quick sanity check */
++      if (!ret) {
++              /* i/o in flight - safer to quit */
++              return -EBUSY;
++      }
++
++      /* 
++       * Move to a softer level of silencing where no spin_lock_irqs 
++       * are held on other cpus
++       */
++      dump_silence_level = DUMP_SOFT_SPIN_CPUS;       
++
++      __dump_irq_enable();
++
++      printk("Dumping to block device (%d,%d) on CPU %d ...\n",
++             MAJOR(dump_bdev->kdev_id), MINOR(dump_bdev->kdev_id),
++             smp_processor_id());
++      
++      return 0;
++}
++
++/*
++ * Invoked when dumping is done. This is the time to put things back 
++ * (i.e. undo the effects of dump_block_silence) so the device is 
++ * available for normal use.
++ */
++static int
++dump_block_resume(struct dump_dev *dev)
++{
++      __dump_irq_restore();
++      return 0;
++}
++
++
++/*
++ * Seek to the specified offset in the dump device.
++ * Makes sure this is a valid offset, otherwise returns an error.
++ */
++static int
++dump_block_seek(struct dump_dev *dev, loff_t off)
++{
++      struct dump_blockdev *dump_bdev = DUMP_BDEV(dev);
++      loff_t offset = off + dump_bdev->start_offset;
++      
++      if (offset & ( PAGE_SIZE - 1)) {
++              printk("seek: non-page aligned\n");
++              return -EINVAL;
++      }
++
++      if (offset & (bdev_hardsect_size(dump_bdev->bdev) - 1)) {
++              printk("seek: not sector aligned \n");
++              return -EINVAL;
++      }
++
++      if (offset > dump_bdev->limit) {
++              printk("seek: not enough space left on device!\n");
++              return -ENOSPC; 
++      }
++      dev->curr_offset = off;
++      return 0;
++}
++
++/*
++ * Write out a buffer after checking the device limitations, 
++ * sector sizes, etc. Assumes the buffer is in directly mapped 
++ * kernel address space (not vmalloc'ed).
++ *
++ * Returns: number of bytes written or -ERRNO. 
++ */
++static int
++dump_block_write(struct dump_dev *dev, void *buf, 
++      unsigned long len)
++{
++      struct dump_blockdev *dump_bdev = DUMP_BDEV(dev);
++      loff_t offset = dev->curr_offset + dump_bdev->start_offset;
++      int retval = -ENOSPC;
++
++      if (offset >= dump_bdev->limit) {
++              printk("write: not enough space left on device!\n");
++              goto out;
++      }
++
++      /* don't write more blocks than our max limit */
++      if (offset + len > dump_bdev->limit) 
++              len = dump_bdev->limit - offset;
++
++
++      retval = dump_block_map(dump_bdev, buf, len);
++      if (retval){
++              printk("write: dump_block_map failed! err %d\n", retval);
++              goto out;
++      }
++
++      /*
++       * Write out the data to disk.
++       * Assumes the entire buffer mapped to a single bio, which we can
++       * submit and wait for io completion. In the future, may consider
++       * increasing the dump buffer size and submitting multiple bio s 
++       * for better throughput.
++       */
++      dump_bdev->err = -EAGAIN;
++      submit_bio(WRITE, dump_bdev->bio);
++
++      dump_bdev->ddev.curr_offset += len;
++      retval = len;
++ out:
++      return retval;
++}
++
++/*
++ * Name: dump_block_ready()
++ * Func: check if the last dump i/o is over and ready for next request
++ */
++static int
++dump_block_ready(struct dump_dev *dev, void *buf)
++{
++      struct dump_blockdev *dump_bdev = DUMP_BDEV(dev);
++      request_queue_t *q = bdev_get_queue(dump_bdev->bio->bi_bdev);
++
++      /* check for io completion */
++      if (dump_bdev->err == -EAGAIN) {
++              q->unplug_fn(q);
++              return -EAGAIN;
++      }
++
++      if (dump_bdev->err) {
++              printk("dump i/o err\n");
++              return dump_bdev->err;
++      }
++
++      return 0;
++}
++
++
++struct dump_dev_ops dump_blockdev_ops = {
++      .open           = dump_block_open,
++      .release        = dump_block_release,
++      .silence        = dump_block_silence,
++      .resume         = dump_block_resume,
++      .seek           = dump_block_seek,
++      .write          = dump_block_write,
++      /* .read not implemented */
++      .ready          = dump_block_ready
++};
++
++static struct dump_blockdev default_dump_blockdev = {
++      .ddev = {.type_name = "blockdev", .ops = &dump_blockdev_ops, 
++                      .curr_offset = 0},
++      /* 
++       * leave enough room for the longest swap header possibly written 
++       * written by mkswap (likely the largest page size supported by
++       * the arch
++       */
++      .start_offset   = DUMP_HEADER_OFFSET,
++      .err            = 0
++      /* assume the rest of the fields are zeroed by default */
++};    
++      
++struct dump_blockdev *dump_blockdev = &default_dump_blockdev;
++
++static int __init
++dump_blockdev_init(void)
++{
++      if (dump_register_device(&dump_blockdev->ddev) < 0) {
++              printk("block device driver registration failed\n");
++              return -1;
++      }
++              
++      printk("block device driver for LKCD registered\n");
++      return 0;
++}
++
++static void __exit
++dump_blockdev_cleanup(void)
++{
++      dump_unregister_device(&dump_blockdev->ddev);
++      printk("block device driver for LKCD unregistered\n");
++}
++
++MODULE_AUTHOR("LKCD Development Team <lkcd-devel@lists.sourceforge.net>");
++MODULE_DESCRIPTION("Block Dump Driver for Linux Kernel Crash Dump (LKCD)");
++MODULE_LICENSE("GPL");
++
++module_init(dump_blockdev_init);
++module_exit(dump_blockdev_cleanup);
+Index: linux-2.6.0-test5/drivers/dump/dump_execute.c
+===================================================================
+--- linux-2.6.0-test5.orig/drivers/dump/dump_execute.c 2003-09-26 14:26:34.000000000 +0800
++++ linux-2.6.0-test5/drivers/dump/dump_execute.c      2003-09-26 14:26:34.000000000 +0800
+@@ -0,0 +1,126 @@
++/*
++ * The file has the common/generic dump execution code 
++ *
++ * Started: Oct 2002 -  Suparna Bhattacharya <suparna@in.ibm.com>
++ *    Split and rewrote high level dump execute code to make use 
++ *    of dump method interfaces.
++ *
++ * Derived from original code in dump_base.c created by 
++ *    Matt Robinson <yakker@sourceforge.net>)
++ *    
++ * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
++ * Copyright (C) 2001 - 2002 Matt D. Robinson.  All rights reserved.
++ * Copyright (C) 2002 International Business Machines Corp. 
++ *
++ * Assumes dumper and dump config settings are in place
++ * (invokes corresponding dumper specific routines as applicable)
++ *
++ * This code is released under version 2 of the GNU GPL.
++ */
++#include <linux/kernel.h>
++#include <linux/notifier.h>
++#include <linux/dump.h>
++#include "dump_methods.h"
++
++struct notifier_block *dump_notifier_list; /* dump started/ended callback */
++
++/* Dump progress indicator */
++void 
++dump_speedo(int i)
++{
++      static const char twiddle[4] =  { '|', '\\', '-', '/' };
++      printk("%c\b", twiddle[i&3]);
++}
++
++/* Make the device ready and write out the header */
++int dump_begin(void)
++{
++      int err = 0;
++
++      /* dump_dev = dump_config.dumper->dev; */
++      dumper_reset();
++      if ((err = dump_dev_silence())) {
++              /* quiesce failed, can't risk continuing */
++              /* Todo/Future: switch to alternate dump scheme if possible */
++              printk("dump silence dev failed ! error %d\n", err);
++              return err;
++      }
++
++      pr_debug("Writing dump header\n");
++      if ((err = dump_update_header())) {
++              printk("dump update header failed ! error %d\n", err);
++              dump_dev_resume();
++              return err;
++      }
++
++      dump_config.dumper->curr_offset = DUMP_BUFFER_SIZE;
++
++      return 0;
++}
++
++/* 
++ * Write the dump terminator, a final header update and let go of 
++ * exclusive use of the device for dump.
++ */
++int dump_complete(void)
++{
++      int ret = 0;
++
++      if (dump_config.level != DUMP_LEVEL_HEADER) {
++              if ((ret = dump_update_end_marker())) {
++                      printk("dump update end marker error %d\n", ret);
++              }
++              if ((ret = dump_update_header())) {
++                      printk("dump update header error %d\n", ret);
++              }
++      }
++      ret = dump_dev_resume();
++
++      return ret;
++}
++
++/* Saves all dump data */
++int dump_execute_savedump(void)
++{
++      int ret = 0, err = 0;
++
++      if ((ret = dump_begin()))  {
++              return ret;
++      }
++
++      if (dump_config.level != DUMP_LEVEL_HEADER) { 
++              ret = dump_sequencer();
++      }
++      if ((err = dump_complete())) {
++              printk("Dump complete failed. Error %d\n", err);
++      }
++
++      return ret;
++}
++
++/* Does all the real work:  Capture and save state */
++int dump_generic_execute(const char *panic_str, const struct pt_regs *regs)
++{
++      int ret = 0;
++
++      if ((ret = dump_configure_header(panic_str, regs))) {
++              printk("dump config header failed ! error %d\n", ret);
++              return ret;     
++      }
++
++      /* tell interested parties that a dump is about to start */
++      notifier_call_chain(&dump_notifier_list, DUMP_BEGIN, 
++              &dump_config.dump_device);
++
++      if (dump_config.level != DUMP_LEVEL_NONE)
++              ret = dump_execute_savedump();
++
++      pr_debug("dumped %ld blocks of %d bytes each\n", 
++              dump_config.dumper->count, DUMP_BUFFER_SIZE);
++      
++      /* tell interested parties that a dump has completed */
++      notifier_call_chain(&dump_notifier_list, DUMP_END, 
++              &dump_config.dump_device);
++
++      return ret;
++}
+Index: linux-2.6.0-test5/drivers/dump/dump_filters.c
+===================================================================
+--- linux-2.6.0-test5.orig/drivers/dump/dump_filters.c 2003-09-26 14:26:34.000000000 +0800
++++ linux-2.6.0-test5/drivers/dump/dump_filters.c      2003-09-26 14:26:34.000000000 +0800
+@@ -0,0 +1,143 @@
++/*
++ * Default filters to select data to dump for various passes.
++ *
++ * Started: Oct 2002 -  Suparna Bhattacharya <suparna@in.ibm.com>
++ *    Split and rewrote default dump selection logic to generic dump 
++ *    method interfaces 
++ * Derived from a portion of dump_base.c created by 
++ *    Matt Robinson <yakker@sourceforge.net>)
++ *
++ * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
++ * Copyright (C) 2001 - 2002 Matt D. Robinson.  All rights reserved.
++ * Copyright (C) 2002 International Business Machines Corp. 
++ *
++ * Used during single-stage dumping and during stage 1 of the 2-stage scheme
++ * (Stage 2 of the 2-stage scheme uses the fully transparent filters
++ * i.e. passthru filters in dump_overlay.c)
++ *
++ * Future: Custom selective dump may involve a different set of filters.
++ *
++ * This code is released under version 2 of the GNU GPL.
++ */
++
++#include <linux/kernel.h>
++#include <linux/bootmem.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/dump.h>
++#include "dump_methods.h"
++
++
++/* Copied from mm/bootmem.c - FIXME */
++/* return the number of _pages_ that will be allocated for the boot bitmap */
++unsigned long dump_calc_bootmap_pages (void)
++{
++      unsigned long mapsize;
++      unsigned long pages = num_physpages;
++
++      mapsize = (pages+7)/8;
++      mapsize = (mapsize + ~PAGE_MASK) & PAGE_MASK;
++      mapsize >>= PAGE_SHIFT;
++
++      return mapsize;
++}
++
++
++#define DUMP_PFN_SAFETY_MARGIN        1024  /* 4 MB */
++/* temporary */
++extern unsigned long min_low_pfn;
++
++
++int dump_low_page(struct page *p)
++{
++      return page_to_pfn(p) < min_low_pfn + dump_calc_bootmap_pages() 
++                      + 1 + DUMP_PFN_SAFETY_MARGIN;
++}
++
++static inline int kernel_page(struct page *p)
++{
++      /* FIXME: Need to exclude hugetlb pages. Clue: reserved but inuse */
++      return PageReserved(p) || (!PageLRU(p) && PageInuse(p));
++}
++
++static inline int user_page(struct page *p)
++{
++      return PageInuse(p) && (!PageReserved(p) && PageLRU(p));
++}
++
++static inline int unreferenced_page(struct page *p)
++{
++      return !PageInuse(p) && !PageReserved(p);
++}
++
++
++/* loc marks the beginning of a range of pages */
++int dump_filter_kernpages(int pass, unsigned long loc, unsigned long sz)
++{
++      struct page *page = (struct page *)loc;
++      /* if any of the pages is a kernel page, select this set */     
++      while (sz) {
++              if (dump_low_page(page) || kernel_page(page))
++                      return 1;
++              sz -= PAGE_SIZE;
++              page++;
++      }       
++      return 0;
++}
++
++
++/* loc marks the beginning of a range of pages */
++int dump_filter_userpages(int pass, unsigned long loc, unsigned long sz)
++{
++      struct page *page = (struct page *)loc;
++      int ret = 0;
++      /* select if the set has any user page, and no kernel pages  */ 
++      while (sz) {
++              if (user_page(page) && !dump_low_page(page)) {
++                      ret = 1;
++              } else if (kernel_page(page) || dump_low_page(page)) {
++                      return 0;
++              }
++              page++;
++              sz -= PAGE_SIZE;
++      }       
++      return ret;
++}
++
++
++
++/* loc marks the beginning of a range of pages */
++int dump_filter_unusedpages(int pass, unsigned long loc, unsigned long sz)
++{
++      struct page *page = (struct page *)loc;
++
++      /* select if the set does not have any used pages  */   
++      while (sz) {
++              if (!unreferenced_page(page) || dump_low_page(page)) {
++                      return 0;
++              }
++              page++;
++              sz -= PAGE_SIZE;
++      }       
++      return 1;
++}
++
++/* dummy: last (non-existent) pass */
++int dump_filter_none(int pass, unsigned long loc, unsigned long sz)
++{
++      return 0;
++}
++
++/* TBD: resolve level bitmask ? */
++struct dump_data_filter dump_filter_table[] = {
++      { .name = "kern", .selector = dump_filter_kernpages, 
++              .level_mask = DUMP_MASK_KERN},
++      { .name = "user", .selector = dump_filter_userpages, 
++              .level_mask = DUMP_MASK_USED},
++      { .name = "unused", .selector = dump_filter_unusedpages, 
++              .level_mask = DUMP_MASK_UNUSED},
++      { .name = "none", .selector = dump_filter_none, 
++              .level_mask = DUMP_MASK_REST},
++      { .name = "", .selector = NULL, .level_mask = 0}
++};
++
+Index: linux-2.6.0-test5/drivers/dump/dump_fmt.c
+===================================================================
+--- linux-2.6.0-test5.orig/drivers/dump/dump_fmt.c     2003-09-26 14:26:34.000000000 +0800
++++ linux-2.6.0-test5/drivers/dump/dump_fmt.c  2003-09-26 14:26:34.000000000 +0800
+@@ -0,0 +1,399 @@
++/*
++ * Implements the routines which handle the format specific
++ * aspects of dump for the default dump format.
++ *
++ * Used in single stage dumping and stage 1 of soft-boot based dumping 
++ * Saves data in LKCD (lcrash) format 
++ *
++ * Previously a part of dump_base.c
++ *
++ * Started: Oct 2002 -  Suparna Bhattacharya <suparna@in.ibm.com>
++ *    Split off and reshuffled LKCD dump format code around generic
++ *    dump method interfaces.
++ *
++ * Derived from original code created by 
++ *    Matt Robinson <yakker@sourceforge.net>)
++ *
++ * Contributions from SGI, IBM, HP, MCL, and others.
++ *
++ * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
++ * Copyright (C) 2000 - 2002 TurboLinux, Inc.  All rights reserved.
++ * Copyright (C) 2001 - 2002 Matt D. Robinson.  All rights reserved.
++ * Copyright (C) 2002 International Business Machines Corp. 
++ *
++ * This code is released under version 2 of the GNU GPL.
++ */
++
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/time.h>
++#include <linux/sched.h>
++#include <linux/ptrace.h>
++#include <linux/utsname.h>
++#include <asm/dump.h>
++#include <linux/dump.h>
++#include "dump_methods.h"
++
++/*
++ * SYSTEM DUMP LAYOUT
++ * 
++ * System dumps are currently the combination of a dump header and a set
++ * of data pages which contain the system memory.  The layout of the dump
++ * (for full dumps) is as follows:
++ *
++ *             +-----------------------------+
++ *             |     generic dump header     |
++ *             +-----------------------------+
++ *             |   architecture dump header  |
++ *             +-----------------------------+
++ *             |         page header         |
++ *             +-----------------------------+
++ *             |          page data          |
++ *             +-----------------------------+
++ *             |         page header         |
++ *             +-----------------------------+
++ *             |          page data          |
++ *             +-----------------------------+
++ *             |              |              |
++ *             |              |              |
++ *             |              |              |
++ *             |              |              |
++ *             |              V              |
++ *             +-----------------------------+
++ *             |        PAGE_END header      |
++ *             +-----------------------------+
++ *
++ * There are two dump headers, the first which is architecture
++ * independent, and the other which is architecture dependent.  This
++ * allows different architectures to dump different data structures
++ * which are specific to their chipset, CPU, etc.
++ *
++ * After the dump headers come a succession of dump page headers along
++ * with dump pages.  The page header contains information about the page
++ * size, any flags associated with the page (whether it's compressed or
++ * not), and the address of the page.  After the page header is the page
++ * data, which is either compressed (or not).  Each page of data is
++ * dumped in succession, until the final dump header (PAGE_END) is
++ * placed at the end of the dump, assuming the dump device isn't out
++ * of space.
++ *
++ * This mechanism allows for multiple compression types, different
++ * types of data structures, different page ordering, etc., etc., etc.
++ * It's a very straightforward mechanism for dumping system memory.
++ */
++
++struct __dump_header dump_header;  /* the primary dump header              */
++struct __dump_header_asm dump_header_asm; /* the arch-specific dump header */
++
++/*
++ *  Set up common header fields (mainly the arch indep section) 
++ *  Per-cpu state is handled by lcrash_save_context
++ *  Returns the size of the header in bytes.
++ */
++static int lcrash_init_dump_header(const char *panic_str)
++{
++      struct timeval dh_time;
++      struct sysinfo info;
++
++      /* make sure the dump header isn't TOO big */
++      if ((sizeof(struct __dump_header) +
++              sizeof(struct __dump_header_asm)) > DUMP_BUFFER_SIZE) {
++                      printk("lcrash_init_header(): combined "
++                              "headers larger than DUMP_BUFFER_SIZE!\n");
++                      return -E2BIG;
++      }
++
++      /* initialize the dump headers to zero */
++      memset(&dump_header, 0, sizeof(dump_header));
++      memset(&dump_header_asm, 0, sizeof(dump_header_asm));
++
++      /* configure dump header values */
++      dump_header.dh_magic_number = DUMP_MAGIC_NUMBER;
++      dump_header.dh_version = DUMP_VERSION_NUMBER;
++      dump_header.dh_memory_start = PAGE_OFFSET;
++      dump_header.dh_memory_end = DUMP_MAGIC_NUMBER;
++      dump_header.dh_header_size = sizeof(struct __dump_header);
++      si_meminfo(&info);
++      dump_header.dh_memory_size = (u64)info.totalram;
++      dump_header.dh_page_size = PAGE_SIZE;
++      dump_header.dh_dump_level = dump_config.level;
++      dump_header.dh_current_task = (unsigned long) current;
++      dump_header.dh_dump_compress = dump_config.dumper->compress->
++              compress_type;
++      dump_header.dh_dump_flags = dump_config.flags;
++      dump_header.dh_dump_device = dump_config.dumper->dev->device_id; 
++      
++#if DUMP_DEBUG >= 6
++      dump_header.dh_num_bytes = 0;
++#endif
++      dump_header.dh_num_dump_pages = 0;
++      do_gettimeofday(&dh_time);
++      dump_header.dh_time.tv_sec = dh_time.tv_sec;
++      dump_header.dh_time.tv_usec = dh_time.tv_usec;
++
++      memcpy((void *)&(dump_header.dh_utsname_sysname), 
++              (const void *)&(system_utsname.sysname), __NEW_UTS_LEN + 1);
++      memcpy((void *)&(dump_header.dh_utsname_nodename), 
++              (const void *)&(system_utsname.nodename), __NEW_UTS_LEN + 1);
++      memcpy((void *)&(dump_header.dh_utsname_release), 
++              (const void *)&(system_utsname.release), __NEW_UTS_LEN + 1);
++      memcpy((void *)&(dump_header.dh_utsname_version), 
++              (const void *)&(system_utsname.version), __NEW_UTS_LEN + 1);
++      memcpy((void *)&(dump_header.dh_utsname_machine), 
++              (const void *)&(system_utsname.machine), __NEW_UTS_LEN + 1);
++      memcpy((void *)&(dump_header.dh_utsname_domainname), 
++              (const void *)&(system_utsname.domainname), __NEW_UTS_LEN + 1);
++
++      if (panic_str) {
++              memcpy((void *)&(dump_header.dh_panic_string),
++                      (const void *)panic_str, DUMP_PANIC_LEN);
++      }
++
++        dump_header_asm.dha_magic_number = DUMP_ASM_MAGIC_NUMBER;
++        dump_header_asm.dha_version = DUMP_ASM_VERSION_NUMBER;
++        dump_header_asm.dha_header_size = sizeof(dump_header_asm);
++
++      dump_header_asm.dha_smp_num_cpus = num_online_cpus();
++      pr_debug("smp_num_cpus in header %d\n", 
++              dump_header_asm.dha_smp_num_cpus);
++
++      dump_header_asm.dha_dumping_cpu = smp_processor_id();
++      
++      return sizeof(dump_header) + sizeof(dump_header_asm);
++}
++
++
++int dump_lcrash_configure_header(const char *panic_str, 
++      const struct pt_regs *regs)
++{
++      int retval = 0;
++
++      dump_config.dumper->header_len = lcrash_init_dump_header(panic_str);
++
++      /* capture register states for all processors */
++      dump_save_this_cpu(regs);
++      __dump_save_other_cpus(); /* side effect:silence cpus */
++
++      /* configure architecture-specific dump header values */
++      if ((retval = __dump_configure_header(regs))) 
++              return retval;
++
++      dump_config.dumper->header_dirty++;
++      return 0;
++}
++
++/* save register and task context */
++void dump_lcrash_save_context(int cpu, const struct pt_regs *regs, 
++      struct task_struct *tsk)
++{
++      dump_header_asm.dha_smp_current_task[cpu] = (uint32_t) tsk;
++
++      __dump_save_regs(&dump_header_asm.dha_smp_regs[cpu], regs);
++
++      /* take a snapshot of the stack */
++      /* doing this enables us to tolerate slight drifts on this cpu */
++      if (dump_header_asm.dha_stack[cpu]) {
++              memcpy((void *)dump_header_asm.dha_stack[cpu],
++                              tsk->thread_info, THREAD_SIZE);
++      }
++      dump_header_asm.dha_stack_ptr[cpu] = (uint32_t)(tsk->thread_info);
++}
++
++/* write out the header */
++int dump_write_header(void)
++{
++      int retval = 0, size;
++      void *buf = dump_config.dumper->dump_buf;
++
++      /* accounts for DUMP_HEADER_OFFSET if applicable */
++      if ((retval = dump_dev_seek(0))) {
++              printk("Unable to seek to dump header offset: %d\n", 
++                      retval);
++              return retval;
++      }
++
++      memcpy(buf, (void *)&dump_header, sizeof(dump_header));
++      size = sizeof(dump_header);
++      memcpy(buf + size, (void *)&dump_header_asm, sizeof(dump_header_asm));
++      size += sizeof(dump_header_asm);
++      size = PAGE_ALIGN(size);
++      retval = dump_ll_write(buf , size);
++
++      if (retval < size) 
++              return (retval >= 0) ? ENOSPC : retval;
++
++      return 0;
++}
++
++int dump_generic_update_header(void)
++{
++      int err = 0;
++
++      if (dump_config.dumper->header_dirty) {
++              if ((err = dump_write_header())) {
++                      printk("dump write header failed !err %d\n", err);
++              } else {
++                      dump_config.dumper->header_dirty = 0;
++              }
++      }
++
++      return err;
++}
++
++static inline int is_curr_stack_page(struct page *page, unsigned long size)
++{
++      unsigned long thread_addr = (unsigned long)current_thread_info();
++      unsigned long addr = (unsigned long)page_address(page);
++
++      return !PageHighMem(page) && (addr < thread_addr + THREAD_SIZE)
++              && (addr + size > thread_addr);
++}
++
++static inline int is_dump_page(struct page *page, unsigned long size)
++{
++      unsigned long addr = (unsigned long)page_address(page);
++      unsigned long dump_buf = (unsigned long)dump_config.dumper->dump_buf;
++
++      return !PageHighMem(page) && (addr < dump_buf + DUMP_BUFFER_SIZE)
++              && (addr + size > dump_buf);
++}
++
++int dump_allow_compress(struct page *page, unsigned long size)
++{
++      /*
++       * Don't compress the page if any part of it overlaps
++       * with the current stack or dump buffer (since the contents
++       * in these could be changing while compression is going on)
++       */
++      return !is_curr_stack_page(page, size) && !is_dump_page(page, size);
++}
++
++void lcrash_init_pageheader(struct __dump_page *dp, struct page *page, 
++      unsigned long sz)
++{
++      memset(dp, sizeof(struct __dump_page), 0);
++      dp->dp_flags = 0; 
++      dp->dp_size = 0;
++      if (sz > 0)
++              dp->dp_address = page_to_pfn(page) << PAGE_SHIFT;
++
++#if DUMP_DEBUG > 6
++      dp->dp_page_index = dump_header.dh_num_dump_pages;
++      dp->dp_byte_offset = dump_header.dh_num_bytes + DUMP_BUFFER_SIZE
++              + DUMP_HEADER_OFFSET; /* ?? */
++#endif /* DUMP_DEBUG */
++}
++
++int dump_lcrash_add_data(unsigned long loc, unsigned long len)
++{
++      struct page *page = (struct page *)loc;
++      void *addr, *buf = dump_config.dumper->curr_buf;
++      struct __dump_page *dp = (struct __dump_page *)buf; 
++      int bytes, size;
++
++      if (buf > dump_config.dumper->dump_buf + DUMP_BUFFER_SIZE)
++              return -ENOMEM;
++
++      lcrash_init_pageheader(dp, page, len);
++      buf += sizeof(struct __dump_page);
++
++      while (len) {
++              addr = kmap_atomic(page, KM_DUMP);
++              size = bytes = (len > PAGE_SIZE) ? PAGE_SIZE : len;     
++              /* check for compression */
++              if (dump_allow_compress(page, bytes)) {
++                      size = dump_compress_data((char *)addr, bytes, (char *)buf);
++              }
++              /* set the compressed flag if the page did compress */
++              if (size && (size < bytes)) {
++                      dp->dp_flags |= DUMP_DH_COMPRESSED;
++              } else {
++                      /* compression failed -- default to raw mode */
++                      dp->dp_flags |= DUMP_DH_RAW;
++                      memcpy(buf, addr, bytes);
++                      size = bytes;
++              }
++              /* memset(buf, 'A', size); temporary: testing only !! */
++              kunmap_atomic(addr, KM_DUMP);
++              dp->dp_size += size;
++              buf += size;
++              len -= bytes;
++              page++;
++      }
++
++      /* now update the header */
++#if DUMP_DEBUG > 6
++      dump_header.dh_num_bytes += dp->dp_size + sizeof(*dp);
++#endif
++      dump_header.dh_num_dump_pages++;
++      dump_config.dumper->header_dirty++;
++
++      dump_config.dumper->curr_buf = buf;     
++
++      return len;
++}
++
++int dump_lcrash_update_end_marker(void)
++{
++      struct __dump_page *dp = 
++              (struct __dump_page *)dump_config.dumper->curr_buf;
++      unsigned long left;
++      int ret = 0;
++              
++      lcrash_init_pageheader(dp, NULL, 0);
++      dp->dp_flags |= DUMP_DH_END; /* tbd: truncation test ? */
++      
++      /* now update the header */
++#if DUMP_DEBUG > 6
++      dump_header.dh_num_bytes += sizeof(*dp);
++#endif
++      dump_config.dumper->curr_buf += sizeof(*dp);
++      left = dump_config.dumper->curr_buf - dump_config.dumper->dump_buf;
++
++      printk("\n");
++
++      while (left) {
++              if ((ret = dump_dev_seek(dump_config.dumper->curr_offset))) {
++                      printk("Seek failed at offset 0x%llx\n", 
++                      dump_config.dumper->curr_offset);
++                      return ret;
++              }
++
++              if (DUMP_BUFFER_SIZE > left) 
++                      memset(dump_config.dumper->curr_buf, 'm', 
++                              DUMP_BUFFER_SIZE - left);
++
++              if ((ret = dump_ll_write(dump_config.dumper->dump_buf, 
++                      DUMP_BUFFER_SIZE)) < DUMP_BUFFER_SIZE) {
++                      return (ret < 0) ? ret : -ENOSPC;
++              }
++
++              dump_config.dumper->curr_offset += DUMP_BUFFER_SIZE;
++      
++              if (left > DUMP_BUFFER_SIZE) {
++                      left -= DUMP_BUFFER_SIZE;
++                      memcpy(dump_config.dumper->dump_buf, 
++                      dump_config.dumper->dump_buf + DUMP_BUFFER_SIZE, left);
++                      dump_config.dumper->curr_buf -= DUMP_BUFFER_SIZE;
++              } else {
++                      left = 0;
++              }
++      }
++      return 0;
++}
++
++
++/* Default Formatter (lcrash) */
++struct dump_fmt_ops dump_fmt_lcrash_ops = {
++      .configure_header       = dump_lcrash_configure_header,
++      .update_header          = dump_generic_update_header,
++      .save_context           = dump_lcrash_save_context,
++      .add_data               = dump_lcrash_add_data,
++      .update_end_marker      = dump_lcrash_update_end_marker
++};
++
++struct dump_fmt dump_fmt_lcrash = {
++      .name   = "lcrash",
++      .ops    = &dump_fmt_lcrash_ops
++};
++
+Index: linux-2.6.0-test5/drivers/dump/dump_gzip.c
+===================================================================
+--- linux-2.6.0-test5.orig/drivers/dump/dump_gzip.c    2003-09-26 14:26:34.000000000 +0800
++++ linux-2.6.0-test5/drivers/dump/dump_gzip.c 2003-09-26 14:26:34.000000000 +0800
+@@ -0,0 +1,118 @@
++/*
++ * GZIP Compression functions for kernel crash dumps.
++ *
++ * Created by: Matt Robinson (yakker@sourceforge.net)
++ * Copyright 2001 Matt D. Robinson.  All rights reserved.
++ *
++ * This code is released under version 2 of the GNU GPL.
++ */
++
++/* header files */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/sched.h>
++#include <linux/fs.h>
++#include <linux/file.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/dump.h>
++#include <linux/zlib.h>
++#include <linux/vmalloc.h>
++
++static void *deflate_workspace;
++
++/*
++ * Name: dump_compress_gzip()
++ * Func: Compress a DUMP_PAGE_SIZE page using gzip-style algorithms (the.
++ *       deflate functions similar to what's used in PPP).
++ */
++static u16
++dump_compress_gzip(const u8 *old, u16 oldsize, u8 *new, u16 newsize)
++{
++      /* error code and dump stream */
++      int err;
++      z_stream dump_stream;
++      
++      dump_stream.workspace = deflate_workspace;
++      
++      if ((err = zlib_deflateInit(&dump_stream, Z_BEST_COMPRESSION)) != Z_OK) {
++              /* fall back to RLE compression */
++              printk("dump_compress_gzip(): zlib_deflateInit() "
++                      "failed (%d)!\n", err);
++              return 0;
++      }
++
++      /* use old (page of memory) and size (DUMP_PAGE_SIZE) as in-streams */
++      dump_stream.next_in = (u8 *) old;
++      dump_stream.avail_in = oldsize;
++
++      /* out streams are new (dpcpage) and new size (DUMP_DPC_PAGE_SIZE) */
++      dump_stream.next_out = new;
++      dump_stream.avail_out = newsize;
++
++      /* deflate the page -- check for error */
++      err = zlib_deflate(&dump_stream, Z_FINISH);
++      if (err != Z_STREAM_END) {
++              /* zero is return code here */
++              (void)zlib_deflateEnd(&dump_stream);
++              printk("dump_compress_gzip(): zlib_deflate() failed (%d)!\n",
++                      err);
++              return 0;
++      }
++
++      /* let's end the deflated compression stream */
++      if ((err = zlib_deflateEnd(&dump_stream)) != Z_OK) {
++              printk("dump_compress_gzip(): zlib_deflateEnd() "
++                      "failed (%d)!\n", err);
++      }
++
++      /* return the compressed byte total (if it's smaller) */
++      if (dump_stream.total_out >= oldsize) {
++              return oldsize;
++      }
++      return dump_stream.total_out;
++}
++
++/* setup the gzip compression functionality */
++static struct __dump_compress dump_gzip_compression = {
++      .compress_type = DUMP_COMPRESS_GZIP,
++      .compress_func = dump_compress_gzip,
++      .compress_name = "GZIP",
++};
++
++/*
++ * Name: dump_compress_gzip_init()
++ * Func: Initialize gzip as a compression mechanism.
++ */
++static int __init
++dump_compress_gzip_init(void)
++{
++      deflate_workspace = vmalloc(zlib_deflate_workspacesize());
++      if (!deflate_workspace) {
++              printk("dump_compress_gzip_init(): Failed to "
++                      "alloc %d bytes for deflate workspace\n",
++                      zlib_deflate_workspacesize());
++              return -ENOMEM;
++      }
++      dump_register_compression(&dump_gzip_compression);
++      return 0;
++}
++
++/*
++ * Name: dump_compress_gzip_cleanup()
++ * Func: Remove gzip as a compression mechanism.
++ */
++static void __exit
++dump_compress_gzip_cleanup(void)
++{
++      vfree(deflate_workspace);
++      dump_unregister_compression(DUMP_COMPRESS_GZIP);
++}
++
++/* module initialization */
++module_init(dump_compress_gzip_init);
++module_exit(dump_compress_gzip_cleanup);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("LKCD Development Team <lkcd-devel@lists.sourceforge.net>");
++MODULE_DESCRIPTION("Gzip compression module for crash dump driver");
+Index: linux-2.6.0-test5/drivers/dump/dump_i386.c
+===================================================================
+--- linux-2.6.0-test5.orig/drivers/dump/dump_i386.c    2003-09-26 14:26:34.000000000 +0800
++++ linux-2.6.0-test5/drivers/dump/dump_i386.c 2003-09-26 14:26:34.000000000 +0800
+@@ -0,0 +1,329 @@
++/*
++ * Architecture specific (i386) functions for Linux crash dumps.
++ *
++ * Created by: Matt Robinson (yakker@sgi.com)
++ *
++ * Copyright 1999 Silicon Graphics, Inc. All rights reserved.
++ *
++ * 2.3 kernel modifications by: Matt D. Robinson (yakker@turbolinux.com)
++ * Copyright 2000 TurboLinux, Inc.  All rights reserved.
++ * 
++ * This code is released under version 2 of the GNU GPL.
++ */
++
++/*
++ * The hooks for dumping the kernel virtual memory to disk are in this
++ * file.  Any time a modification is made to the virtual memory mechanism,
++ * these routines must be changed to use the new mechanisms.
++ */
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/smp.h>
++#include <linux/fs.h>
++#include <linux/vmalloc.h>
++#include <linux/mm.h>
++#include <linux/dump.h>
++#include "dump_methods.h"
++#include <linux/irq.h>
++
++#include <asm/processor.h>
++#include <asm/e820.h>
++#include <asm/hardirq.h>
++#include <asm/nmi.h>
++
++static __s32       saved_irq_count;   /* saved preempt_count() flags */
++
++static int
++alloc_dha_stack(void)
++{
++      int i;
++      void *ptr;
++      
++      if (dump_header_asm.dha_stack[0])
++              return 0;
++
++      ptr = vmalloc(THREAD_SIZE * num_online_cpus());
++      if (!ptr) {
++              printk("vmalloc for dha_stacks failed\n");
++              return -ENOMEM;
++      }
++
++      for (i = 0; i < num_online_cpus(); i++) {
++              dump_header_asm.dha_stack[i] = (u32)((unsigned long)ptr +
++                              (i * THREAD_SIZE));
++      }
++      return 0;
++}
++
++static int
++free_dha_stack(void) 
++{
++      if (dump_header_asm.dha_stack[0]) {
++              vfree((void *)dump_header_asm.dha_stack[0]);    
++              dump_header_asm.dha_stack[0] = 0;
++      }
++      return 0;
++}
++
++
++void 
++__dump_save_regs(struct pt_regs *dest_regs, const struct pt_regs *regs)
++{
++      *dest_regs = *regs;
++
++      /* In case of panic dumps, we collects regs on entry to panic.
++       * so, we shouldn't 'fix' ssesp here again. But it is hard to
++       * tell just looking at regs whether ssesp need fixing. We make
++       * this decision by looking at xss in regs. If we have better
++       * means to determine that ssesp are valid (by some flag which
++       * tells that we are here due to panic dump), then we can use
++       * that instead of this kludge.
++       */
++      if (!user_mode(regs)) {
++              if ((0xffff & regs->xss) == __KERNEL_DS) 
++                      /* already fixed up */
++                      return;
++              dest_regs->esp = (unsigned long)&(regs->esp);
++              __asm__ __volatile__ ("movw %%ss, %%ax;"
++                      :"=a"(dest_regs->xss));
++      }
++}
++
++
++#ifdef CONFIG_SMP
++extern cpumask_t irq_affinity[];
++extern irq_desc_t irq_desc[];
++extern void dump_send_ipi(void);
++
++static int dump_expect_ipi[NR_CPUS];
++static atomic_t waiting_for_dump_ipi;
++static cpumask_t saved_affinity[NR_IRQS];
++
++extern void stop_this_cpu(void *); /* exported by i386 kernel */
++
++static int
++dump_nmi_callback(struct pt_regs *regs, int cpu) 
++{
++      if (!dump_expect_ipi[cpu])
++              return 0;
++
++      dump_expect_ipi[cpu] = 0;
++      
++      dump_save_this_cpu(regs);
++      atomic_dec(&waiting_for_dump_ipi);
++
++ level_changed:
++      switch (dump_silence_level) {
++      case DUMP_HARD_SPIN_CPUS:       /* Spin until dump is complete */
++              while (dump_oncpu) {
++                      barrier();      /* paranoia */
++                      if (dump_silence_level != DUMP_HARD_SPIN_CPUS)
++                              goto level_changed;
++
++                      cpu_relax();    /* kill time nicely */
++              }
++              break;
++
++      case DUMP_HALT_CPUS:            /* Execute halt */
++              stop_this_cpu(NULL);
++              break;
++              
++      case DUMP_SOFT_SPIN_CPUS:
++              /* Mark the task so it spins in schedule */
++              set_tsk_thread_flag(current, TIF_NEED_RESCHED);
++              break;
++      }
++
++      return 1;
++}
++
++/* save registers on other processors */
++void 
++__dump_save_other_cpus(void)
++{
++      int i, cpu = smp_processor_id();
++      int other_cpus = num_online_cpus()-1;
++      
++      if (other_cpus > 0) {
++              atomic_set(&waiting_for_dump_ipi, other_cpus);
++
++              for (i = 0; i < NR_CPUS; i++) {
++                      dump_expect_ipi[i] = (i != cpu && cpu_online(i));
++              }
++
++              /* short circuit normal NMI handling temporarily */
++              set_nmi_callback(dump_nmi_callback);
++              wmb();
++
++              dump_send_ipi();
++              /* may be we dont need to wait for NMI to be processed. 
++                 just write out the header at the end of dumping, if
++                 this IPI is not processed until then, there probably
++                 is a problem and we just fail to capture state of 
++                 other cpus. */
++              while(atomic_read(&waiting_for_dump_ipi) > 0) {
++                      cpu_relax();
++              }
++
++              unset_nmi_callback();
++      }
++}
++
++/*
++ * Routine to save the old irq affinities and change affinities of all irqs to
++ * the dumping cpu.
++ */
++static void 
++set_irq_affinity(void)
++{
++      int i;
++      int cpu = smp_processor_id();
++
++      memcpy(saved_affinity, irq_affinity, NR_IRQS * sizeof(cpumask_t));
++      for (i = 0; i < NR_IRQS; i++) {
++              if (irq_desc[i].handler == NULL)
++                      continue;
++              irq_affinity[i] = cpumask_of_cpu(cpu);
++              if (irq_desc[i].handler->set_affinity != NULL)
++                      irq_desc[i].handler->set_affinity(i, irq_affinity[i]);
++      }
++}
++
++/*
++ * Restore old irq affinities.
++ */
++static void 
++reset_irq_affinity(void)
++{
++      int i;
++
++      memcpy(irq_affinity, saved_affinity, NR_IRQS * sizeof(unsigned long));
++      for (i = 0; i < NR_IRQS; i++) {
++              if (irq_desc[i].handler == NULL)
++                      continue;
++              if (irq_desc[i].handler->set_affinity != NULL)
++                      irq_desc[i].handler->set_affinity(i, saved_affinity[i]);
++      }
++}
++
++#else /* !CONFIG_SMP */
++#define set_irq_affinity()    do { } while (0)
++#define reset_irq_affinity()  do { } while (0)
++#define save_other_cpu_states() do { } while (0)
++#endif /* !CONFIG_SMP */
++
++/* 
++ * Kludge - dump from interrupt context is unreliable (Fixme)
++ *
++ * We do this so that softirqs initiated for dump i/o 
++ * get processed and we don't hang while waiting for i/o
++ * to complete or in any irq synchronization attempt.
++ *
++ * This is not quite legal of course, as it has the side 
++ * effect of making all interrupts & softirqs triggered 
++ * while dump is in progress complete before currently 
++ * pending softirqs and the currently executing interrupt 
++ * code. 
++ */
++static inline void
++irq_bh_save(void)
++{
++      saved_irq_count = irq_count();
++      preempt_count() &= ~(HARDIRQ_MASK|SOFTIRQ_MASK);
++}
++
++static inline void
++irq_bh_restore(void)
++{
++      preempt_count() |= saved_irq_count;
++}
++
++/*
++ * Name: __dump_irq_enable
++ * Func: Reset system so interrupts are enabled.
++ *     This is used for dump methods that require interrupts
++ *     Eventually, all methods will have interrupts disabled
++ *     and this code can be removed.
++ *
++ *     Change irq affinities
++ *     Re-enable interrupts
++ */
++void 
++__dump_irq_enable(void)
++{
++      set_irq_affinity();
++      irq_bh_save();
++      local_irq_enable();
++}
++
++/*
++ * Name: __dump_irq_restore
++ * Func: Resume the system state in an architecture-specific way.
++
++ */
++void 
++__dump_irq_restore(void)
++{
++      local_irq_disable();
++      reset_irq_affinity();
++      irq_bh_restore();
++}
++
++/*
++ * Name: __dump_configure_header()
++ * Func: Meant to fill in arch specific header fields except per-cpu state
++ * already captured via __dump_save_context for all CPUs.
++ */
++int
++__dump_configure_header(const struct pt_regs *regs)
++{
++      return (0);
++}
++
++/*
++ * Name: __dump_init()
++ * Func: Initialize the dumping routine process.
++ */
++void
++__dump_init(uint64_t local_memory_start)
++{
++      return;
++}
++
++/*
++ * Name: __dump_open()
++ * Func: Open the dump device (architecture specific).
++ */
++void
++__dump_open(void)
++{
++      alloc_dha_stack();
++}
++
++/*
++ * Name: __dump_cleanup()
++ * Func: Free any architecture specific data structures. This is called
++ *       when the dump module is being removed.
++ */
++void
++__dump_cleanup(void)
++{
++      free_dha_stack();
++}
++
++extern int pfn_is_ram(unsigned long);
++
++/*
++ * Name: __dump_page_valid()
++ * Func: Check if page is valid to dump.
++ */ 
++int 
++__dump_page_valid(unsigned long index)
++{
++      if (!pfn_valid(index))
++              return 0;
++
++      return pfn_is_ram(index);
++}
++
+Index: linux-2.6.0-test5/drivers/dump/dump_memdev.c
+===================================================================
+--- linux-2.6.0-test5.orig/drivers/dump/dump_memdev.c  2003-09-26 14:26:34.000000000 +0800
++++ linux-2.6.0-test5/drivers/dump/dump_memdev.c       2003-09-26 14:26:34.000000000 +0800
+@@ -0,0 +1,640 @@
++/*
++ * Implements the dump driver interface for saving a dump in available
++ * memory areas. The saved pages may be written out to persistent storage  
++ * after a soft reboot.
++ *
++ * Started: Oct 2002 -  Suparna Bhattacharya <suparna@in.ibm.com>
++ *
++ * Copyright (C) 2002 International Business Machines Corp. 
++ *
++ * This code is released under version 2 of the GNU GPL.
++ *
++ * The approach of tracking pages containing saved dump using map pages 
++ * allocated as needed has been derived from the Mission Critical Linux 
++ * mcore dump implementation. 
++ *
++ * Credits and a big thanks for letting the lkcd project make use of 
++ * the excellent piece of work and also helping with clarifications 
++ * and tips along the way are due to:
++ *    Dave Winchell <winchell@mclx.com> (primary author of mcore)
++ *    Jeff Moyer <moyer@mclx.com>
++ *    Josh Huber <huber@mclx.com>
++ *
++ * For those familiar with the mcore code, the main differences worth
++ * noting here (besides the dump device abstraction) result from enabling 
++ * "high" memory pages (pages not permanently mapped in the kernel 
++ * address space) to be used for saving dump data (because of which a 
++ * simple virtual address based linked list cannot be used anymore for 
++ * managing free pages), an added level of indirection for faster 
++ * lookups during the post-boot stage, and the idea of pages being 
++ * made available as they get freed up while dump to memory progresses 
++ * rather than one time before starting the dump. The last point enables 
++ * a full memory snapshot to be saved starting with an initial set of 
++ * bootstrap pages given a good compression ratio. (See dump_overlay.c)
++ *
++ */
++
++/*
++ * -----------------MEMORY LAYOUT ------------------
++ * The memory space consists of a set of discontiguous pages, and
++ * discontiguous map pages as well, rooted in a chain of indirect
++ * map pages (also discontiguous). Except for the indirect maps 
++ * (which must be preallocated in advance), the rest of the pages 
++ * could be in high memory.
++ *
++ * root
++ *  |    ---------    --------        --------
++ *  -->  | .  . +|--->|  .  +|------->| . .  |       indirect 
++ *       --|--|---    ---|----        --|-|---             maps
++ *         |  |          |                    | |     
++ *    ------  ------   -------     ------ -------
++ *    | .  |  | .  |   | .  . |    | .  | |  . . |   maps 
++ *    --|---  --|---   --|--|--    --|--- ---|-|--
++ *     page    page    page page   page   page page  data
++ *                                                   pages
++ *
++ * Writes to the dump device happen sequentially in append mode.
++ * The main reason for the existence of the indirect map is
++ * to enable a quick way to lookup a specific logical offset in
++ * the saved data post-soft-boot, e.g. to writeout pages
++ * with more critical data first, even though such pages
++ * would have been compressed and copied last, being the lowest
++ * ranked candidates for reuse due to their criticality.
++ * (See dump_overlay.c)
++ */
++#include <linux/mm.h>
++#include <linux/highmem.h>
++#include <linux/bootmem.h>
++#include <linux/dump.h>
++#include "dump_methods.h"
++
++#define DUMP_MAP_SZ (PAGE_SIZE / sizeof(unsigned long)) /* direct map size */
++#define DUMP_IND_MAP_SZ       DUMP_MAP_SZ - 1  /* indirect map size */
++#define DUMP_NR_BOOTSTRAP     64  /* no of bootstrap pages */
++
++extern int dump_low_page(struct page *);
++
++/* check if the next entry crosses a page boundary */
++static inline int is_last_map_entry(unsigned long *map)
++{
++      unsigned long addr = (unsigned long)(map + 1);
++
++      return (!(addr & (PAGE_SIZE - 1)));
++}
++
++/* Todo: should have some validation checks */
++/* The last entry in the indirect map points to the next indirect map */
++/* Indirect maps are referred to directly by virtual address */
++static inline unsigned long *next_indirect_map(unsigned long *map)
++{
++      return (unsigned long *)map[DUMP_IND_MAP_SZ];
++}
++
++#ifdef CONFIG_CRASH_DUMP_SOFTBOOT
++/* Called during early bootup - fixme: make this __init */
++void dump_early_reserve_map(struct dump_memdev *dev)
++{
++      unsigned long *map1, *map2;
++      loff_t off = 0, last = dev->last_used_offset >> PAGE_SHIFT;
++      int i, j;
++      
++      printk("Reserve bootmap space holding previous dump of %lld pages\n",
++                      last);
++      map1= (unsigned long *)dev->indirect_map_root;
++
++      while (map1 && (off < last)) {
++              reserve_bootmem(virt_to_phys((void *)map1), PAGE_SIZE);
++              for (i=0;  (i < DUMP_MAP_SZ - 1) && map1[i] && (off < last); 
++                      i++, off += DUMP_MAP_SZ) {
++                      pr_debug("indirect map[%d] = 0x%lx\n", i, map1[i]);
++                      if (map1[i] >= max_low_pfn)
++                              continue;
++                      reserve_bootmem(map1[i] << PAGE_SHIFT, PAGE_SIZE);
++                      map2 = pfn_to_kaddr(map1[i]);
++                      for (j = 0 ; (j < DUMP_MAP_SZ) && map2[j] && 
++                              (off + j < last); j++) {
++                              pr_debug("\t map[%d][%d] = 0x%lx\n", i, j, 
++                                      map2[j]);
++                              if (map2[j] < max_low_pfn) {
++                                      reserve_bootmem(map2[j] << PAGE_SHIFT,
++                                              PAGE_SIZE);
++                              }
++                      }
++              }
++              map1 = next_indirect_map(map1);
++      }
++      dev->nr_free = 0; /* these pages don't belong to this boot */
++}
++#endif
++
++/* mark dump pages so that they aren't used by this kernel */
++void dump_mark_map(struct dump_memdev *dev)
++{
++      unsigned long *map1, *map2;
++      loff_t off = 0, last = dev->last_used_offset >> PAGE_SHIFT;
++      struct page *page;
++      int i, j;
++      
++      printk("Dump: marking pages in use by previous dump\n");
++      map1= (unsigned long *)dev->indirect_map_root;
++
++      while (map1 && (off < last)) {
++              page = virt_to_page(map1);      
++              set_page_count(page, 1);
++              for (i=0;  (i < DUMP_MAP_SZ - 1) && map1[i] && (off < last); 
++                      i++, off += DUMP_MAP_SZ) {
++                      pr_debug("indirect map[%d] = 0x%lx\n", i, map1[i]);
++                      page = pfn_to_page(map1[i]);
++                      set_page_count(page, 1);
++                      map2 = kmap_atomic(page, KM_DUMP);
++                      for (j = 0 ; (j < DUMP_MAP_SZ) && map2[j] && 
++                              (off + j < last); j++) {
++                              pr_debug("\t map[%d][%d] = 0x%lx\n", i, j, 
++                                      map2[j]);
++                              page = pfn_to_page(map2[j]);
++                              set_page_count(page, 1);
++                      }
++              }
++              map1 = next_indirect_map(map1);
++      }
++}
++      
++
++/* 
++ * Given a logical offset into the mem device lookup the 
++ * corresponding page 
++ *    loc is specified in units of pages 
++ * Note: affects curr_map (even in the case where lookup fails)
++ */
++struct page *dump_mem_lookup(struct dump_memdev *dump_mdev, unsigned long loc)
++{
++      unsigned long *map;
++      unsigned long i, index = loc / DUMP_MAP_SZ;
++      struct page *page = NULL;
++      unsigned long curr_pfn, curr_map, *curr_map_ptr = NULL;
++
++      map = (unsigned long *)dump_mdev->indirect_map_root;
++      if (!map)
++              return NULL;
++
++      if (loc > dump_mdev->last_offset >> PAGE_SHIFT)
++              return NULL;
++
++      /* 
++       * first locate the right indirect map 
++       * in the chain of indirect maps 
++       */
++      for (i = 0; i + DUMP_IND_MAP_SZ < index ; i += DUMP_IND_MAP_SZ) {
++              if (!(map = next_indirect_map(map)))
++                      return NULL;
++      }
++      /* then the right direct map */
++      /* map entries are referred to by page index */
++      if ((curr_map = map[index - i])) {
++              page = pfn_to_page(curr_map);
++              /* update the current traversal index */
++              /* dump_mdev->curr_map = &map[index - i];*/
++              curr_map_ptr = &map[index - i];
++      }
++
++      if (page)
++              map = kmap_atomic(page, KM_DUMP);
++      else 
++              return NULL;
++
++      /* and finally the right entry therein */
++      /* data pages are referred to by page index */
++      i = index * DUMP_MAP_SZ;
++      if ((curr_pfn = map[loc - i])) {
++              page = pfn_to_page(curr_pfn);
++              dump_mdev->curr_map = curr_map_ptr;
++              dump_mdev->curr_map_offset = loc - i;
++              dump_mdev->ddev.curr_offset = loc << PAGE_SHIFT;
++      } else {
++              page = NULL;
++      }
++      kunmap_atomic(map, KM_DUMP);
++
++      return page;
++}
++                      
++/* 
++ * Retrieves a pointer to the next page in the dump device 
++ * Used during the lookup pass post-soft-reboot 
++ */
++struct page *dump_mem_next_page(struct dump_memdev *dev)
++{
++      unsigned long i; 
++      unsigned long *map;     
++      struct page *page = NULL;
++
++      if (dev->ddev.curr_offset + PAGE_SIZE >= dev->last_offset) {
++              return NULL;
++      }
++
++      if ((i = (unsigned long)(++dev->curr_map_offset)) >= DUMP_MAP_SZ) {
++              /* move to next map */  
++              if (is_last_map_entry(++dev->curr_map)) {
++                      /* move to the next indirect map page */
++                      printk("dump_mem_next_page: go to next indirect map\n");
++                      dev->curr_map = (unsigned long *)*dev->curr_map;
++                      if (!dev->curr_map)
++                              return NULL;
++              }
++              i = dev->curr_map_offset = 0;
++              pr_debug("dump_mem_next_page: next map 0x%lx, entry 0x%lx\n",
++                              dev->curr_map, *dev->curr_map);
++
++      };
++      
++      if (*dev->curr_map) {
++              map = kmap_atomic(pfn_to_page(*dev->curr_map), KM_DUMP);
++              if (map[i])
++                      page = pfn_to_page(map[i]);
++              kunmap_atomic(map, KM_DUMP);
++              dev->ddev.curr_offset += PAGE_SIZE;
++      };
++
++      return page;
++}
++
++/* Copied from dump_filters.c */
++static inline int kernel_page(struct page *p)
++{
++      /* FIXME: Need to exclude hugetlb pages. Clue: reserved but inuse */
++      return PageReserved(p) || (!PageLRU(p) && PageInuse(p));
++}
++
++static inline int user_page(struct page *p)
++{
++      return PageInuse(p) && (!PageReserved(p) && PageLRU(p));
++}
++
++int dump_reused_by_boot(struct page *page)
++{
++      /* Todo
++       * Checks:
++       * if PageReserved 
++       * if < __end + bootmem_bootmap_pages for this boot + allowance 
++       * if overwritten by initrd (how to check ?)
++       * Also, add more checks in early boot code
++       * e.g. bootmem bootmap alloc verify not overwriting dump, and if
++       * so then realloc or move the dump pages out accordingly.
++       */
++
++      /* Temporary proof of concept hack, avoid overwriting kern pages */
++
++      return (kernel_page(page) || dump_low_page(page) || user_page(page));
++}
++
++
++/* Uses the free page passed in to expand available space */
++int dump_mem_add_space(struct dump_memdev *dev, struct page *page)
++{
++      struct page *map_page;
++      unsigned long *map;     
++      unsigned long i; 
++
++      if (!dev->curr_map)
++              return -ENOMEM; /* must've exhausted indirect map */
++
++      if (!*dev->curr_map || dev->curr_map_offset >= DUMP_MAP_SZ) {
++              /* add map space */
++              *dev->curr_map = page_to_pfn(page);
++              dev->curr_map_offset = 0;
++              return 0;
++      }
++
++      /* add data space */
++      i = dev->curr_map_offset;
++      map_page = pfn_to_page(*dev->curr_map);
++      map = (unsigned long *)kmap_atomic(map_page, KM_DUMP);
++      map[i] = page_to_pfn(page);
++      kunmap_atomic(map, KM_DUMP);
++      dev->curr_map_offset = ++i;
++      dev->last_offset += PAGE_SIZE;
++      if (i >= DUMP_MAP_SZ) {
++              /* move to next map */
++              if (is_last_map_entry(++dev->curr_map)) {
++                      /* move to the next indirect map page */
++                      pr_debug("dump_mem_add_space: using next"
++                      "indirect map\n");
++                      dev->curr_map = (unsigned long *)*dev->curr_map;
++              }
++      }               
++      return 0;
++}
++
++
++/* Caution: making a dest page invalidates existing contents of the page */
++int dump_check_and_free_page(struct dump_memdev *dev, struct page *page)
++{
++      int err = 0;
++
++      /* 
++       * the page can be used as a destination only if we are sure
++       * it won't get overwritten by the soft-boot, and is not
++       * critical for us right now.
++       */
++      if (dump_reused_by_boot(page))
++              return 0;
++
++      if ((err = dump_mem_add_space(dev, page))) {
++              printk("Warning: Unable to extend memdev space. Err %d\n",
++              err);
++              return 0;
++      }
++
++      dev->nr_free++;
++      return 1;
++}
++
++
++/* Set up the initial maps and bootstrap space  */
++/* Must be called only after any previous dump is written out */
++int dump_mem_open(struct dump_dev *dev, unsigned long devid)
++{
++      struct dump_memdev *dump_mdev = DUMP_MDEV(dev);
++      unsigned long nr_maps, *map, *prev_map = &dump_mdev->indirect_map_root;
++      void *addr;
++      struct page *page;
++      unsigned long i = 0;
++      int err = 0;
++
++      /* Todo: sanity check for unwritten previous dump */
++
++      /* allocate pages for indirect map (non highmem area) */
++      nr_maps = num_physpages / DUMP_MAP_SZ; /* maps to cover entire mem */
++      for (i = 0; i < nr_maps; i += DUMP_IND_MAP_SZ) {
++              if (!(map = (unsigned long *)dump_alloc_mem(PAGE_SIZE))) {
++                      printk("Unable to alloc indirect map %ld\n", 
++                              i / DUMP_IND_MAP_SZ);
++                      return -ENOMEM;
++              }
++              clear_page(map);
++              *prev_map = (unsigned long)map;
++              prev_map = &map[DUMP_IND_MAP_SZ];
++      };
++              
++      dump_mdev->curr_map = (unsigned long *)dump_mdev->indirect_map_root;
++      dump_mdev->curr_map_offset = 0; 
++
++      /* 
++       * allocate a few bootstrap pages: at least 1 map and 1 data page
++       * plus enough to save the dump header
++       */
++      i = 0;
++      do {
++              if (!(addr = dump_alloc_mem(PAGE_SIZE))) {
++                      printk("Unable to alloc bootstrap page %ld\n", i);
++                      return -ENOMEM;
++              }
++
++              page = virt_to_page(addr);
++              if (dump_low_page(page)) {
++                      dump_free_mem(addr);
++                      continue;
++              }
++
++              if (dump_mem_add_space(dump_mdev, page)) {
++                      printk("Warning: Unable to extend memdev "
++                                      "space. Err %d\n", err);
++                      dump_free_mem(addr);
++                      continue;
++              }
++              i++;
++      } while (i < DUMP_NR_BOOTSTRAP);
++
++      printk("dump memdev init: %ld maps, %ld bootstrap pgs, %ld free pgs\n",
++              nr_maps, i, dump_mdev->last_offset >> PAGE_SHIFT);
++      
++      dump_mdev->last_bs_offset = dump_mdev->last_offset;
++
++      return 0;
++}
++
++/* Releases all pre-alloc'd pages */
++int dump_mem_release(struct dump_dev *dev)
++{
++      struct dump_memdev *dump_mdev = DUMP_MDEV(dev);
++      struct page *page, *map_page;
++      unsigned long *map, *prev_map;
++      void *addr;
++      int i;
++
++      if (!dump_mdev->nr_free)
++              return 0;
++
++      pr_debug("dump_mem_release\n");
++      page = dump_mem_lookup(dump_mdev, 0);
++      for (i = 0; page && (i < DUMP_NR_BOOTSTRAP - 1); i++) {
++              if (PageHighMem(page))
++                      break;
++              addr = page_address(page);
++              if (!addr) {
++                      printk("page_address(%p) = NULL\n", page);
++                      break;
++              }
++              pr_debug("Freeing page at 0x%lx\n", addr); 
++              dump_free_mem(addr);
++              if (dump_mdev->curr_map_offset >= DUMP_MAP_SZ - 1) {
++                      map_page = pfn_to_page(*dump_mdev->curr_map);
++                      if (PageHighMem(map_page))
++                              break;
++                      page = dump_mem_next_page(dump_mdev);
++                      addr = page_address(map_page);
++                      if (!addr) {
++                              printk("page_address(%p) = NULL\n", 
++                                      map_page);
++                              break;
++                      }
++                      pr_debug("Freeing map page at 0x%lx\n", addr);
++                      dump_free_mem(addr);
++                      i++;
++              } else {
++                      page = dump_mem_next_page(dump_mdev);
++              }
++      }
++
++      /* now for the last used bootstrap page used as a map page */
++      if ((i < DUMP_NR_BOOTSTRAP) && (*dump_mdev->curr_map)) {
++              map_page = pfn_to_page(*dump_mdev->curr_map);
++              if ((map_page) && !PageHighMem(map_page)) {
++                      addr = page_address(map_page);
++                      if (!addr) {
++                              printk("page_address(%p) = NULL\n", map_page);
++                      } else {
++                              pr_debug("Freeing map page at 0x%lx\n", addr);
++                              dump_free_mem(addr);
++                              i++;
++                      }
++              }
++      }
++
++      printk("Freed %d bootstrap pages\n", i);
++
++      /* free the indirect maps */
++      map = (unsigned long *)dump_mdev->indirect_map_root;
++
++      i = 0;
++      while (map) {
++              prev_map = map;
++              map = next_indirect_map(map);
++              dump_free_mem(prev_map);
++              i++;
++      }
++
++      printk("Freed %d indirect map(s)\n", i);
++
++      /* Reset the indirect map */
++      dump_mdev->indirect_map_root = 0;
++      dump_mdev->curr_map = 0;
++
++      /* Reset the free list */
++      dump_mdev->nr_free = 0;
++
++      dump_mdev->last_offset = dump_mdev->ddev.curr_offset = 0;
++      dump_mdev->last_used_offset = 0;
++      dump_mdev->curr_map = NULL;
++      dump_mdev->curr_map_offset = 0;
++      return 0;
++}
++
++/*
++ * Long term:
++ * It is critical for this to be very strict. Cannot afford
++ * to have anything running and accessing memory while we overwrite 
++ * memory (potential risk of data corruption).
++ * If in doubt (e.g if a cpu is hung and not responding) just give
++ * up and refuse to proceed with this scheme.
++ *
++ * Note: I/O will only happen after soft-boot/switchover, so we can 
++ * safely disable interrupts and force stop other CPUs if this is
++ * going to be a disruptive dump, no matter what they
++ * are in the middle of.
++ */
++/* 
++ * ATM Most of this is already taken care of in the nmi handler 
++ * We may halt the cpus rightaway if we know this is going to be disruptive 
++ * For now, since we've limited ourselves to overwriting free pages we
++ * aren't doing much here. Eventually, we'd have to wait to make sure other
++ * cpus aren't using memory we could be overwriting
++ */
++int dump_mem_silence(struct dump_dev *dev)
++{
++      struct dump_memdev *dump_mdev = DUMP_MDEV(dev);
++
++      if (dump_mdev->last_offset > dump_mdev->last_bs_offset) {
++              /* prefer to run lkcd config & start with a clean slate */
++              return -EEXIST;
++      }
++      return 0;
++}
++
++extern int dump_overlay_resume(void);
++
++/* Trigger the next stage of dumping */
++int dump_mem_resume(struct dump_dev *dev)
++{
++      dump_overlay_resume(); 
++      return 0;
++}
++
++/* 
++ * Allocate mem dev pages as required and copy buffer contents into it.
++ * Fails if the no free pages are available
++ * Keeping it simple and limited for starters (can modify this over time)
++ *  Does not handle holes or a sparse layout
++ *  Data must be in multiples of PAGE_SIZE
++ */
++int dump_mem_write(struct dump_dev *dev, void *buf, unsigned long len)
++{
++      struct dump_memdev *dump_mdev = DUMP_MDEV(dev);
++      struct page *page;
++      unsigned long n = 0;
++      void *addr;
++      unsigned long *saved_curr_map, saved_map_offset;
++      int ret = 0;
++
++      pr_debug("dump_mem_write: offset 0x%llx, size %ld\n", 
++              dev->curr_offset, len);
++
++      if (dev->curr_offset + len > dump_mdev->last_offset)  {
++              printk("Out of space to write\n");
++              return -ENOSPC;
++      }
++      
++      if ((len & (PAGE_SIZE - 1)) || (dev->curr_offset & (PAGE_SIZE - 1)))
++              return -EINVAL; /* not aligned in units of page size */
++
++      saved_curr_map = dump_mdev->curr_map;
++      saved_map_offset = dump_mdev->curr_map_offset;
++      page = dump_mem_lookup(dump_mdev, dev->curr_offset >> PAGE_SHIFT);
++
++      for (n = len; (n > 0) && page; n -= PAGE_SIZE, buf += PAGE_SIZE ) {
++              addr = kmap_atomic(page, KM_DUMP);
++              /* memset(addr, 'x', PAGE_SIZE); */
++              memcpy(addr, buf, PAGE_SIZE);
++              kunmap_atomic(addr, KM_DUMP);
++              /* dev->curr_offset += PAGE_SIZE; */
++              page = dump_mem_next_page(dump_mdev);
++      }
++
++      dump_mdev->curr_map = saved_curr_map;
++      dump_mdev->curr_map_offset = saved_map_offset;
++
++      if (dump_mdev->last_used_offset < dev->curr_offset)
++              dump_mdev->last_used_offset = dev->curr_offset;
++
++      return (len - n) ? (len - n) : ret ;
++}
++
++/* dummy - always ready */
++int dump_mem_ready(struct dump_dev *dev, void *buf)
++{
++      return 0;
++}
++
++/* 
++ * Should check for availability of space to write upto the offset 
++ * affects only the curr_offset; last_offset untouched 
++ * Keep it simple: Only allow multiples of PAGE_SIZE for now 
++ */
++int dump_mem_seek(struct dump_dev *dev, loff_t offset)
++{
++      struct dump_memdev *dump_mdev = DUMP_MDEV(dev);
++
++      if (offset & (PAGE_SIZE - 1))
++              return -EINVAL; /* allow page size units only for now */
++      
++      /* Are we exceeding available space ? */
++      if (offset > dump_mdev->last_offset) {
++              printk("dump_mem_seek failed for offset 0x%llx\n",
++                      offset);
++              return -ENOSPC; 
++      }
++
++      dump_mdev->ddev.curr_offset = offset;
++      return 0;
++}
++
++struct dump_dev_ops dump_memdev_ops = {
++      .open           = dump_mem_open,
++      .release        = dump_mem_release,
++      .silence        = dump_mem_silence,
++      .resume         = dump_mem_resume,
++      .seek           = dump_mem_seek,
++      .write          = dump_mem_write,
++      .read           = NULL, /* not implemented at the moment */
++      .ready          = dump_mem_ready
++};
++
++static struct dump_memdev default_dump_memdev = {
++      .ddev = {.type_name = "memdev", .ops = &dump_memdev_ops,
++               .device_id = 0x14}
++      /* assume the rest of the fields are zeroed by default */
++};    
++      
++/* may be overwritten if a previous dump exists */
++struct dump_memdev *dump_memdev = &default_dump_memdev;
++
+Index: linux-2.6.0-test5/drivers/dump/dump_netdev.c
+===================================================================
+--- linux-2.6.0-test5.orig/drivers/dump/dump_netdev.c  2003-09-26 14:26:34.000000000 +0800
++++ linux-2.6.0-test5/drivers/dump/dump_netdev.c       2003-09-26 14:26:34.000000000 +0800
+@@ -0,0 +1,880 @@
++/*
++ * Implements the dump driver interface for saving a dump via network
++ * interface. 
++ *
++ * Some of this code has been taken/adapted from Ingo Molnar's netconsole
++ * code. LKCD team expresses its thanks to Ingo.
++ *
++ * Started: June 2002 - Mohamed Abbas <mohamed.abbas@intel.com>
++ *    Adapted netconsole code to implement LKCD dump over the network.
++ *
++ * Nov 2002 - Bharata B. Rao <bharata@in.ibm.com>
++ *    Innumerable code cleanups, simplification and some fixes.
++ *    Netdump configuration done by ioctl instead of using module parameters.
++ *
++ * Copyright (C) 2001  Ingo Molnar <mingo@redhat.com>
++ * Copyright (C) 2002 International Business Machines Corp. 
++ *
++ *  This code is released under version 2 of the GNU GPL.
++ */
++
++#include <net/tcp.h>
++#include <net/udp.h>
++#include <linux/delay.h>
++#include <linux/random.h>
++#include <linux/reboot.h>
++#include <linux/module.h>
++#include <linux/dump.h>
++#include <linux/dump_netdev.h>
++
++#include <asm/unaligned.h>
++
++static int startup_handshake;
++static int page_counter;
++static struct net_device *dump_ndev;
++static struct in_device *dump_in_dev;
++static u16 source_port, target_port;
++static u32 source_ip, target_ip;
++static unsigned char daddr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} ;
++static spinlock_t dump_skb_lock = SPIN_LOCK_UNLOCKED;
++static int dump_nr_skbs;
++static struct sk_buff *dump_skb;
++static unsigned long flags_global;
++static int netdump_in_progress;
++static char device_name[IFNAMSIZ];
++
++/*
++ * security depends on the trusted path between the netconsole
++ * server and netconsole client, since none of the packets are
++ * encrypted. The random magic number protects the protocol
++ * against spoofing.
++ */
++static u64 dump_magic;
++
++#define MAX_UDP_CHUNK 1460
++#define MAX_PRINT_CHUNK (MAX_UDP_CHUNK-HEADER_LEN)
++
++/*
++ * We maintain a small pool of fully-sized skbs,
++ * to make sure the message gets out even in
++ * extreme OOM situations.
++ */
++#define DUMP_MAX_SKBS 32
++
++#define MAX_SKB_SIZE \
++              (MAX_UDP_CHUNK + sizeof(struct udphdr) + \
++                              sizeof(struct iphdr) + sizeof(struct ethhdr))
++
++static void
++dump_refill_skbs(void)
++{
++      struct sk_buff *skb;
++      unsigned long flags;
++
++      spin_lock_irqsave(&dump_skb_lock, flags);
++      while (dump_nr_skbs < DUMP_MAX_SKBS) {
++              skb = alloc_skb(MAX_SKB_SIZE, GFP_ATOMIC);
++              if (!skb)
++                      break;
++              if (dump_skb)
++                      skb->next = dump_skb;
++              else
++                      skb->next = NULL;
++              dump_skb = skb;
++              dump_nr_skbs++;
++      }
++      spin_unlock_irqrestore(&dump_skb_lock, flags);
++}
++
++static struct
++sk_buff * dump_get_skb(void)
++{
++      struct sk_buff *skb;
++      unsigned long flags;
++
++      spin_lock_irqsave(&dump_skb_lock, flags);
++      skb = dump_skb;
++      if (skb) {
++              dump_skb = skb->next;
++              skb->next = NULL;
++              dump_nr_skbs--;
++      }
++      spin_unlock_irqrestore(&dump_skb_lock, flags);
++        
++      return skb;
++}
++
++/*
++ * Zap completed output skbs.
++ */
++static void
++zap_completion_queue(void)
++{
++      int count;
++      unsigned long flags;
++      int cpu = smp_processor_id();
++      struct softnet_data *softnet_data;
++              
++
++      softnet_data = &__get_cpu_var(softnet_data);
++      count=0;
++      if (softnet_data[cpu].completion_queue) {
++              struct sk_buff *clist;
++      
++              local_irq_save(flags);
++              clist = softnet_data[cpu].completion_queue;
++              softnet_data[cpu].completion_queue = NULL;
++              local_irq_restore(flags);
++
++              while (clist != NULL) {
++                      struct sk_buff *skb = clist;
++                      clist = clist->next;
++                      __kfree_skb(skb);
++                      count++;
++                      if (count > 10000)
++                              printk("Error in sk list\n");
++              }
++      }
++}
++
++static void
++dump_send_skb(struct net_device *dev, const char *msg, unsigned int msg_len,
++              reply_t *reply)
++{
++      int once = 1;
++      int total_len, eth_len, ip_len, udp_len, count = 0;
++      struct sk_buff *skb;
++      struct udphdr *udph;
++      struct iphdr *iph;
++      struct ethhdr *eth; 
++
++      udp_len = msg_len + HEADER_LEN + sizeof(*udph);
++      ip_len = eth_len = udp_len + sizeof(*iph);
++      total_len = eth_len + ETH_HLEN;
++
++repeat_loop:
++      zap_completion_queue();
++      if (dump_nr_skbs < DUMP_MAX_SKBS)
++              dump_refill_skbs();
++
++      skb = alloc_skb(total_len, GFP_ATOMIC);
++      if (!skb) {
++              skb = dump_get_skb();
++              if (!skb) {
++                      count++;
++                      if (once && (count == 1000000)) {
++                              printk("possibly FATAL: out of netconsole "
++                                      "skbs!!! will keep retrying.\n");
++                              once = 0;
++                      }
++                      dev->poll_controller(dev);
++                      goto repeat_loop;
++              }
++      }
++
++      atomic_set(&skb->users, 1);
++      skb_reserve(skb, total_len - msg_len - HEADER_LEN);
++      skb->data[0] = NETCONSOLE_VERSION;
++
++      put_unaligned(htonl(reply->nr), (u32 *) (skb->data + 1));
++      put_unaligned(htonl(reply->code), (u32 *) (skb->data + 5));
++      put_unaligned(htonl(reply->info), (u32 *) (skb->data + 9));
++
++      memcpy(skb->data + HEADER_LEN, msg, msg_len);
++      skb->len += msg_len + HEADER_LEN;
++
++      udph = (struct udphdr *) skb_push(skb, sizeof(*udph));
++      udph->source = source_port;
++      udph->dest = target_port;
++      udph->len = htons(udp_len);
++      udph->check = 0;
++
++      iph = (struct iphdr *)skb_push(skb, sizeof(*iph));
++
++      iph->version  = 4;
++      iph->ihl      = 5;
++      iph->tos      = 0;
++      iph->tot_len  = htons(ip_len);
++      iph->id       = 0;
++      iph->frag_off = 0;
++      iph->ttl      = 64;
++      iph->protocol = IPPROTO_UDP;
++      iph->check    = 0;
++      iph->saddr    = source_ip;
++      iph->daddr    = target_ip;
++      iph->check    = ip_fast_csum((unsigned char *)iph, iph->ihl);
++
++      eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
++
++      eth->h_proto = htons(ETH_P_IP);
++      memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
++      memcpy(eth->h_dest, daddr, dev->addr_len);
++
++      count=0;
++repeat_poll:
++      spin_lock(&dev->xmit_lock);
++      dev->xmit_lock_owner = smp_processor_id();
++
++      count++;
++
++
++      if (netif_queue_stopped(dev)) {
++              dev->xmit_lock_owner = -1;
++              spin_unlock(&dev->xmit_lock);
++
++              dev->poll_controller(dev);
++              zap_completion_queue();
++
++
++              goto repeat_poll;
++      }
++
++      dev->hard_start_xmit(skb, dev);
++
++      dev->xmit_lock_owner = -1;
++      spin_unlock(&dev->xmit_lock);
++}
++
++static unsigned short
++udp_check(struct udphdr *uh, int len, unsigned long saddr, unsigned long daddr,
++              unsigned long base)
++{
++      return csum_tcpudp_magic(saddr, daddr, len, IPPROTO_UDP, base);
++}
++
++static int
++udp_checksum_init(struct sk_buff *skb, struct udphdr *uh,
++                           unsigned short ulen, u32 saddr, u32 daddr)
++{
++      if (uh->check == 0) {
++              skb->ip_summed = CHECKSUM_UNNECESSARY;
++      } else if (skb->ip_summed == CHECKSUM_HW) {
++              skb->ip_summed = CHECKSUM_UNNECESSARY;
++              if (!udp_check(uh, ulen, saddr, daddr, skb->csum))
++                      return 0;
++              skb->ip_summed = CHECKSUM_NONE;
++      }
++      if (skb->ip_summed != CHECKSUM_UNNECESSARY)
++              skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen,
++                              IPPROTO_UDP, 0);
++      /* Probably, we should checksum udp header (it should be in cache
++       * in any case) and data in tiny packets (< rx copybreak).
++       */
++      return 0;
++}
++
++static __inline__ int
++__udp_checksum_complete(struct sk_buff *skb)
++{
++      return (unsigned short)csum_fold(skb_checksum(skb, 0, skb->len,
++                              skb->csum));
++}
++
++static __inline__
++int udp_checksum_complete(struct sk_buff *skb)
++{
++      return skb->ip_summed != CHECKSUM_UNNECESSARY &&
++              __udp_checksum_complete(skb);
++}
++
++int new_req = 0;
++static req_t req;
++
++static int
++dump_rx_hook(struct sk_buff *skb)
++{
++      int proto;
++      struct iphdr *iph;
++      struct udphdr *uh;
++      __u32 len, saddr, daddr, ulen;
++      req_t *__req;
++
++      /* 
++       * First check if were are dumping or doing startup handshake, if
++       * not quickly return.
++       */
++      if (!netdump_in_progress)
++              return NET_RX_SUCCESS;
++
++      if (skb->dev->type != ARPHRD_ETHER)
++              goto out;
++
++      proto = ntohs(skb->mac.ethernet->h_proto);
++      if (proto != ETH_P_IP)
++              goto out;
++
++      if (skb->pkt_type == PACKET_OTHERHOST)
++              goto out;
++
++      if (skb_shared(skb))
++              goto out;
++
++       /* IP header correctness testing: */
++      iph = (struct iphdr *)skb->data;
++      if (!pskb_may_pull(skb, sizeof(struct iphdr)))
++              goto out;
++
++      if (iph->ihl < 5 || iph->version != 4)
++              goto out;
++
++      if (!pskb_may_pull(skb, iph->ihl*4))
++              goto out;
++
++      if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)
++              goto out;
++
++      len = ntohs(iph->tot_len);
++      if (skb->len < len || len < iph->ihl*4)
++              goto out;
++
++      saddr = iph->saddr;
++      daddr = iph->daddr;
++      if (iph->protocol != IPPROTO_UDP)
++              goto out;
++
++      if (source_ip != daddr)
++              goto out;
++
++      if (target_ip != saddr)
++              goto out;
++
++      len -= iph->ihl*4;
++      uh = (struct udphdr *)(((char *)iph) + iph->ihl*4);
++      ulen = ntohs(uh->len);
++
++      if (ulen != len || ulen < (sizeof(*uh) + sizeof(*__req)))
++              goto out;
++
++      if (udp_checksum_init(skb, uh, ulen, saddr, daddr) < 0)
++              goto out;
++
++      if (udp_checksum_complete(skb))
++              goto out;
++
++      if (source_port != uh->dest)
++              goto out;
++
++      if (target_port != uh->source)
++              goto out;
++
++      __req = (req_t *)(uh + 1);
++      if ((ntohl(__req->command) != COMM_GET_MAGIC) &&
++          (ntohl(__req->command) != COMM_HELLO) &&
++          (ntohl(__req->command) != COMM_START_WRITE_NETDUMP_ACK) &&
++          (ntohl(__req->command) != COMM_START_NETDUMP_ACK) &&
++          (memcmp(&__req->magic, &dump_magic, sizeof(dump_magic)) != 0))
++              goto out;
++
++      req.magic = ntohl(__req->magic);
++      req.command = ntohl(__req->command);
++      req.from = ntohl(__req->from);
++      req.to = ntohl(__req->to);
++      req.nr = ntohl(__req->nr);
++      new_req = 1;
++out:
++      return NET_RX_DROP;
++}
++
++static void
++dump_send_mem(struct net_device *dev, req_t *req, const char* buff, size_t len)
++{
++      int i;
++
++      int nr_chunks = len/1024;
++      reply_t reply;
++      
++      reply.nr = req->nr;
++      reply.info = 0;
++
++        if ( nr_chunks <= 0)
++               nr_chunks = 1;
++      for (i = 0; i < nr_chunks; i++) {
++              unsigned int offset = i*1024;
++              reply.code = REPLY_MEM;
++              reply.info = offset;
++                dump_send_skb(dev, buff + offset, 1024, &reply);
++      }
++}
++static void dump_do_sysrq(int key)
++{
++        struct pt_regs regs;
++        
++      get_current_regs(&regs);
++      handle_sysrq(key, &regs, NULL, NULL);
++}
++
++/*
++ * This function waits for the client to acknowledge the receipt
++ * of the netdump startup reply, with the possibility of packets
++ * getting lost. We resend the startup packet if no ACK is received,
++ * after a 1 second delay.
++ *
++ * (The client can test the success of the handshake via the HELLO
++ * command, and send ACKs until we enter netdump mode.)
++ */
++static int
++dump_handshake(struct dump_dev *net_dev)
++{
++      char tmp[200];
++      reply_t reply;
++      int i, j;
++
++      if (startup_handshake) {
++              sprintf(tmp, "NETDUMP start, waiting for start-ACK.\n");
++              reply.code = REPLY_START_NETDUMP;
++              reply.nr = 0;
++              reply.info = 0;
++      } else {
++              sprintf(tmp, "NETDUMP start, waiting for start-ACK.\n");
++              reply.code = REPLY_START_WRITE_NETDUMP;
++              reply.nr = net_dev->curr_offset;
++              reply.info = net_dev->curr_offset;
++      }
++      
++      /* send 300 handshake packets before declaring failure */
++      for (i = 0; i < 300; i++) {
++              dump_send_skb(dump_ndev, tmp, strlen(tmp), &reply);
++
++              /* wait 1 sec */
++              for (j = 0; j < 10000; j++) {
++                      udelay(100);
++                      dump_ndev->poll_controller(dump_ndev);
++                      zap_completion_queue();
++                      if (new_req)
++                              break;
++              }
++
++              /* 
++               * if there is no new request, try sending the handshaking
++               * packet again
++               */
++              if (!new_req)
++                      continue;
++
++              /* 
++               * check if the new request is of the expected type,
++               * if so, return, else try sending the handshaking
++               * packet again
++               */
++              if (startup_handshake) {
++                      if (req.command == COMM_HELLO || req.command ==
++                              COMM_START_NETDUMP_ACK) {
++                              return 0;
++                      } else {
++                              new_req = 0;
++                              continue;
++                      }
++              } else {
++                      if (req.command == COMM_SEND_MEM) {
++                              return 0;
++                      } else {
++                              new_req = 0;
++                              continue;
++                      }
++              }
++      }
++      return -1;
++}
++
++static ssize_t
++do_netdump(struct dump_dev *net_dev, const char* buff, size_t len)
++{
++      reply_t reply;
++      char tmp[200];
++      ssize_t  ret = 0;
++      int repeatCounter, counter, total_loop;
++      
++      netdump_in_progress = 1;
++
++      if (dump_handshake(net_dev) < 0) {
++              printk("network dump failed due to handshake failure\n");
++              goto out;
++      }
++
++      /*
++       * Ideally startup handshake should be done during dump configuration,
++       * i.e., in dump_net_open(). This will be done when I figure out
++       * the dependency between startup handshake, subsequent write and
++       * various commands wrt to net-server.
++       */
++      if (startup_handshake)
++              startup_handshake = 0;
++
++        counter = 0;
++      repeatCounter = 0;
++      total_loop = 0;
++      while (1) {
++                if (!new_req) {
++                      dump_ndev->poll_controller(dump_ndev);
++                      zap_completion_queue();
++              }
++              if (!new_req) {
++                      repeatCounter++;
++
++                      if (repeatCounter > 5) {
++                              counter++;
++                              if (counter > 10000) {
++                                      if (total_loop >= 100000) {
++                                              printk("Time OUT LEAVE NOW\n");
++                                              goto out;
++                                      } else {
++                                              total_loop++;
++                                              printk("Try number %d out of "
++                                                      "10 before Time Out\n",
++                                                      total_loop);
++                                      }
++                              }
++                              mdelay(1);
++                              repeatCounter = 0;
++                      }       
++                      continue;
++              }
++              repeatCounter = 0;
++              counter = 0;
++              total_loop = 0;
++              new_req = 0;
++              switch (req.command) {
++              case COMM_NONE:
++                      break;
++
++              case COMM_SEND_MEM:
++                      dump_send_mem(dump_ndev, &req, buff, len);
++                      break;
++
++              case COMM_EXIT:
++                case COMM_START_WRITE_NETDUMP_ACK:
++                      ret = len;
++                      goto out;
++
++              case COMM_HELLO:
++                      sprintf(tmp, "Hello, this is netdump version "
++                                      "0.%02d\n", NETCONSOLE_VERSION);
++                      reply.code = REPLY_HELLO;
++                      reply.nr = req.nr;
++                        reply.info = net_dev->curr_offset;
++                      dump_send_skb(dump_ndev, tmp, strlen(tmp), &reply);
++                      break;
++
++              case COMM_GET_PAGE_SIZE:
++                      sprintf(tmp, "PAGE_SIZE: %ld\n", PAGE_SIZE);
++                      reply.code = REPLY_PAGE_SIZE;
++                      reply.nr = req.nr;
++                      reply.info = PAGE_SIZE;
++                      dump_send_skb(dump_ndev, tmp, strlen(tmp), &reply);
++                      break;
++
++              case COMM_GET_NR_PAGES:
++                      reply.code = REPLY_NR_PAGES;
++                      reply.nr = req.nr;
++                      reply.info = num_physpages;
++                        reply.info = page_counter;
++                      sprintf(tmp, "Number of pages: %ld\n", num_physpages);
++                      dump_send_skb(dump_ndev, tmp, strlen(tmp), &reply);
++                      break;
++
++              case COMM_GET_MAGIC:
++                      reply.code = REPLY_MAGIC;
++                      reply.nr = req.nr;
++                      reply.info = NETCONSOLE_VERSION;
++                      dump_send_skb(dump_ndev, (char *)&dump_magic,
++                                      sizeof(dump_magic), &reply);
++                      break;
++                case COMM_SYSRQ:
++                      dump_do_sysrq(req.from);
++                      reply.code = REPLY_SYSRQ;
++                      reply.nr = req.nr;
++                      reply.info = req.from;
++                      sprintf(tmp, "SYSRQ command %d \n", req.from);
++                      dump_send_skb(dump_ndev, tmp, strlen(tmp), &reply);
++                      break;
++              default:
++                      reply.code = REPLY_ERROR;
++                      reply.nr = req.nr;
++                      reply.info = req.command;
++                      sprintf(tmp, "Got unknown command code %d!\n",
++                                      req.command);
++                      dump_send_skb(dump_ndev, tmp, strlen(tmp), &reply);
++                      break;
++              }
++      }
++out:
++      netdump_in_progress = 0;
++      return ret;
++}
++
++static int
++dump_validate_config(void)
++{
++      source_ip = dump_in_dev->ifa_list->ifa_local;
++      if (!source_ip) {
++              printk("network device %s has no local address, "
++                              "aborting.\n", device_name);
++              return -1;
++      }
++
++#define IP(x) ((unsigned char *)&source_ip)[x]
++      printk("Source %d.%d.%d.%d", IP(0), IP(1), IP(2), IP(3));
++#undef IP
++
++      if (!source_port) {
++              printk("source_port parameter not specified, aborting.\n");
++              return -1;
++      }
++      printk(":%i\n", source_port);
++      source_port = htons(source_port);
++
++      if (!target_ip) {
++              printk("target_ip parameter not specified, aborting.\n");
++              return -1;
++      }
++
++#define IP(x) ((unsigned char *)&target_ip)[x]
++      printk("Target %d.%d.%d.%d", IP(0), IP(1), IP(2), IP(3));
++#undef IP
++
++      if (!target_port) {
++              printk("target_port parameter not specified, aborting.\n");
++              return -1;
++      }
++      printk(":%i\n", target_port);
++      target_port = htons(target_port);
++
++      printk("Target Ethernet Address %02x:%02x:%02x:%02x:%02x:%02x",
++              daddr[0], daddr[1], daddr[2], daddr[3], daddr[4], daddr[5]);
++
++      if ((daddr[0] & daddr[1] & daddr[2] & daddr[3] & daddr[4] & 
++                              daddr[5]) == 255)
++              printk("(Broadcast)");
++      printk("\n");
++      return 0;
++}
++
++/*
++ * Prepares the dump device so we can take a dump later. 
++ * Validates the netdump configuration parameters.
++ *
++ * TODO: Network connectivity check should be done here.
++ */
++static int
++dump_net_open(struct dump_dev *net_dev, unsigned long arg)
++{
++      int retval = 0;
++
++      /* get the interface name */
++      if (copy_from_user(device_name, (void *)arg, IFNAMSIZ))
++              return -EFAULT;
++
++      if (!(dump_ndev = dev_get_by_name(device_name))) {
++              printk("network device %s does not exist, aborting.\n",
++                              device_name);
++              return -ENODEV;
++      }
++
++      if (!dump_ndev->poll_controller) {
++              printk("network device %s does not implement polling yet, "
++                              "aborting.\n", device_name);
++              retval = -1; /* return proper error */
++              goto err1;
++      }
++
++      if (!(dump_in_dev = in_dev_get(dump_ndev))) {
++              printk("network device %s is not an IP protocol device, "
++                              "aborting.\n", device_name);
++              retval = -EINVAL;
++              goto err1;
++      }
++
++      if ((retval = dump_validate_config()) < 0)
++              goto err2;
++
++      net_dev->curr_offset = 0;
++      printk("Network device %s successfully configured for dumping\n",
++                      device_name);
++      return retval;
++err2:
++      in_dev_put(dump_in_dev);
++err1:
++      dev_put(dump_ndev);     
++      return retval;
++}
++
++/*
++ * Close the dump device and release associated resources
++ * Invoked when unconfiguring the dump device.
++ */
++static int
++dump_net_release(struct dump_dev *net_dev)
++{
++      if (dump_in_dev)
++              in_dev_put(dump_in_dev);
++      if (dump_ndev)
++              dev_put(dump_ndev);
++      return 0;
++}
++
++/*
++ * Prepare the dump device for use (silence any ongoing activity
++ * and quiesce state) when the system crashes.
++ */
++static int
++dump_net_silence(struct dump_dev *net_dev)
++{
++      local_irq_save(flags_global);
++      dump_ndev->rx_hook = dump_rx_hook;
++        startup_handshake = 1;
++      net_dev->curr_offset = 0;
++      printk("Dumping to network device %s on CPU %d ...\n", device_name,
++                      smp_processor_id());
++      return 0;
++}
++
++/*
++ * Invoked when dumping is done. This is the time to put things back 
++ * (i.e. undo the effects of dump_block_silence) so the device is 
++ * available for normal use.
++ */
++static int
++dump_net_resume(struct dump_dev *net_dev)
++{
++      int indx;
++      reply_t reply;
++      char tmp[200];
++
++        if (!dump_ndev)
++              return (0);
++
++      sprintf(tmp, "NETDUMP end.\n");
++      for( indx = 0; indx < 6; indx++) {
++              reply.code = REPLY_END_NETDUMP;
++              reply.nr = 0;
++              reply.info = 0;
++              dump_send_skb(dump_ndev, tmp, strlen(tmp), &reply);
++      }
++      printk("NETDUMP END!\n");
++      local_irq_restore(flags_global);
++      dump_ndev->rx_hook = NULL;
++      startup_handshake = 0;
++      return 0;
++}
++
++/*
++ * Seek to the specified offset in the dump device.
++ * Makes sure this is a valid offset, otherwise returns an error.
++ */
++static  int
++dump_net_seek(struct dump_dev *net_dev, loff_t off)
++{
++      /*
++       * For now using DUMP_HEADER_OFFSET as hard coded value,
++       * See dump_block_seekin dump_blockdev.c to know how to
++       * do this properly.
++       */
++      net_dev->curr_offset = off + DUMP_HEADER_OFFSET;
++      return 0;
++}
++
++/*
++ *
++ */
++static int
++dump_net_write(struct dump_dev *net_dev, void *buf, unsigned long len)
++{
++      int cnt, i, off;
++      ssize_t ret;
++
++      cnt = len/ PAGE_SIZE;
++
++      for (i = 0; i < cnt; i++) {
++              off = i* PAGE_SIZE;
++              ret = do_netdump(net_dev, buf+off, PAGE_SIZE);
++              if (ret <= 0)
++                      return -1;
++              net_dev->curr_offset = net_dev->curr_offset + PAGE_SIZE;
++      }
++      return len;
++}
++
++/*
++ * check if the last dump i/o is over and ready for next request
++ */
++static int
++dump_net_ready(struct dump_dev *net_dev, void *buf)
++{
++      return 0;
++}
++
++/*
++ * ioctl function used for configuring network dump
++ */
++static int
++dump_net_ioctl(struct dump_dev *net_dev, unsigned int cmd, unsigned long arg)
++{
++      switch (cmd) {
++      case DIOSTARGETIP:
++              target_ip = arg;
++              break;
++      case DIOSTARGETPORT:
++              target_port = (u16)arg;
++              break;
++      case DIOSSOURCEPORT:
++              source_port = (u16)arg;
++              break;
++      case DIOSETHADDR:
++              return copy_from_user(daddr, (void *)arg, 6);
++              break;
++      case DIOGTARGETIP:
++      case DIOGTARGETPORT:
++      case DIOGSOURCEPORT:
++      case DIOGETHADDR:
++              break;
++      default:
++              return -EINVAL;
++      }
++      return 0;
++}
++
++struct dump_dev_ops dump_netdev_ops = {
++      .open           = dump_net_open,
++      .release        = dump_net_release,
++      .silence        = dump_net_silence,
++      .resume         = dump_net_resume,
++      .seek           = dump_net_seek,
++      .write          = dump_net_write,
++      /* .read not implemented */
++      .ready          = dump_net_ready,
++      .ioctl          = dump_net_ioctl
++};
++
++static struct dump_dev default_dump_netdev = {
++      .type_name = "networkdev", 
++      .ops = &dump_netdev_ops, 
++      .curr_offset = 0
++};
++
++static int __init
++dump_netdev_init(void)
++{
++        default_dump_netdev.curr_offset = 0;
++
++      if (dump_register_device(&default_dump_netdev) < 0) {
++              printk("network dump device driver registration failed\n");
++              return -1;
++      }
++      printk("network device driver for LKCD registered\n");
++ 
++      get_random_bytes(&dump_magic, sizeof(dump_magic));
++      return 0;
++}
++
++static void __exit
++dump_netdev_cleanup(void)
++{
++      dump_unregister_device(&default_dump_netdev);
++}
++
++MODULE_AUTHOR("LKCD Development Team <lkcd-devel@lists.sourceforge.net>");
++MODULE_DESCRIPTION("Network Dump Driver for Linux Kernel Crash Dump (LKCD)");
++MODULE_LICENSE("GPL");
++
++module_init(dump_netdev_init);
++module_exit(dump_netdev_cleanup);
+Index: linux-2.6.0-test5/drivers/dump/dump_overlay.c
+===================================================================
+--- linux-2.6.0-test5.orig/drivers/dump/dump_overlay.c 2003-09-26 14:26:34.000000000 +0800
++++ linux-2.6.0-test5/drivers/dump/dump_overlay.c      2003-09-26 14:26:34.000000000 +0800
+@@ -0,0 +1,848 @@
++/*
++ * Two-stage soft-boot based dump scheme methods (memory overlay
++ * with post soft-boot writeout)
++ *
++ * Started: Oct 2002 -  Suparna Bhattacharya <suparna@in.ibm.com>
++ *
++ * This approach of saving the dump in memory and writing it 
++ * out after a softboot without clearing memory is derived from the 
++ * Mission Critical Linux dump implementation. Credits and a big
++ * thanks for letting the lkcd project make use of the excellent 
++ * piece of work and also for helping with clarifications and 
++ * tips along the way are due to:
++ *    Dave Winchell <winchell@mclx.com> (primary author of mcore)
++ *    and also to
++ *    Jeff Moyer <moyer@mclx.com>
++ *    Josh Huber <huber@mclx.com>
++ * 
++ * For those familiar with the mcore implementation, the key 
++ * differences/extensions here are in allowing entire memory to be 
++ * saved (in compressed form) through a careful ordering scheme 
++ * on both the way down as well on the way up after boot, the latter
++ * for supporting the LKCD notion of passes in which most critical 
++ * data is the first to be saved to the dump device. Also the post 
++ * boot writeout happens from within the kernel rather than driven 
++ * from userspace.
++ *
++ * The sequence is orchestrated through the abstraction of "dumpers",
++ * one for the first stage which then sets up the dumper for the next 
++ * stage, providing for a smooth and flexible reuse of the singlestage 
++ * dump scheme methods and a handle to pass dump device configuration 
++ * information across the soft boot. 
++ *
++ * Copyright (C) 2002 International Business Machines Corp. 
++ *
++ * This code is released under version 2 of the GNU GPL.
++ */
++
++/*
++ * Disruptive dumping using the second kernel soft-boot option
++ * for issuing dump i/o operates in 2 stages:
++ * 
++ * (1) - Saves the (compressed & formatted) dump in memory using a 
++ *       carefully ordered overlay scheme designed to capture the 
++ *       entire physical memory or selective portions depending on 
++ *       dump config settings, 
++ *     - Registers the stage 2 dumper and 
++ *     - Issues a soft reboot w/o clearing memory. 
++ *
++ *     The overlay scheme starts with a small bootstrap free area
++ *     and follows a reverse ordering of passes wherein it 
++ *     compresses and saves data starting with the least critical 
++ *     areas first, thus freeing up the corresponding pages to 
++ *     serve as destination for subsequent data to be saved, and
++ *     so on. With a good compression ratio, this makes it feasible
++ *     to capture an entire physical memory dump without significantly
++ *     reducing memory available during regular operation.
++ *
++ * (2) Post soft-reboot, runs through the saved memory dump and
++ *     writes it out to disk, this time around, taking care to
++ *     save the more critical data first (i.e. pages which figure 
++ *     in early passes for a regular dump). Finally issues a 
++ *     clean reboot.
++ *     
++ *     Since the data was saved in memory after selection/filtering
++ *     and formatted as per the chosen output dump format, at this 
++ *     stage the filter and format actions are just dummy (or
++ *     passthrough) actions, except for influence on ordering of
++ *     passes.
++ */
++
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/highmem.h>
++#include <linux/bootmem.h>
++#include <linux/dump.h>
++#include "dump_methods.h"
++
++extern struct list_head dumper_list_head;
++extern struct dump_memdev *dump_memdev;
++extern struct dumper dumper_stage2;
++struct dump_config_block *dump_saved_config = NULL;
++extern struct dump_blockdev *dump_blockdev;
++static struct dump_memdev *saved_dump_memdev = NULL;
++static struct dumper *saved_dumper = NULL;
++
++/* For testing 
++extern void dump_display_map(struct dump_memdev *);
++*/
++
++struct dumper *dumper_by_name(char *name)
++{
++#ifdef LATER
++      struct dumper *dumper;
++      list_for_each_entry(dumper, &dumper_list_head, dumper_list)
++              if (!strncmp(dumper->name, name, 32))
++                      return dumper;
++
++      /* not found */
++      return NULL; 
++#endif
++      /* Temporary proof of concept */
++      if (!strncmp(dumper_stage2.name, name, 32))
++              return &dumper_stage2;
++      else
++              return NULL;
++}
++
++#ifdef CONFIG_CRASH_DUMP_SOFTBOOT
++extern void dump_early_reserve_map(struct dump_memdev *);
++
++void crashdump_reserve(void)
++{
++      extern unsigned long crashdump_addr;
++
++      if (crashdump_addr == 0xdeadbeef) 
++              return;
++
++      /* reserve dump config and saved dump pages */
++      dump_saved_config = (struct dump_config_block *)crashdump_addr;
++      /* magic verification */
++      if (dump_saved_config->magic != DUMP_MAGIC_LIVE) {
++              printk("Invalid dump magic. Ignoring dump\n");
++              dump_saved_config = NULL;
++              return;
++      }
++                      
++      printk("Dump may be available from previous boot\n");
++
++      reserve_bootmem(virt_to_phys((void *)crashdump_addr), 
++              PAGE_ALIGN(sizeof(struct dump_config_block)));
++      dump_early_reserve_map(&dump_saved_config->memdev);
++
++}
++#endif
++
++/* 
++ * Loads the dump configuration from a memory block saved across soft-boot
++ * The ops vectors need fixing up as the corresp. routines may have 
++ * relocated in the new soft-booted kernel.
++ */
++int dump_load_config(struct dump_config_block *config)
++{
++      struct dumper *dumper;
++      struct dump_data_filter *filter_table, *filter;
++      struct dump_dev *dev;
++      int i;
++
++      if (config->magic != DUMP_MAGIC_LIVE)
++              return -ENOENT; /* not a valid config */
++
++      /* initialize generic config data */
++      memcpy(&dump_config, &config->config, sizeof(dump_config));
++
++      /* initialize dumper state */
++      if (!(dumper = dumper_by_name(config->dumper.name)))  {
++              printk("dumper name mismatch\n");
++              return -ENOENT; /* dumper mismatch */
++      }
++      
++      /* verify and fixup schema */
++      if (strncmp(dumper->scheme->name, config->scheme.name, 32)) {
++              printk("dumper scheme mismatch\n");
++              return -ENOENT; /* mismatch */
++      }
++      config->scheme.ops = dumper->scheme->ops;
++      config->dumper.scheme = &config->scheme;
++      
++      /* verify and fixup filter operations */
++      filter_table = dumper->filter;
++      for (i = 0, filter = config->filter_table; 
++              ((i < MAX_PASSES) && filter_table[i].selector); 
++              i++, filter++) {
++              if (strncmp(filter_table[i].name, filter->name, 32)) {
++                      printk("dump filter mismatch\n");
++                      return -ENOENT; /* filter name mismatch */
++              }
++              filter->selector = filter_table[i].selector;
++      }
++      config->dumper.filter = config->filter_table;
++
++      /* fixup format */
++      if (strncmp(dumper->fmt->name, config->fmt.name, 32)) {
++              printk("dump format mismatch\n");
++              return -ENOENT; /* mismatch */
++      }
++      config->fmt.ops = dumper->fmt->ops;
++      config->dumper.fmt = &config->fmt;
++
++      /* fixup target device */
++      dev = (struct dump_dev *)(&config->dev[0]);
++      if (dumper->dev == NULL) {
++              pr_debug("Vanilla dumper - assume default\n");
++              if (dump_dev == NULL)
++                      return -ENODEV;
++              dumper->dev = dump_dev;
++      }
++
++      if (strncmp(dumper->dev->type_name, dev->type_name, 32)) { 
++              printk("dump dev type mismatch %s instead of %s\n",
++                              dev->type_name, dumper->dev->type_name);
++              return -ENOENT; /* mismatch */
++      }
++      dev->ops = dumper->dev->ops; 
++      config->dumper.dev = dev;
++      
++      /* fixup memory device containing saved dump pages */
++      /* assume statically init'ed dump_memdev */
++      config->memdev.ddev.ops = dump_memdev->ddev.ops; 
++      /* switch to memdev from prev boot */
++      saved_dump_memdev = dump_memdev; /* remember current */
++      dump_memdev = &config->memdev;
++
++      /* Make this the current primary dumper */
++      dump_config.dumper = &config->dumper;
++
++      return 0;
++}
++
++/* Saves the dump configuration in a memory block for use across a soft-boot */
++int dump_save_config(struct dump_config_block *config)
++{
++      printk("saving dump config settings\n");
++
++      /* dump config settings */
++      memcpy(&config->config, &dump_config, sizeof(dump_config));
++
++      /* dumper state */
++      memcpy(&config->dumper, dump_config.dumper, sizeof(struct dumper));
++      memcpy(&config->scheme, dump_config.dumper->scheme, 
++              sizeof(struct dump_scheme));
++      memcpy(&config->fmt, dump_config.dumper->fmt, sizeof(struct dump_fmt));
++      memcpy(&config->dev[0], dump_config.dumper->dev, 
++              sizeof(struct dump_anydev));
++      memcpy(&config->filter_table, dump_config.dumper->filter, 
++              sizeof(struct dump_data_filter)*MAX_PASSES);
++
++      /* handle to saved mem pages */
++      memcpy(&config->memdev, dump_memdev, sizeof(struct dump_memdev));
++
++      config->magic = DUMP_MAGIC_LIVE;
++      
++      return 0;
++}
++
++int dump_init_stage2(struct dump_config_block *saved_config)
++{
++      int err = 0;
++
++      pr_debug("dump_init_stage2\n");
++      /* Check if dump from previous boot exists */
++      if (saved_config) {
++              printk("loading dumper from previous boot \n");
++              /* load and configure dumper from previous boot */
++              if ((err = dump_load_config(saved_config)))
++                      return err;
++
++              if (!dump_oncpu) {
++                      if ((err = dump_configure(dump_config.dump_device))) {
++                              printk("Stage 2 dump configure failed\n");
++                              return err;
++                      }
++              }
++
++              dumper_reset();
++              dump_dev = dump_config.dumper->dev;
++              /* write out the dump */
++              err = dump_generic_execute(NULL, NULL);
++              
++              dump_saved_config = NULL;
++
++              if (!dump_oncpu) {
++                      dump_unconfigure(); 
++              }
++              
++              return err;
++
++      } else {
++              /* no dump to write out */
++              printk("no dumper from previous boot \n");
++              return 0;
++      }
++}
++
++extern void dump_mem_markpages(struct dump_memdev *);
++
++int dump_switchover_stage(void)
++{
++      int ret = 0;
++
++      /* trigger stage 2 rightaway - in real life would be after soft-boot */
++      /* dump_saved_config would be a boot param */
++      saved_dump_memdev = dump_memdev;
++      saved_dumper = dump_config.dumper;
++      ret = dump_init_stage2(dump_saved_config);
++      dump_memdev = saved_dump_memdev;
++      dump_config.dumper = saved_dumper;
++      return ret;
++}
++
++int dump_activate_softboot(void) 
++{
++      int err = 0;
++
++      /* temporary - switchover to writeout previously saved dump */
++      err = dump_switchover_stage(); /* non-disruptive case */
++      if (dump_oncpu) 
++              dump_config.dumper = &dumper_stage1; /* set things back */
++
++      return err;
++
++      dump_silence_level = DUMP_HALT_CPUS;
++      /* wait till we become the only cpu */
++      /* maybe by checking for online cpus ? */
++
++      /* now call into kexec */
++
++      /* TBD/Fixme: 
++       * should we call reboot notifiers ? inappropriate for panic ?  
++       * what about device_shutdown() ? 
++       * is explicit bus master disabling needed or can we do that
++       * through driverfs ? 
++       */
++      return 0;
++}
++
++/* --- DUMP SCHEME ROUTINES  --- */
++
++static inline int dump_buf_pending(struct dumper *dumper)
++{
++      return (dumper->curr_buf - dumper->dump_buf);
++}
++
++/* Invoked during stage 1 of soft-reboot based dumping */
++int dump_overlay_sequencer(void)
++{
++      struct dump_data_filter *filter = dump_config.dumper->filter;
++      struct dump_data_filter *filter2 = dumper_stage2.filter;
++      int pass = 0, err = 0, save = 0;
++      int (*action)(unsigned long, unsigned long);
++
++      /* Make sure gzip compression is being used */
++      if (dump_config.dumper->compress->compress_type != DUMP_COMPRESS_GZIP) {
++              printk(" Please set GZIP compression \n");
++              return -EINVAL;
++      }
++
++      /* start filling in dump data right after the header */
++      dump_config.dumper->curr_offset = 
++              PAGE_ALIGN(dump_config.dumper->header_len);
++
++      /* Locate the last pass */
++      for (;filter->selector; filter++, pass++);
++      
++      /* 
++       * Start from the end backwards: overlay involves a reverse 
++       * ordering of passes, since less critical pages are more
++       * likely to be reusable as scratch space once we are through
++       * with them. 
++       */
++      for (--pass, --filter; pass >= 0; pass--, filter--)
++      {
++              /* Assumes passes are exclusive (even across dumpers) */
++              /* Requires care when coding the selection functions */
++              if ((save = filter->level_mask & dump_config.level))
++                      action = dump_save_data;
++              else
++                      action = dump_skip_data;
++
++              /* Remember the offset where this pass started */
++              /* The second stage dumper would use this */
++              if (dump_buf_pending(dump_config.dumper) & (PAGE_SIZE - 1)) {
++                      pr_debug("Starting pass %d with pending data\n", pass);
++                      pr_debug("filling dummy data to page-align it\n");
++                      dump_config.dumper->curr_buf = (void *)PAGE_ALIGN(
++                              (unsigned long)dump_config.dumper->curr_buf);
++              }
++              
++              filter2[pass].start = dump_config.dumper->curr_offset
++                      + dump_buf_pending(dump_config.dumper);
++
++              err = dump_iterator(pass, action, filter);
++
++              filter2[pass].end = dump_config.dumper->curr_offset
++                      + dump_buf_pending(dump_config.dumper);
++
++              if (err < 0) {
++                      printk("dump_overlay_seq: failure %d in pass %d\n", 
++                              err, pass);
++                      break;
++              }       
++              printk("\n %d overlay pages %s of %d each in pass %d\n", 
++              err, save ? "saved" : "skipped", DUMP_PAGE_SIZE, pass);
++      }
++
++      return err;
++}
++
++/* from dump_memdev.c */
++extern struct page *dump_mem_lookup(struct dump_memdev *dev, unsigned long loc);
++extern struct page *dump_mem_next_page(struct dump_memdev *dev);
++
++static inline struct page *dump_get_saved_page(loff_t loc)
++{
++      return (dump_mem_lookup(dump_memdev, loc >> PAGE_SHIFT));
++}
++
++static inline struct page *dump_next_saved_page(void)
++{
++      return (dump_mem_next_page(dump_memdev));
++}
++
++/* 
++ * Iterates over list of saved dump pages. Invoked during second stage of 
++ * soft boot dumping
++ *
++ * Observation: If additional selection is desired at this stage then
++ * a different iterator could be written which would advance 
++ * to the next page header everytime instead of blindly picking up
++ * the data. In such a case loc would be interpreted differently. 
++ * At this moment however a blind pass seems sufficient, cleaner and
++ * faster.
++ */
++int dump_saved_data_iterator(int pass, int (*action)(unsigned long, 
++      unsigned long), struct dump_data_filter *filter)
++{
++      loff_t loc = filter->start;
++      struct page *page;
++      unsigned long count = 0;
++      int err = 0;
++      unsigned long sz;
++
++      printk("pass %d, start off 0x%llx end offset 0x%llx\n", pass,
++                      filter->start, filter->end);
++
++      /* loc will get treated as logical offset into stage 1 */
++      page = dump_get_saved_page(loc);
++                      
++      for (; loc < filter->end; loc += PAGE_SIZE) {
++              dump_config.dumper->curr_loc = loc;
++              if (!page) {
++                      printk("no more saved data for pass %d\n", pass);
++                      break;
++              }
++              sz = (loc + PAGE_SIZE > filter->end) ? filter->end - loc :
++                      PAGE_SIZE;
++
++              if (page && filter->selector(pass, (unsigned long)page, 
++                      PAGE_SIZE))  {
++                      pr_debug("mem offset 0x%llx\n", loc);
++                      if ((err = action((unsigned long)page, sz))) 
++                              break;
++                      else
++                              count++;
++                      /* clear the contents of page */
++                      /* fixme: consider using KM_DUMP instead */
++                      clear_highpage(page);
++                      
++              }
++              page = dump_next_saved_page();
++      }
++
++      return err ? err : count;
++}
++
++static inline int dump_overlay_pages_done(struct page *page, int nr)
++{
++      int ret=0;
++
++      for (; nr ; page++, nr--) {
++              if (dump_check_and_free_page(dump_memdev, page))
++                      ret++;
++      }
++      return ret;
++}
++
++int dump_overlay_save_data(unsigned long loc, unsigned long len)
++{
++      int err = 0;
++      struct page *page = (struct page *)loc;
++      static unsigned long cnt = 0;
++
++      if ((err = dump_generic_save_data(loc, len)))
++              return err;
++
++      if (dump_overlay_pages_done(page, len >> PAGE_SHIFT)) {
++              cnt++;
++              if (!(cnt & 0x7f))
++                      pr_debug("released page 0x%lx\n", page_to_pfn(page));
++      }
++      
++      return err;
++}
++
++
++int dump_overlay_skip_data(unsigned long loc, unsigned long len)
++{
++      struct page *page = (struct page *)loc;
++
++      dump_overlay_pages_done(page, len >> PAGE_SHIFT);
++      return 0;
++}
++
++int dump_overlay_resume(void)
++{
++      int err = 0;
++
++      /* 
++       * switch to stage 2 dumper, save dump_config_block
++       * and then trigger a soft-boot
++       */
++      dumper_stage2.header_len = dump_config.dumper->header_len;
++      dump_config.dumper = &dumper_stage2;
++      if ((err = dump_save_config(dump_saved_config)))
++              return err;
++
++      dump_dev = dump_config.dumper->dev;
++
++      return err;
++      err = dump_switchover_stage();  /* plugs into soft boot mechanism */
++      dump_config.dumper = &dumper_stage1; /* set things back */
++      return err;
++}
++
++int dump_overlay_configure(unsigned long devid)
++{
++      struct dump_dev *dev;
++      struct dump_config_block *saved_config = dump_saved_config;
++      int err = 0;
++
++      /* If there is a previously saved dump, write it out first */
++      if (saved_config) {
++              printk("Processing old dump pending writeout\n");
++              err = dump_switchover_stage();
++              if (err) {
++                      printk("failed to writeout saved dump\n");
++                      return err;
++              }
++              dump_free_mem(saved_config); /* testing only: not after boot */
++      }
++
++      dev = dumper_stage2.dev = dump_config.dumper->dev;
++      /* From here on the intermediate dump target is memory-only */
++      dump_dev = dump_config.dumper->dev = &dump_memdev->ddev;
++      if ((err = dump_generic_configure(0))) {
++              printk("dump generic configure failed: err %d\n", err);
++              return err;
++      }
++      /* temporary */
++      dumper_stage2.dump_buf = dump_config.dumper->dump_buf;
++
++      /* Sanity check on the actual target dump device */
++      if (!dev || (err = dev->ops->open(dev, devid))) {
++              return err;
++      }
++      /* TBD: should we release the target if this is soft-boot only ? */
++
++      /* alloc a dump config block area to save across reboot */
++      if (!(dump_saved_config = dump_alloc_mem(sizeof(struct 
++              dump_config_block)))) {
++              printk("dump config block alloc failed\n");
++              /* undo configure */
++              dump_generic_unconfigure();
++              return -ENOMEM;
++      }
++      dump_config.dump_addr = (unsigned long)dump_saved_config;
++      printk("Dump config block of size %d set up at 0x%lx\n", 
++              sizeof(*dump_saved_config), (unsigned long)dump_saved_config);
++      return 0;
++}
++
++int dump_overlay_unconfigure(void)
++{
++      struct dump_dev *dev = dumper_stage2.dev;
++      int err = 0;
++
++      pr_debug("dump_overlay_unconfigure\n");
++      /* Close the secondary device */
++      dev->ops->release(dev); 
++      pr_debug("released secondary device\n");
++
++      err = dump_generic_unconfigure();
++      pr_debug("Unconfigured generic portions\n");
++      dump_free_mem(dump_saved_config);
++      dump_saved_config = NULL;
++      pr_debug("Freed saved config block\n");
++      dump_dev = dump_config.dumper->dev = dumper_stage2.dev;
++
++      printk("Unconfigured overlay dumper\n");
++      return err;
++}
++
++int dump_staged_unconfigure(void)
++{
++      int err = 0;
++      struct dump_config_block *saved_config = dump_saved_config;
++      struct dump_dev *dev;
++
++      pr_debug("dump_staged_unconfigure\n");
++      err = dump_generic_unconfigure();
++
++      /* now check if there is a saved dump waiting to be written out */
++      if (saved_config) {
++              printk("Processing saved dump pending writeout\n");
++              if ((err = dump_switchover_stage())) {
++                      printk("Error in commiting saved dump at 0x%lx\n", 
++                              (unsigned long)saved_config);
++                      printk("Old dump may hog memory\n");
++              } else {
++                      dump_free_mem(saved_config);
++                      pr_debug("Freed saved config block\n");
++              }
++              dump_saved_config = NULL;
++      } else {
++              dev = &dump_memdev->ddev;
++              dev->ops->release(dev);
++      }
++      printk("Unconfigured second stage dumper\n");
++
++      return 0;
++}
++
++/* ----- PASSTHRU FILTER ROUTINE --------- */
++
++/* transparent - passes everything through */
++int dump_passthru_filter(int pass, unsigned long loc, unsigned long sz)
++{
++      return 1;
++}
++
++/* ----- PASSTRU FORMAT ROUTINES ---- */
++
++
++int dump_passthru_configure_header(const char *panic_str, const struct pt_regs *regs)
++{
++      dump_config.dumper->header_dirty++;
++      return 0;
++}
++
++/* Copies bytes of data from page(s) to the specified buffer */
++int dump_copy_pages(void *buf, struct page *page, unsigned long sz)
++{
++      unsigned long len = 0, bytes;
++      void *addr;
++
++      while (len < sz) {
++              addr = kmap_atomic(page, KM_DUMP);
++              bytes = (sz > len + PAGE_SIZE) ? PAGE_SIZE : sz - len;  
++              memcpy(buf, addr, bytes); 
++              kunmap_atomic(addr, KM_DUMP);
++              buf += bytes;
++              len += bytes;
++              page++;
++      }
++      /* memset(dump_config.dumper->curr_buf, 0x57, len); temporary */
++
++      return sz - len;
++}
++
++int dump_passthru_update_header(void)
++{
++      long len = dump_config.dumper->header_len;
++      struct page *page;
++      void *buf = dump_config.dumper->dump_buf;
++      int err = 0;
++
++      if (!dump_config.dumper->header_dirty)
++              return 0;
++
++      pr_debug("Copying header of size %ld bytes from memory\n", len);
++      if (len > DUMP_BUFFER_SIZE) 
++              return -E2BIG;
++
++      page = dump_mem_lookup(dump_memdev, 0);
++      for (; (len > 0) && page; buf += PAGE_SIZE, len -= PAGE_SIZE) {
++              if ((err = dump_copy_pages(buf, page, PAGE_SIZE)))
++                      return err;
++              page = dump_mem_next_page(dump_memdev);
++      }
++      if (len > 0) {
++              printk("Incomplete header saved in mem\n");
++              return -ENOENT;
++      }
++
++      if ((err = dump_dev_seek(0))) {
++              printk("Unable to seek to dump header offset\n");
++              return err;
++      }
++      err = dump_ll_write(dump_config.dumper->dump_buf, 
++              buf - dump_config.dumper->dump_buf);
++      if (err < dump_config.dumper->header_len)
++              return (err < 0) ? err : -ENOSPC;
++
++      dump_config.dumper->header_dirty = 0;
++      return 0;
++}
++
++static loff_t next_dph_offset = 0;
++
++static int dph_valid(struct __dump_page *dph)
++{
++      if ((dph->dp_address & (PAGE_SIZE - 1)) || (dph->dp_flags 
++            > DUMP_DH_COMPRESSED) || (!dph->dp_flags) ||
++              (dph->dp_size > PAGE_SIZE)) {
++      printk("dp->address = 0x%llx, dp->size = 0x%x, dp->flag = 0x%x\n",
++              dph->dp_address, dph->dp_size, dph->dp_flags);
++              return 0;
++      }
++      return 1;
++}
++
++int dump_verify_lcrash_data(void *buf, unsigned long sz)
++{
++      struct __dump_page *dph;
++
++      /* sanity check for page headers */
++      while (next_dph_offset + sizeof(*dph) < sz) {
++              dph = (struct __dump_page *)(buf + next_dph_offset);
++              if (!dph_valid(dph)) {
++                      printk("Invalid page hdr at offset 0x%llx\n",
++                              next_dph_offset);
++                      return -EINVAL;
++              }
++              next_dph_offset += dph->dp_size + sizeof(*dph);
++      }
++
++      next_dph_offset -= sz;  
++      return 0;
++}
++
++/* 
++ * TBD/Later: Consider avoiding the copy by using a scatter/gather 
++ * vector representation for the dump buffer
++ */
++int dump_passthru_add_data(unsigned long loc, unsigned long sz)
++{
++      struct page *page = (struct page *)loc;
++      void *buf = dump_config.dumper->curr_buf;
++      int err = 0;
++
++      if ((err = dump_copy_pages(buf, page, sz))) {
++              printk("dump_copy_pages failed");
++              return err;
++      }
++
++      if ((err = dump_verify_lcrash_data(buf, sz))) {
++              printk("dump_verify_lcrash_data failed\n");
++              printk("Invalid data for pfn 0x%lx\n", page_to_pfn(page));
++              printk("Page flags 0x%lx\n", page->flags);
++              printk("Page count 0x%x\n", atomic_read(&page->count));
++              return err;
++      }
++
++      dump_config.dumper->curr_buf = buf + sz;
++
++      return 0;
++}
++
++
++/* Stage 1 dumper: Saves compressed dump in memory and soft-boots system */
++
++/* Scheme to overlay saved data in memory for writeout after a soft-boot */
++struct dump_scheme_ops dump_scheme_overlay_ops = {
++      .configure      = dump_overlay_configure,
++      .unconfigure    = dump_overlay_unconfigure,
++      .sequencer      = dump_overlay_sequencer,
++      .iterator       = dump_page_iterator,
++      .save_data      = dump_overlay_save_data,
++      .skip_data      = dump_overlay_skip_data,
++      .write_buffer   = dump_generic_write_buffer
++};
++
++struct dump_scheme dump_scheme_overlay = {
++      .name           = "overlay",
++      .ops            = &dump_scheme_overlay_ops
++};
++
++
++/* Stage 1 must use a good compression scheme - default to gzip */
++extern struct __dump_compress dump_gzip_compression;
++
++struct dumper dumper_stage1 = {
++      .name           = "stage1",
++      .scheme         = &dump_scheme_overlay,
++      .fmt            = &dump_fmt_lcrash,
++      .compress       = &dump_none_compression, /* needs to be gzip */
++      .filter         = dump_filter_table,
++      .dev            = NULL,
++};            
++
++/* Stage 2 dumper: Activated after softboot to write out saved dump to device */
++
++/* Formatter that transfers data as is (transparent) w/o further conversion */
++struct dump_fmt_ops dump_fmt_passthru_ops = {
++      .configure_header       = dump_passthru_configure_header,
++      .update_header          = dump_passthru_update_header,
++      .save_context           = NULL, /* unused */
++      .add_data               = dump_passthru_add_data,
++      .update_end_marker      = dump_lcrash_update_end_marker
++};
++
++struct dump_fmt dump_fmt_passthru = {
++      .name   = "passthru",
++      .ops    = &dump_fmt_passthru_ops
++};
++
++/* Filter that simply passes along any data within the range (transparent)*/
++/* Note: The start and end ranges in the table are filled in at run-time */
++
++extern int dump_filter_none(int pass, unsigned long loc, unsigned long sz);
++
++struct dump_data_filter dump_passthru_filtertable[MAX_PASSES] = {
++{.name = "passkern", .selector = dump_passthru_filter, 
++      .level_mask = DUMP_MASK_KERN },
++{.name = "passuser", .selector = dump_passthru_filter, 
++      .level_mask = DUMP_MASK_USED },
++{.name = "passunused", .selector = dump_passthru_filter, 
++      .level_mask = DUMP_MASK_UNUSED },
++{.name = "none", .selector = dump_filter_none, 
++      .level_mask = DUMP_MASK_REST }
++};
++
++
++/* Scheme to handle data staged / preserved across a soft-boot */
++struct dump_scheme_ops dump_scheme_staged_ops = {
++      .configure      = dump_generic_configure,
++      .unconfigure    = dump_staged_unconfigure,
++      .sequencer      = dump_generic_sequencer,
++      .iterator       = dump_saved_data_iterator,
++      .save_data      = dump_generic_save_data,
++      .skip_data      = dump_generic_skip_data,
++      .write_buffer   = dump_generic_write_buffer
++};
++
++struct dump_scheme dump_scheme_staged = {
++      .name           = "staged",
++      .ops            = &dump_scheme_staged_ops
++};
++
++/* The stage 2 dumper comprising all these */
++struct dumper dumper_stage2 = {
++      .name           = "stage2",
++      .scheme         = &dump_scheme_staged,
++      .fmt            = &dump_fmt_passthru,
++      .compress       = &dump_none_compression,
++      .filter         = dump_passthru_filtertable,
++      .dev            = NULL,
++};            
++
+Index: linux-2.6.0-test5/drivers/dump/dump_rle.c
+===================================================================
+--- linux-2.6.0-test5.orig/drivers/dump/dump_rle.c     2003-09-26 14:26:34.000000000 +0800
++++ linux-2.6.0-test5/drivers/dump/dump_rle.c  2003-09-26 14:26:34.000000000 +0800
+@@ -0,0 +1,175 @@
++/*
++ * RLE Compression functions for kernel crash dumps.
++ *
++ * Created by: Matt Robinson (yakker@sourceforge.net)
++ * Copyright 2001 Matt D. Robinson.  All rights reserved.
++ *
++ * This code is released under version 2 of the GNU GPL.
++ */
++
++/* header files */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/sched.h>
++#include <linux/fs.h>
++#include <linux/file.h>
++#include <linux/init.h>
++#include <linux/dump.h>
++
++/*
++ * Name: dump_compress_rle()
++ * Func: Compress a DUMP_PAGE_SIZE (hardware) page down to something more
++ *       reasonable, if possible.  This is the same routine we use in IRIX.
++ */
++static u16
++dump_compress_rle(const u8 *old, u16 oldsize, u8 *new, u16 newsize)
++{
++      u16 ri, wi, count = 0;
++      u_char value = 0, cur_byte;
++
++      /*
++       * If the block should happen to "compress" to larger than the
++       * buffer size, allocate a larger one and change cur_buf_size.
++       */
++
++      wi = ri = 0;
++
++      while (ri < oldsize) {
++              if (!ri) {
++                      cur_byte = value = old[ri];
++                      count = 0;
++              } else {
++                      if (count == 255) {
++                              if (wi + 3 > oldsize) {
++                                      return oldsize;
++                              }
++                              new[wi++] = 0;
++                              new[wi++] = count;
++                              new[wi++] = value;
++                              value = cur_byte = old[ri];
++                              count = 0;
++                      } else { 
++                              if ((cur_byte = old[ri]) == value) {
++                                      count++;
++                              } else {
++                                      if (count > 1) {
++                                              if (wi + 3 > oldsize) {
++                                                      return oldsize;
++                                              }
++                                              new[wi++] = 0;
++                                              new[wi++] = count;
++                                              new[wi++] = value;
++                                      } else if (count == 1) {
++                                              if (value == 0) {
++                                                      if (wi + 3 > oldsize) {
++                                                              return oldsize;
++                                                      }
++                                                      new[wi++] = 0;
++                                                      new[wi++] = 1;
++                                                      new[wi++] = 0;
++                                              } else {
++                                                      if (wi + 2 > oldsize) {
++                                                              return oldsize;
++                                                      }
++                                                      new[wi++] = value;
++                                                      new[wi++] = value;
++                                              }
++                                      } else { /* count == 0 */
++                                              if (value == 0) {
++                                                      if (wi + 2 > oldsize) {
++                                                              return oldsize;
++                                                      }
++                                                      new[wi++] = value;
++                                                      new[wi++] = value;
++                                              } else {
++                                                      if (wi + 1 > oldsize) {
++                                                              return oldsize;
++                                                      }
++                                                      new[wi++] = value;
++                                              }
++                                      } /* if count > 1 */
++
++                                      value = cur_byte;
++                                      count = 0;
++
++                              } /* if byte == value */
++
++                      } /* if count == 255 */
++
++              } /* if ri == 0 */
++              ri++;
++
++      }
++      if (count > 1) {
++              if (wi + 3 > oldsize) {
++                      return oldsize;
++              }
++              new[wi++] = 0;
++              new[wi++] = count;
++              new[wi++] = value;
++      } else if (count == 1) {
++              if (value == 0) {
++                      if (wi + 3 > oldsize)
++                              return oldsize;
++                      new[wi++] = 0;
++                      new[wi++] = 1;
++                      new[wi++] = 0;
++              } else {
++                      if (wi + 2 > oldsize)
++                              return oldsize;
++                      new[wi++] = value;
++                      new[wi++] = value;
++              }
++      } else { /* count == 0 */
++              if (value == 0) {
++                      if (wi + 2 > oldsize)
++                              return oldsize;
++                      new[wi++] = value;
++                      new[wi++] = value;
++              } else {
++                      if (wi + 1 > oldsize)
++                              return oldsize;
++                      new[wi++] = value;
++              }
++      } /* if count > 1 */
++
++      value = cur_byte;
++      count = 0;
++      return wi;
++}
++
++/* setup the rle compression functionality */
++static struct __dump_compress dump_rle_compression = {
++      .compress_type = DUMP_COMPRESS_RLE,
++      .compress_func = dump_compress_rle,
++      .compress_name = "RLE",
++};
++
++/*
++ * Name: dump_compress_rle_init()
++ * Func: Initialize rle compression for dumping.
++ */
++static int __init
++dump_compress_rle_init(void)
++{
++      dump_register_compression(&dump_rle_compression);
++      return 0;
++}
++
++/*
++ * Name: dump_compress_rle_cleanup()
++ * Func: Remove rle compression for dumping.
++ */
++static void __exit
++dump_compress_rle_cleanup(void)
++{
++      dump_unregister_compression(DUMP_COMPRESS_RLE);
++}
++
++/* module initialization */
++module_init(dump_compress_rle_init);
++module_exit(dump_compress_rle_cleanup);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("LKCD Development Team <lkcd-devel@lists.sourceforge.net>");
++MODULE_DESCRIPTION("RLE compression module for crash dump driver");
+Index: linux-2.6.0-test5/drivers/dump/dump_scheme.c
+===================================================================
+--- linux-2.6.0-test5.orig/drivers/dump/dump_scheme.c  2003-09-26 14:26:34.000000000 +0800
++++ linux-2.6.0-test5/drivers/dump/dump_scheme.c       2003-09-26 14:26:34.000000000 +0800
+@@ -0,0 +1,357 @@
++/* 
++ * Default single stage dump scheme methods
++ *
++ * Previously a part of dump_base.c
++ *
++ * Started: Oct 2002 -  Suparna Bhattacharya <suparna@in.ibm.com>
++ *    Split and rewrote LKCD dump scheme to generic dump method 
++ *    interfaces 
++ * Derived from original code created by
++ *    Matt Robinson <yakker@sourceforge.net>)
++ *
++ * Contributions from SGI, IBM, HP, MCL, and others.
++ *
++ * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
++ * Copyright (C) 2001 - 2002 Matt D. Robinson.  All rights reserved.
++ * Copyright (C) 2002 International Business Machines Corp. 
++ *
++ * This code is released under version 2 of the GNU GPL.
++ */
++
++/*
++ * Implements the default dump scheme, i.e. single-stage gathering and 
++ * saving of dump data directly to the target device, which operates in
++ * a push mode, where the dumping system decides what data it saves
++ * taking into account pre-specified dump config options.
++ *
++ * Aside: The 2-stage dump scheme, where there is a soft-reset between
++ * the gathering and saving phases, also reuses some of these
++ * default routines (see dump_overlay.c) 
++ */ 
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <linux/reboot.h>
++#include <linux/nmi.h>
++#include <linux/dump.h>
++#include "dump_methods.h"
++
++extern int panic_timeout;  /* time before reboot */
++
++extern void dump_speedo(int);
++
++/* Default sequencer used during single stage dumping */
++/* Also invoked during stage 2 of soft-boot based dumping */
++int dump_generic_sequencer(void)
++{
++      struct dump_data_filter *filter = dump_config.dumper->filter;
++      int pass = 0, err = 0, save = 0;
++      int (*action)(unsigned long, unsigned long);
++
++      /* 
++       * We want to save the more critical data areas first in 
++       * case we run out of space, encounter i/o failures, or get
++       * interrupted otherwise and have to give up midway
++       * So, run through the passes in increasing order 
++       */
++      for (;filter->selector; filter++, pass++)
++      {
++              /* Assumes passes are exclusive (even across dumpers) */
++              /* Requires care when coding the selection functions */
++              if ((save = filter->level_mask & dump_config.level))
++                      action = dump_save_data;
++              else
++                      action = dump_skip_data;
++
++              if ((err = dump_iterator(pass, action, filter)) < 0)
++                      break;
++
++              printk("\n %d dump pages %s of %d each in pass %d\n", 
++              err, save ? "saved" : "skipped", DUMP_PAGE_SIZE, pass);
++
++      }
++
++      return (err < 0) ? err : 0;
++}
++
++static inline struct page *dump_get_page(loff_t loc)
++{
++      unsigned long page_index = loc >> PAGE_SHIFT;
++
++      /* todo: complete this  to account for ia64/discontig mem */
++      /* todo: and to check for validity, ram page, no i/o mem etc */
++      /* need to use pfn/physaddr equiv of kern_addr_valid */
++      if (__dump_page_valid(page_index))
++              return pfn_to_page(page_index);
++      else
++              return NULL;
++
++}
++
++/* Default iterator: for singlestage and stage 1 of soft-boot dumping */
++/* Iterates over range of physical memory pages in DUMP_PAGE_SIZE increments */
++int dump_page_iterator(int pass, int (*action)(unsigned long, unsigned long), 
++      struct dump_data_filter *filter)
++{
++      /* Todo : fix unit, type */
++      loff_t loc;
++      int count = 0, err = 0;
++      struct page *page;
++
++      /* Todo: Add membanks code */
++      /* TBD: Check if we need to address DUMP_PAGE_SIZE < PAGE_SIZE */       
++      
++      for (loc = filter->start; loc < filter->end; loc += DUMP_PAGE_SIZE) {
++              dump_config.dumper->curr_loc = loc;
++              page = dump_get_page(loc);
++              if (page && filter->selector(pass, (unsigned long) page, 
++              DUMP_PAGE_SIZE)) {
++                      if ((err = action((unsigned long)page, DUMP_PAGE_SIZE)))
++                      {
++                              printk("dump_page_iterator: err %d for loc "
++                              "0x%llx, in pass %d\n", err, loc, pass);
++                              break;
++                      } else
++                              count++;
++              }
++      }
++
++      return err ? err : count;
++}
++
++/* 
++ * Base function that saves the selected block of data in the dump 
++ * Action taken when iterator decides that data needs to be saved 
++ */
++int dump_generic_save_data(unsigned long loc, unsigned long sz)
++{
++      void *buf;
++      void *dump_buf = dump_config.dumper->dump_buf;
++      int left, bytes, ret;
++
++      if ((ret = dump_add_data(loc, sz))) {
++              return ret;
++      }
++      buf = dump_config.dumper->curr_buf;
++
++      /* If we've filled up the buffer write it out */
++      if ((left = buf - dump_buf) >= DUMP_BUFFER_SIZE) {
++              bytes = dump_write_buffer(dump_buf, DUMP_BUFFER_SIZE);
++              if (bytes < DUMP_BUFFER_SIZE) {
++                      printk("dump_write_buffer failed %d\n", bytes);
++                      return bytes ? -ENOSPC : bytes;
++              }
++
++              left -= bytes;
++              
++              /* -- A few chores to do from time to time -- */
++              dump_config.dumper->count++;
++
++              if (!(dump_config.dumper->count & 0x3f)) {
++                      /* Update the header every one in a while */
++                      memset((void *)dump_buf, 'b', DUMP_BUFFER_SIZE);
++                      if ((ret = dump_update_header()) < 0) {
++                              /* issue warning */
++                              return ret;
++                      }
++                      printk(".");
++
++                      touch_nmi_watchdog();
++              } else if (!(dump_config.dumper->count & 0x7)) {
++                      /* Show progress so the user knows we aren't hung */
++                      dump_speedo(dump_config.dumper->count >> 3); 
++              }
++              /* Todo: Touch/Refresh watchdog */
++
++              /* --- Done with periodic chores -- */
++
++              /* 
++               * extra bit of copying to simplify verification  
++               * in the second kernel boot based scheme
++               */
++              memcpy(dump_buf - DUMP_PAGE_SIZE, dump_buf + 
++                      DUMP_BUFFER_SIZE - DUMP_PAGE_SIZE, DUMP_PAGE_SIZE);
++
++              /* now adjust the leftover bits back to the top of the page */
++              /* this case would not arise during stage 2 (passthru) */
++              memset(dump_buf, 'z', DUMP_BUFFER_SIZE);
++              if (left) {
++                      memcpy(dump_buf, dump_buf + DUMP_BUFFER_SIZE, left);
++              }
++              buf -= DUMP_BUFFER_SIZE;
++              dump_config.dumper->curr_buf = buf;
++      }
++                              
++      return 0;
++}
++
++int dump_generic_skip_data(unsigned long loc, unsigned long sz)
++{
++      /* dummy by default */
++      return 0;
++}
++
++/* 
++ * Common low level routine to write a buffer to current dump device 
++ * Expects checks for space etc to have been taken care of by the caller 
++ * Operates serially at the moment for simplicity. 
++ * TBD/Todo: Consider batching for improved throughput
++ */
++int dump_ll_write(void *buf, unsigned long len)
++{
++      long transferred = 0, last_transfer = 0;
++      int ret = 0;
++
++      /* make sure device is ready */
++      while ((ret = dump_dev_ready(NULL)) == -EAGAIN);
++      if  (ret < 0) {
++              printk("dump_dev_ready failed !err %d\n", ret);
++              return ret;
++      }
++
++      while (len) {
++              if ((last_transfer = dump_dev_write(buf, len)) <= 0)  {
++                      ret = last_transfer;
++                      printk("dump_dev_write failed !err %d\n", 
++                      ret);
++                      break;
++              }
++              /* wait till complete */
++              while ((ret = dump_dev_ready(buf)) == -EAGAIN)
++                      cpu_relax();
++
++              if  (ret < 0) {
++                      printk("i/o failed !err %d\n", ret);
++                      break;
++              }
++
++              len -= last_transfer;
++              buf += last_transfer;
++              transferred += last_transfer;
++      }
++      return (ret < 0) ? ret : transferred;
++}
++
++/* default writeout routine for single dump device */
++/* writes out the dump data ensuring enough space is left for the end marker */
++int dump_generic_write_buffer(void *buf, unsigned long len)
++{
++      long written = 0;
++      int err = 0;
++
++      /* check for space */
++      if ((err = dump_dev_seek(dump_config.dumper->curr_offset + len + 
++                      2*DUMP_BUFFER_SIZE)) < 0) {
++              printk("dump_write_buffer: insuff space after offset 0x%llx\n",
++                      dump_config.dumper->curr_offset);
++              return err;
++      }
++      /* alignment check would happen as a side effect of this */
++      if ((err = dump_dev_seek(dump_config.dumper->curr_offset)) < 0)
++              return err; 
++
++      written = dump_ll_write(buf, len);
++
++      /* all or none */
++
++      if (written < len)
++              written = written ? -ENOSPC : written;
++      else
++              dump_config.dumper->curr_offset += len;
++
++      return written;
++}
++
++int dump_generic_configure(unsigned long devid)
++{
++      struct dump_dev *dev = dump_config.dumper->dev;
++      struct dump_data_filter *filter;
++      void *buf;
++      int ret = 0;
++
++      /* Allocate the dump buffer and initialize dumper state */
++      /* Assume that we get aligned addresses */
++      if (!(buf = dump_alloc_mem(DUMP_BUFFER_SIZE + 3 * DUMP_PAGE_SIZE)))
++              return -ENOMEM;
++
++      if ((unsigned long)buf & (PAGE_SIZE - 1)) {
++              /* sanity check for page aligned address */
++              dump_free_mem(buf);
++              return -ENOMEM; /* fixme: better error code */
++      }
++
++      /* Initialize the rest of the fields */
++      dump_config.dumper->dump_buf = buf + DUMP_PAGE_SIZE;
++      dumper_reset();
++
++      /* Open the dump device */
++      if (!dev)
++              return -ENODEV;
++
++      if ((ret = dev->ops->open(dev, devid))) {
++             return ret;
++      }
++
++      /* Initialise the memory ranges in the dump filter */
++      for (filter = dump_config.dumper->filter ;filter->selector; filter++) {
++              if (!filter->start && !filter->end) {
++                      filter->start = 0;
++                      filter->end = num_physpages << PAGE_SHIFT;
++              }
++      }
++
++      return 0;
++}
++
++int dump_generic_unconfigure(void)
++{
++      struct dump_dev *dev = dump_config.dumper->dev;
++      void *buf = dump_config.dumper->dump_buf;
++      int ret = 0;
++
++      pr_debug("Generic unconfigure\n");
++      /* Close the dump device */
++      if (dev && (ret = dev->ops->release(dev)))
++              return ret;
++
++      printk("Closed dump device\n");
++      
++      if (buf)
++              dump_free_mem((buf - DUMP_PAGE_SIZE));
++
++      dump_config.dumper->curr_buf = dump_config.dumper->dump_buf = NULL;
++      pr_debug("Released dump buffer\n");
++
++      return 0;
++}
++
++
++/* Set up the default dump scheme */
++
++struct dump_scheme_ops dump_scheme_singlestage_ops = {
++      .configure      = dump_generic_configure,
++      .unconfigure    = dump_generic_unconfigure,
++      .sequencer      = dump_generic_sequencer,
++      .iterator       = dump_page_iterator,
++      .save_data      = dump_generic_save_data,
++      .skip_data      = dump_generic_skip_data,
++      .write_buffer   = dump_generic_write_buffer,
++};
++
++struct dump_scheme dump_scheme_singlestage = {
++      .name           = "single-stage",
++      .ops            = &dump_scheme_singlestage_ops
++};
++
++/* The single stage dumper comprising all these */
++struct dumper dumper_singlestage = {
++      .name           = "single-stage",
++      .scheme         = &dump_scheme_singlestage,
++      .fmt            = &dump_fmt_lcrash,
++      .compress       = &dump_none_compression,
++      .filter         = dump_filter_table,
++      .dev            = NULL,
++};            
++
+Index: linux-2.6.0-test5/drivers/dump/dump_setup.c
+===================================================================
+--- linux-2.6.0-test5.orig/drivers/dump/dump_setup.c   2003-09-26 14:26:34.000000000 +0800
++++ linux-2.6.0-test5/drivers/dump/dump_setup.c        2003-09-26 14:26:34.000000000 +0800
+@@ -0,0 +1,803 @@
++/*
++ * Standard kernel function entry points for Linux crash dumps.
++ *
++ * Created by: Matt Robinson (yakker@sourceforge.net)
++ * Contributions from SGI, IBM, HP, MCL, and others.
++ *
++ * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
++ * Copyright (C) 2000 - 2002 TurboLinux, Inc.  All rights reserved.
++ * Copyright (C) 2001 - 2002 Matt D. Robinson.  All rights reserved.
++ * Copyright (C) 2002 Free Software Foundation, Inc. All rights reserved.
++ *
++ * This code is released under version 2 of the GNU GPL.
++ */
++
++/*
++ * -----------------------------------------------------------------------
++ *
++ * DUMP HISTORY
++ *
++ * This dump code goes back to SGI's first attempts at dumping system
++ * memory on SGI systems running IRIX.  A few developers at SGI needed
++ * a way to take this system dump and analyze it, and created 'icrash',
++ * or IRIX Crash.  The mechanism (the dumps and 'icrash') were used
++ * by support people to generate crash reports when a system failure
++ * occurred.  This was vital for large system configurations that
++ * couldn't apply patch after patch after fix just to hope that the
++ * problems would go away.  So the system memory, along with the crash
++ * dump analyzer, allowed support people to quickly figure out what the
++ * problem was on the system with the crash dump.
++ *
++ * In comes Linux.  SGI started moving towards the open source community,
++ * and upon doing so, SGI wanted to take its support utilities into Linux
++ * with the hopes that they would end up the in kernel and user space to
++ * be used by SGI's customers buying SGI Linux systems.  One of the first
++ * few products to be open sourced by SGI was LKCD, or Linux Kernel Crash
++ * Dumps.  LKCD comprises of a patch to the kernel to enable system
++ * dumping, along with 'lcrash', or Linux Crash, to analyze the system
++ * memory dump.  A few additional system scripts and kernel modifications
++ * are also included to make the dump mechanism and dump data easier to
++ * process and use.
++ *
++ * As soon as LKCD was released into the open source community, a number
++ * of larger companies started to take advantage of it.  Today, there are
++ * many community members that contribute to LKCD, and it continues to
++ * flourish and grow as an open source project.
++ */
++
++/*
++ * DUMP TUNABLES
++ *
++ * This is the list of system tunables (via /proc) that are available
++ * for Linux systems.  All the read, write, etc., functions are listed
++ * here.  Currently, there are a few different tunables for dumps:
++ *
++ * dump_device (used to be dumpdev):
++ *     The device for dumping the memory pages out to.  This 
++ *     may be set to the primary swap partition for disruptive dumps,
++ *     and must be an unused partition for non-disruptive dumps.
++ *     Todo: In the case of network dumps, this may be interpreted 
++ *     as the IP address of the netdump server to connect to.
++ *
++ * dump_compress (used to be dump_compress_pages):
++ *     This is the flag which indicates which compression mechanism
++ *     to use.  This is a BITMASK, not an index (0,1,2,4,8,16,etc.).
++ *     This is the current set of values:
++ *
++ *     0: DUMP_COMPRESS_NONE -- Don't compress any pages.
++ *     1: DUMP_COMPRESS_RLE  -- This uses RLE compression.
++ *     2: DUMP_COMPRESS_GZIP -- This uses GZIP compression.
++ *
++ * dump_level:
++ *     The amount of effort the dump module should make to save
++ *     information for post crash analysis.  This value is now
++ *     a BITMASK value, not an index:
++ *
++ *     0:   Do nothing, no dumping. (DUMP_LEVEL_NONE)
++ *
++ *     1:   Print out the dump information to the dump header, and
++ *          write it out to the dump_device. (DUMP_LEVEL_HEADER)
++ *
++ *     2:   Write out the dump header and all kernel memory pages.
++ *          (DUMP_LEVEL_KERN)
++ *
++ *     4:   Write out the dump header and all kernel and user
++ *          memory pages.  (DUMP_LEVEL_USED)
++ *
++ *     8:   Write out the dump header and all conventional/cached 
++ *        memory (RAM) pages in the system (kernel, user, free).  
++ *        (DUMP_LEVEL_ALL_RAM)
++ *
++ *    16:   Write out everything, including non-conventional memory
++ *        like firmware, proms, I/O registers, uncached memory.
++ *        (DUMP_LEVEL_ALL)
++ *
++ *     The dump_level will default to 1.
++ *
++ * dump_flags:
++ *     These are the flags to use when talking about dumps.  There
++ *     are lots of possibilities.  This is a BITMASK value, not an index.
++ * 
++ * -----------------------------------------------------------------------
++ */
++
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/reboot.h>
++#include <linux/fs.h>
++#include <linux/dump.h>
++#include "dump_methods.h"
++#include <linux/proc_fs.h>
++#include <linux/module.h>
++#include <linux/utsname.h>
++#include <linux/highmem.h>
++#include <linux/major.h>
++#include <linux/sysrq.h>
++#include <linux/sysctl.h>
++#include <linux/nmi.h>
++
++#include <asm/hardirq.h>
++#include <asm/uaccess.h>
++
++/*
++ * -----------------------------------------------------------------------
++ *                         V A R I A B L E S
++ * -----------------------------------------------------------------------
++ */
++
++/* Dump tunables */
++struct dump_config dump_config = {
++      .level          = 0,
++      .flags          = 0,
++      .dump_device    = 0,
++      .dump_addr      = 0,
++      .dumper         = NULL
++};
++
++
++/* Global variables used in dump.h */
++/* degree of system freeze when dumping */
++enum dump_silence_levels dump_silence_level = DUMP_HARD_SPIN_CPUS;     
++
++/* Other global fields */
++extern struct __dump_header dump_header; 
++struct dump_dev *dump_dev = NULL;  /* Active dump device                   */
++static int dump_compress = 0;
++
++static u16 dump_compress_none(const u8 *old, u16 oldsize, u8 *new, u16 newsize);
++struct __dump_compress dump_none_compression = {
++      .compress_type  = DUMP_COMPRESS_NONE,
++      .compress_func  = dump_compress_none,
++      .compress_name  = "none",
++};
++
++/* our device operations and functions */
++static int dump_ioctl(struct inode *i, struct file *f,
++      unsigned int cmd, unsigned long arg);
++
++static struct file_operations dump_fops = {
++      .ioctl          =       dump_ioctl,
++};
++
++/* static variables                                                   */
++static int dump_okay = 0;             /* can we dump out to disk?     */
++static spinlock_t dump_lock = SPIN_LOCK_UNLOCKED;
++
++/* used for dump compressors */
++static struct list_head dump_compress_list = LIST_HEAD_INIT(dump_compress_list);
++
++/* list of registered dump targets */
++static struct list_head dump_target_list = LIST_HEAD_INIT(dump_target_list);
++
++/* lkcd info structure -- this is used by lcrash for basic system data     */
++struct __lkcdinfo lkcdinfo = {
++      .ptrsz          = (sizeof(void *) * 8),
++#if defined(__LITTLE_ENDIAN) 
++      .byte_order     = __LITTLE_ENDIAN,
++#else
++      .byte_order     = __BIG_ENDIAN,
++#endif
++      .page_shift     = PAGE_SHIFT,
++      .page_size      = PAGE_SIZE,
++      .page_mask      = PAGE_MASK,
++      .page_offset    = PAGE_OFFSET,
++};
++
++/*
++ * -----------------------------------------------------------------------
++ *            / P R O C   T U N A B L E   F U N C T I O N S
++ * -----------------------------------------------------------------------
++ */
++
++static int proc_dump_device(ctl_table *ctl, int write, struct file *f,
++                          void *buffer, size_t *lenp);
++
++static int proc_doulonghex(ctl_table *ctl, int write, struct file *f,
++                          void *buffer, size_t *lenp);
++/*
++ * sysctl-tuning infrastructure.
++ */
++static ctl_table dump_table[] = {
++      { .ctl_name = CTL_DUMP_LEVEL,
++        .procname = DUMP_LEVEL_NAME, 
++        .data = &dump_config.level,    
++        .maxlen = sizeof(int),
++        .mode = 0644,
++        .proc_handler = proc_doulonghex, },
++
++      { .ctl_name = CTL_DUMP_FLAGS,
++        .procname = DUMP_FLAGS_NAME,
++        .data = &dump_config.flags,   
++        .maxlen = sizeof(int),
++        .mode = 0644,
++        .proc_handler = proc_doulonghex, },
++
++      { .ctl_name = CTL_DUMP_COMPRESS,
++        .procname = DUMP_COMPRESS_NAME,
++        .data = &dump_compress, /* FIXME */
++        .maxlen = sizeof(int),
++        .mode = 0644,
++        .proc_handler = proc_dointvec, },
++        
++      { .ctl_name = CTL_DUMP_DEVICE,
++        .procname = DUMP_DEVICE_NAME,
++        .mode = 0644,
++        .data = &dump_config.dump_device, /* FIXME */
++        .maxlen = sizeof(int),
++        .proc_handler = proc_dump_device },
++
++#ifdef CONFIG_CRASH_DUMP_MEMDEV
++      { .ctl_name = CTL_DUMP_ADDR,
++        .procname = DUMP_ADDR_NAME,
++        .mode = 0444,
++        .data = &dump_config.dump_addr,
++        .maxlen = sizeof(unsigned long),
++        .proc_handler = proc_doulonghex },
++#endif
++
++      { 0, }
++};
++
++static ctl_table dump_root[] = {
++      { .ctl_name = KERN_DUMP,
++        .procname = "dump",
++        .mode = 0555, 
++        .child = dump_table },
++      { 0, }
++};
++
++static ctl_table kernel_root[] = {
++      { .ctl_name = CTL_KERN,
++        .procname = "kernel",
++        .mode = 0555,
++        .child = dump_root, },
++      { 0, }
++};
++
++static struct ctl_table_header *sysctl_header;
++
++/*
++ * -----------------------------------------------------------------------
++ *              C O M P R E S S I O N   F U N C T I O N S
++ * -----------------------------------------------------------------------
++ */
++
++/*
++ * Name: dump_compress_none()
++ * Func: Don't do any compression, period.
++ */
++static u16
++dump_compress_none(const u8 *old, u16 oldsize, u8 *new, u16 newsize)
++{
++      /* just return the old size */
++      return oldsize;
++}
++
++
++/*
++ * Name: dump_execute()
++ * Func: Execute the dumping process.  This makes sure all the appropriate
++ *       fields are updated correctly, and calls dump_execute_memdump(),
++ *       which does the real work.
++ */
++void
++dump_execute(const char *panic_str, const struct pt_regs *regs)
++{
++      int state = -1;
++      unsigned long flags;
++
++      /* make sure we can dump */
++      if (!dump_okay) {
++              pr_info("LKCD not yet configured, can't take dump now\n");
++              return;
++      }
++
++      /* Exclude multiple dumps at the same time,
++       * and disable interrupts,  some drivers may re-enable
++       * interrupts in with silence()
++       *
++       * Try and acquire spin lock. If successful, leave preempt
++       * and interrupts disabled.  See spin_lock_irqsave in spinlock.h
++       */
++      local_irq_save(flags);
++      if (!spin_trylock(&dump_lock)) {
++              local_irq_restore(flags);
++              pr_info("LKCD dump already in progress\n");
++              return;
++      }
++
++      /* Bring system into the strictest level of quiescing for min drift 
++       * dump drivers can soften this as required in dev->ops->silence() 
++       */
++      dump_oncpu = smp_processor_id() + 1;
++      dump_silence_level = DUMP_HARD_SPIN_CPUS; 
++
++      state = dump_generic_execute(panic_str, regs);
++      
++      dump_oncpu = 0;
++      spin_unlock_irqrestore(&dump_lock, flags);
++
++      if (state < 0) {
++              printk("Dump Incomplete or failed!\n");
++      } else {
++              printk("Dump Complete; %d dump pages saved.\n", 
++                     dump_header.dh_num_dump_pages);
++      }
++}
++
++/*
++ * Name: dump_register_compression()
++ * Func: Register a dump compression mechanism.
++ */
++void
++dump_register_compression(struct __dump_compress *item)
++{
++      if (item)
++              list_add(&(item->list), &dump_compress_list);
++}
++
++/*
++ * Name: dump_unregister_compression()
++ * Func: Remove a dump compression mechanism, and re-assign the dump
++ *       compression pointer if necessary.
++ */
++void
++dump_unregister_compression(int compression_type)
++{
++      struct list_head *tmp;
++      struct __dump_compress *dc;
++
++      /* let's make sure our list is valid */
++      if (compression_type != DUMP_COMPRESS_NONE) {
++              list_for_each(tmp, &dump_compress_list) {
++                      dc = list_entry(tmp, struct __dump_compress, list);
++                      if (dc->compress_type == compression_type) {
++                              list_del(&(dc->list));
++                              break;
++                      }
++              }
++      }
++}
++
++/*
++ * Name: dump_compress_init()
++ * Func: Initialize (or re-initialize) compression scheme.
++ */
++static int
++dump_compress_init(int compression_type)
++{
++      struct list_head *tmp;
++      struct __dump_compress *dc;
++
++      /* try to remove the compression item */
++      list_for_each(tmp, &dump_compress_list) {
++              dc = list_entry(tmp, struct __dump_compress, list);
++              if (dc->compress_type == compression_type) {
++                      dump_config.dumper->compress = dc;
++                      dump_compress = compression_type;
++                      pr_debug("Dump Compress %s\n", dc->compress_name);
++                      return 0;
++              }
++      }
++
++      /* 
++       * nothing on the list -- return ENODATA to indicate an error 
++       *
++       * NB: 
++       *      EAGAIN: reports "Resource temporarily unavailable" which
++       *              isn't very enlightening.
++       */
++      printk("compression_type:%d not found\n", compression_type);
++
++      return -ENODATA;
++}
++
++static int
++dumper_setup(unsigned long flags, unsigned long devid)
++{
++      int ret = 0;
++
++      /* unconfigure old dumper if it exists */
++      dump_okay = 0;
++      if (dump_config.dumper) {
++              pr_debug("Unconfiguring current dumper\n");
++              dump_unconfigure();
++      }
++      /* set up new dumper */
++      if (dump_config.flags & DUMP_FLAGS_SOFTBOOT) {
++              printk("Configuring softboot based dump \n");
++#ifdef CONFIG_CRASH_DUMP_MEMDEV
++              dump_config.dumper = &dumper_stage1; 
++#else
++              printk("Requires CONFIG_CRASHDUMP_MEMDEV. Can't proceed.\n");
++              return -1;
++#endif
++      } else {
++              dump_config.dumper = &dumper_singlestage;
++      }       
++      dump_config.dumper->dev = dump_dev;
++
++      ret = dump_configure(devid);
++      if (!ret) {
++              dump_okay = 1;
++              pr_debug("%s dumper set up for dev 0x%lx\n", 
++                      dump_config.dumper->name, devid);
++              dump_config.dump_device = devid;
++      } else {
++              printk("%s dumper set up failed for dev 0x%lx\n", 
++                     dump_config.dumper->name, devid);
++              dump_config.dumper = NULL;
++      }
++      return ret;
++}
++
++static int
++dump_target_init(int target)
++{
++      char type[20];
++      struct list_head *tmp;
++      struct dump_dev *dev;
++      
++      switch (target) {
++              case DUMP_FLAGS_DISKDUMP:
++                      strcpy(type, "blockdev"); break;
++              case DUMP_FLAGS_NETDUMP:
++                      strcpy(type, "networkdev"); break;
++              default:
++                      return -1;
++      }
++
++      /*
++       * This is a bit stupid, generating strings from flag
++       * and doing strcmp. This is done because 'struct dump_dev'
++       * has string 'type_name' and not interger 'type'.
++       */
++      list_for_each(tmp, &dump_target_list) {
++              dev = list_entry(tmp, struct dump_dev, list);
++              if (strcmp(type, dev->type_name) == 0) {
++                      dump_dev = dev;
++                      return 0;
++              }
++      }
++      return -1;
++}
++
++/*
++ * Name: dump_ioctl()
++ * Func: Allow all dump tunables through a standard ioctl() mechanism.
++ *       This is far better than before, where we'd go through /proc,
++ *       because now this will work for multiple OS and architectures.
++ */
++static int
++dump_ioctl(struct inode *i, struct file *f, unsigned int cmd, unsigned long arg)
++{
++      /* check capabilities */
++      if (!capable(CAP_SYS_ADMIN))
++              return -EPERM;
++
++      if (!dump_config.dumper && cmd == DIOSDUMPCOMPRESS)
++              /* dump device must be configured first */
++              return -ENODEV;
++
++      /*
++       * This is the main mechanism for controlling get/set data
++       * for various dump device parameters.  The real trick here
++       * is setting the dump device (DIOSDUMPDEV).  That's what
++       * triggers everything else.
++       */
++      switch (cmd) {
++      case DIOSDUMPDEV:       /* set dump_device */
++              pr_debug("Configuring dump device\n"); 
++              if (!(f->f_flags & O_RDWR))
++                      return -EPERM;
++
++              __dump_open();
++              return dumper_setup(dump_config.flags, arg);
++
++              
++      case DIOGDUMPDEV:       /* get dump_device */
++              return put_user((long)dump_config.dump_device, (long *)arg);
++
++      case DIOSDUMPLEVEL:     /* set dump_level */
++              if (!(f->f_flags & O_RDWR))
++                      return -EPERM;
++
++              /* make sure we have a positive value */
++              if (arg < 0)
++                      return -EINVAL;
++
++              /* Fixme: clean this up */
++              dump_config.level = 0;
++              switch ((int)arg) {
++                      case DUMP_LEVEL_ALL:
++                      case DUMP_LEVEL_ALL_RAM:
++                              dump_config.level |= DUMP_MASK_UNUSED;
++                      case DUMP_LEVEL_USED:
++                              dump_config.level |= DUMP_MASK_USED;
++                      case DUMP_LEVEL_KERN:
++                              dump_config.level |= DUMP_MASK_KERN;
++                      case DUMP_LEVEL_HEADER:
++                              dump_config.level |= DUMP_MASK_HEADER;
++                      case DUMP_LEVEL_NONE:
++                              break;
++                      default:
++                              return (-EINVAL);
++                      }
++              pr_debug("Dump Level 0x%lx\n", dump_config.level);
++              break;
++
++      case DIOGDUMPLEVEL:     /* get dump_level */
++              /* fixme: handle conversion */
++              return put_user((long)dump_config.level, (long *)arg);
++
++              
++      case DIOSDUMPFLAGS:     /* set dump_flags */
++              /* check flags */
++              if (!(f->f_flags & O_RDWR))
++                      return -EPERM;
++
++              /* make sure we have a positive value */
++              if (arg < 0)
++                      return -EINVAL;
++                      
++              if (dump_target_init(arg & DUMP_FLAGS_TARGETMASK) < 0)
++                      return -EINVAL; /* return proper error */
++
++              dump_config.flags = arg;
++              
++              pr_debug("Dump Flags 0x%lx\n", dump_config.flags);
++              break;
++              
++      case DIOGDUMPFLAGS:     /* get dump_flags */
++              return put_user((long)dump_config.flags, (long *)arg);
++
++      case DIOSDUMPCOMPRESS:  /* set the dump_compress status */
++              if (!(f->f_flags & O_RDWR))
++                      return -EPERM;
++
++              return dump_compress_init((int)arg);
++
++      case DIOGDUMPCOMPRESS:  /* get the dump_compress status */
++              return put_user((long)(dump_config.dumper ? 
++                      dump_config.dumper->compress->compress_type : 0), 
++                      (long *)arg);
++                      
++      default:
++              /* 
++               * these are network dump specific ioctls, let the
++               * module handle them.
++               */
++              return dump_dev_ioctl(cmd, arg);
++      }
++      return 0;
++}
++
++/*
++ * Handle special cases for dump_device 
++ * changing dump device requires doing an opening the device
++ */
++static int 
++proc_dump_device(ctl_table *ctl, int write, struct file *f,
++               void *buffer, size_t *lenp)
++{
++      int *valp = ctl->data;
++      int oval = *valp;
++      int ret = -EPERM;
++
++      /* same permission checks as ioctl */
++      if (capable(CAP_SYS_ADMIN)) {
++              ret = proc_doulonghex(ctl, write, f, buffer, lenp);
++              if (ret == 0 && write && *valp != oval) {
++                      /* need to restore old value to close properly */
++                      dump_config.dump_device = (dev_t) oval;
++                      __dump_open();
++                      ret = dumper_setup(dump_config.flags, (dev_t) *valp);
++              }
++      }
++
++      return ret;
++}
++
++/* All for the want of a proc_do_xxx routine which prints values in hex */
++static int 
++proc_doulonghex(ctl_table *ctl, int write, struct file *f,
++               void *buffer, size_t *lenp)
++{
++#define TMPBUFLEN 20
++      unsigned long *i;
++      size_t len, left;
++      char buf[TMPBUFLEN];
++
++      if (!ctl->data || !ctl->maxlen || !*lenp || (f->f_pos)) {
++              *lenp = 0;
++              return 0;
++      }
++      
++      i = (unsigned long *) ctl->data;
++      left = *lenp;
++      
++      sprintf(buf, "0x%lx\n", (*i));
++      len = strlen(buf);
++      if (len > left)
++              len = left;
++      if(copy_to_user(buffer, buf, len))
++              return -EFAULT;
++      
++      left -= len;
++      *lenp -= left;
++      f->f_pos += *lenp;
++      return 0;
++}
++
++/*
++ * -----------------------------------------------------------------------
++ *                     I N I T   F U N C T I O N S
++ * -----------------------------------------------------------------------
++ */
++
++/*
++ * These register and unregister routines are exported for modules
++ * to register their dump drivers (like block, net etc)
++ */
++int
++dump_register_device(struct dump_dev *ddev)
++{
++      struct list_head *tmp;
++      struct dump_dev *dev;
++
++      list_for_each(tmp, &dump_target_list) {
++              dev = list_entry(tmp, struct dump_dev, list);
++              if (strcmp(ddev->type_name, dev->type_name) == 0) {
++                      printk("Target type %s already registered\n",
++                                      dev->type_name);
++                      return -1; /* return proper error */
++              }
++      }
++      list_add(&(ddev->list), &dump_target_list);
++      
++      return 0;
++}
++
++void
++dump_unregister_device(struct dump_dev *ddev)
++{
++      list_del(&(ddev->list));
++      if (ddev != dump_dev)
++              return;
++
++      dump_okay = 0;
++
++      if (dump_config.dumper)
++              dump_unconfigure();
++
++      dump_config.flags &= ~DUMP_FLAGS_TARGETMASK;
++      dump_okay = 0;
++      dump_dev = NULL;
++      dump_config.dumper = NULL;
++}
++
++static int panic_event(struct notifier_block *this, unsigned long event,
++                     void *ptr)
++{
++      struct pt_regs regs;
++
++      get_current_regs(&regs);
++      dump_execute((const char *)ptr, &regs);
++      return 0;
++}
++
++extern struct notifier_block *panic_notifier_list;
++static int panic_event(struct notifier_block *, unsigned long, void *);
++static struct notifier_block panic_block = {
++      .notifier_call = panic_event,
++};
++
++#ifdef CONFIG_MAGIC_SYSRQ
++/* Sysrq handler */
++static void sysrq_handle_crashdump(int key, struct pt_regs *pt_regs,
++              struct tty_struct *tty) {
++      dump_execute("sysrq", pt_regs);
++}
++
++static struct sysrq_key_op sysrq_crashdump_op = {
++      .handler        =       sysrq_handle_crashdump,
++      .help_msg       =       "Dump",
++      .action_msg     =       "Starting crash dump",
++};
++#endif
++
++static inline void
++dump_sysrq_register(void) 
++{
++#ifdef CONFIG_MAGIC_SYSRQ
++      __sysrq_lock_table();
++      __sysrq_put_key_op(DUMP_SYSRQ_KEY, &sysrq_crashdump_op);
++      __sysrq_unlock_table();
++#endif
++}
++
++static inline void
++dump_sysrq_unregister(void)
++{
++#ifdef CONFIG_MAGIC_SYSRQ
++      __sysrq_lock_table();
++      if (__sysrq_get_key_op(DUMP_SYSRQ_KEY) == &sysrq_crashdump_op)
++              __sysrq_put_key_op(DUMP_SYSRQ_KEY, NULL);
++      __sysrq_unlock_table();
++#endif
++}
++
++/*
++ * Name: dump_init()
++ * Func: Initialize the dump process.  This will set up any architecture
++ *       dependent code.  The big key is we need the memory offsets before
++ *       the page table is initialized, because the base memory offset
++ *       is changed after paging_init() is called.
++ */
++static int __init
++dump_init(void)
++{
++      struct sysinfo info;
++
++      /* try to create our dump device */
++      if (register_chrdev(CRASH_DUMP_MAJOR, "dump", &dump_fops)) {
++              printk("cannot register dump character device!\n");
++              return -EBUSY;
++      }
++
++      __dump_init((u64)PAGE_OFFSET);
++
++      /* set the dump_compression_list structure up */
++      dump_register_compression(&dump_none_compression);
++
++      /* grab the total memory size now (not if/when we crash) */
++      si_meminfo(&info);
++
++      /* set the memory size */
++      dump_header.dh_memory_size = (u64)info.totalram;
++
++      sysctl_header = register_sysctl_table(kernel_root, 0);
++      dump_sysrq_register();
++
++      notifier_chain_register(&panic_notifier_list, &panic_block);
++      dump_function_ptr = dump_execute;
++
++      pr_info("Crash dump driver initialized.\n");
++      return 0;
++}
++
++static void __exit
++dump_cleanup(void)
++{
++      dump_okay = 0;
++
++      if (dump_config.dumper)
++              dump_unconfigure();
++
++      /* arch-specific cleanup routine */
++      __dump_cleanup();
++
++      /* ignore errors while unregistering -- since can't do anything */
++      unregister_sysctl_table(sysctl_header);
++      unregister_chrdev(CRASH_DUMP_MAJOR, "dump");
++      dump_sysrq_unregister();
++      notifier_chain_unregister(&panic_notifier_list, &panic_block);
++      dump_function_ptr = NULL;
++}
++
++EXPORT_SYMBOL(dump_register_compression);
++EXPORT_SYMBOL(dump_unregister_compression);
++EXPORT_SYMBOL(dump_register_device);
++EXPORT_SYMBOL(dump_unregister_device);
++EXPORT_SYMBOL(dump_config);
++EXPORT_SYMBOL(dump_silence_level);
++
++EXPORT_SYMBOL(__dump_irq_enable);
++EXPORT_SYMBOL(__dump_irq_restore);
++
++MODULE_AUTHOR("Matt D. Robinson <yakker@sourceforge.net>");
++MODULE_DESCRIPTION("Linux Kernel Crash Dump (LKCD) driver");
++MODULE_LICENSE("GPL");
++
++module_init(dump_init);
++module_exit(dump_cleanup);
+Index: linux-2.6.0-test5/include/linux/dumpdev.h
+===================================================================
+--- linux-2.6.0-test5.orig/include/linux/dumpdev.h     2003-09-26 14:26:34.000000000 +0800
++++ linux-2.6.0-test5/include/linux/dumpdev.h  2003-09-26 14:27:08.000000000 +0800
+@@ -0,0 +1,161 @@
++/*
++ * Generic dump device interfaces for flexible system dump 
++ * (Enables variation of dump target types e.g disk, network, memory)
++ *
++ * These interfaces have evolved based on discussions on lkcd-devel. 
++ * Eventually the intent is to support primary and secondary or 
++ * alternate targets registered at the same time, with scope for 
++ * situation based failover or multiple dump devices used for parallel 
++ * dump i/o.
++ *
++ * Started: Oct 2002 - Suparna Bhattacharya (suparna@in.ibm.com)
++ *
++ * Copyright (C) 2001 - 2002 Matt D. Robinson.  All rights reserved.
++ * Copyright (C) 2002 International Business Machines Corp. 
++ *
++ * This code is released under version 2 of the GNU GPL.
++ */
++
++#ifndef _LINUX_DUMPDEV_H
++#define _LINUX_DUMPDEV_H
++
++#include <linux/kernel.h>
++#include <linux/wait.h>
++#include <linux/bio.h>
++
++/* Determined by the dump target (device) type */
++
++struct dump_dev;
++
++struct dump_dev_ops {
++      int (*open)(struct dump_dev *, unsigned long); /* configure */
++      int (*release)(struct dump_dev *); /* unconfigure */
++      int (*silence)(struct dump_dev *); /* when dump starts */
++      int (*resume)(struct dump_dev *); /* when dump is over */
++      int (*seek)(struct dump_dev *, loff_t);
++      /* trigger a write (async in nature typically) */
++      int (*write)(struct dump_dev *, void *, unsigned long);
++      /* not usually used during dump, but option available */
++      int (*read)(struct dump_dev *, void *, unsigned long);
++      /* use to poll for completion */
++      int (*ready)(struct dump_dev *, void *); 
++      int (*ioctl)(struct dump_dev *, unsigned int, unsigned long);
++};
++
++struct dump_dev {
++      char type_name[32]; /* block, net-poll etc */
++      unsigned long device_id; /* interpreted differently for various types */
++      struct dump_dev_ops *ops;
++      struct list_head list;
++      loff_t curr_offset;
++};
++
++/*
++ * dump_dev type variations: 
++ */
++
++/* block */
++struct dump_blockdev {
++      struct dump_dev ddev;
++      dev_t kdev_id;
++      struct block_device *bdev;
++      struct bio *bio;
++      loff_t start_offset;
++      loff_t limit;
++      int err;
++};
++
++static inline struct dump_blockdev *DUMP_BDEV(struct dump_dev *dev)
++{
++      return container_of(dev, struct dump_blockdev, ddev);
++}
++
++
++/* mem  - for internal use by soft-boot based dumper */
++struct dump_memdev {
++      struct dump_dev ddev;
++      unsigned long indirect_map_root;
++      unsigned long nr_free;
++      struct page *curr_page;
++      unsigned long *curr_map;
++      unsigned long curr_map_offset;
++      unsigned long last_offset;
++      unsigned long last_used_offset;
++      unsigned long last_bs_offset;
++};    
++
++static inline struct dump_memdev *DUMP_MDEV(struct dump_dev *dev)
++{
++      return container_of(dev, struct dump_memdev, ddev);
++}
++
++/* Todo/future - meant for raw dedicated interfaces e.g. mini-ide driver */
++struct dump_rdev {
++      struct dump_dev ddev;
++      char name[32];
++      int (*reset)(struct dump_rdev *, unsigned int, 
++              unsigned long);
++      /* ... to do ... */
++};
++
++/* just to get the size right when saving config across a soft-reboot */
++struct dump_anydev {
++      union {
++              struct dump_blockdev bddev;
++              /* .. add other types here .. */
++      };
++};
++
++
++
++/* Dump device / target operation wrappers */
++/* These assume that dump_dev is initiatized to dump_config.dumper->dev */
++
++extern struct dump_dev *dump_dev;
++
++static inline int dump_dev_open(unsigned long arg)
++{
++      return dump_dev->ops->open(dump_dev, arg);
++}
++
++static inline int dump_dev_release(void)
++{
++      return dump_dev->ops->release(dump_dev);
++}
++
++static inline int dump_dev_silence(void)
++{
++      return dump_dev->ops->silence(dump_dev);
++}
++
++static inline int dump_dev_resume(void)
++{
++      return dump_dev->ops->resume(dump_dev);
++}
++
++static inline int dump_dev_seek(loff_t offset)
++{
++      return dump_dev->ops->seek(dump_dev, offset);
++}
++
++static inline int dump_dev_write(void *buf, unsigned long len)
++{
++      return dump_dev->ops->write(dump_dev, buf, len);
++}
++
++static inline int dump_dev_ready(void *buf)
++{
++      return dump_dev->ops->ready(dump_dev, buf);
++}
++
++static inline int dump_dev_ioctl(unsigned int cmd, unsigned long arg)
++{
++      if (!dump_dev->ops->ioctl)
++              return -EINVAL;
++      return dump_dev->ops->ioctl(dump_dev, cmd, arg);
++}
++
++extern int dump_register_device(struct dump_dev *);
++extern void dump_unregister_device(struct dump_dev *);
++
++#endif /*  _LINUX_DUMPDEV_H */
+Index: linux-2.6.0-test5/include/linux/dump.h
+===================================================================
+--- linux-2.6.0-test5.orig/include/linux/dump.h        2003-09-26 14:26:34.000000000 +0800
++++ linux-2.6.0-test5/include/linux/dump.h     2003-09-26 14:26:34.000000000 +0800
+@@ -0,0 +1,376 @@
++/*
++ * Kernel header file for Linux crash dumps.
++ *
++ * Created by: Matt Robinson (yakker@sgi.com)
++ * Copyright 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
++ *
++ * vmdump.h to dump.h by: Matt D. Robinson (yakker@sourceforge.net)
++ * Copyright 2001 - 2002 Matt D. Robinson.  All rights reserved.
++ * Copyright (C) 2002 Free Software Foundation, Inc. All rights reserved.
++ *
++ * Most of this is the same old stuff from vmdump.h, except now we're
++ * actually a stand-alone driver plugged into the block layer interface,
++ * with the exception that we now allow for compression modes externally
++ * loaded (e.g., someone can come up with their own).
++ *
++ * This code is released under version 2 of the GNU GPL.
++ */
++
++/* This header file includes all structure definitions for crash dumps. */
++#ifndef _DUMP_H
++#define _DUMP_H
++
++#if defined(CONFIG_CRASH_DUMP) || defined (CONFIG_CRASH_DUMP_MODULE)
++
++#include <linux/list.h>
++#include <linux/notifier.h>
++#include <linux/dumpdev.h>
++
++/* 
++ * Predefine default DUMP_PAGE constants, asm header may override.
++ *
++ * On ia64 discontinuous memory systems it's possible for the memory
++ * banks to stop at 2**12 page alignments, the smallest possible page
++ * size. But the system page size, PAGE_SIZE, is in fact larger.
++ */
++#define DUMP_PAGE_SHIFT       PAGE_SHIFT
++#define DUMP_PAGE_MASK                PAGE_MASK
++#define DUMP_PAGE_ALIGN(addr) PAGE_ALIGN(addr)
++#define DUMP_HEADER_OFFSET    PAGE_SIZE
++
++/* keep DUMP_PAGE_SIZE constant to 4K = 1<<12
++ * it may be different from PAGE_SIZE then.
++ */
++#define DUMP_PAGE_SIZE                4096
++
++/* 
++ * Predefined default memcpy() to use when copying memory to the dump buffer.
++ *
++ * On ia64 there is a heads up function that can be called to let the prom
++ * machine check monitor know that the current activity is risky and it should
++ * ignore the fault (nofault). In this case the ia64 header will redefine this
++ * macro to __dump_memcpy() and use it's arch specific version.
++ */
++#define DUMP_memcpy           memcpy
++
++/* necessary header files */
++#include <asm/dump.h>                 /* for architecture-specific header */
++
++/* 
++ * Size of the buffer that's used to hold:
++ *
++ *    1. the dump header (padded to fill the complete buffer)
++ *    2. the possibly compressed page headers and data
++ */
++#define DUMP_BUFFER_SIZE      (64 * 1024)  /* size of dump buffer         */
++#define DUMP_HEADER_SIZE      DUMP_BUFFER_SIZE
++
++/* standard header definitions */
++#define DUMP_MAGIC_NUMBER     0xa8190173618f23edULL  /* dump magic number */
++#define DUMP_MAGIC_LIVE               0xa8190173618f23cdULL  /* live magic number */
++#define DUMP_VERSION_NUMBER   0x8     /* dump version number              */
++#define DUMP_PANIC_LEN                0x100   /* dump panic string length         */
++
++/* dump levels - type specific stuff added later -- add as necessary */
++#define DUMP_LEVEL_NONE               0x0     /* no dumping at all -- just bail   */
++#define DUMP_LEVEL_HEADER     0x1     /* kernel dump header only          */
++#define DUMP_LEVEL_KERN               0x2     /* dump header and kernel pages     */
++#define DUMP_LEVEL_USED               0x4     /* dump header, kernel/user pages   */
++#define DUMP_LEVEL_ALL_RAM    0x8     /* dump header, all RAM pages       */
++#define DUMP_LEVEL_ALL                0x10    /* dump all memory RAM and firmware */
++
++
++/* dump compression options -- add as necessary */
++#define DUMP_COMPRESS_NONE    0x0     /* don't compress this dump         */
++#define DUMP_COMPRESS_RLE     0x1     /* use RLE compression              */
++#define DUMP_COMPRESS_GZIP    0x2     /* use GZIP compression             */
++
++/* dump flags - any dump-type specific flags -- add as necessary */
++#define DUMP_FLAGS_NONE               0x0     /* no flags are set for this dump   */
++#define DUMP_FLAGS_SOFTBOOT   0x2     /* 2 stage soft-boot based dump     */
++
++#define DUMP_FLAGS_TARGETMASK 0xf0000000 /* handle special case targets   */
++#define DUMP_FLAGS_DISKDUMP   0x80000000 /* dump to local disk            */
++#define DUMP_FLAGS_NETDUMP    0x40000000 /* dump over the network         */
++
++/* dump header flags -- add as necessary */
++#define DUMP_DH_FLAGS_NONE    0x0     /* no flags set (error condition!)  */
++#define DUMP_DH_RAW           0x1     /* raw page (no compression)        */
++#define DUMP_DH_COMPRESSED    0x2     /* page is compressed               */
++#define DUMP_DH_END           0x4     /* end marker on a full dump        */
++#define DUMP_DH_TRUNCATED     0x8     /* dump is incomplete               */
++#define DUMP_DH_TEST_PATTERN  0x10    /* dump page is a test pattern      */
++#define DUMP_DH_NOT_USED      0x20    /* 1st bit not used in flags        */
++
++/* names for various dump parameters in /proc/kernel */
++#define DUMP_ROOT_NAME                "sys/dump"
++#define DUMP_DEVICE_NAME      "device"
++#define DUMP_COMPRESS_NAME    "compress"
++#define DUMP_LEVEL_NAME               "level"
++#define DUMP_FLAGS_NAME               "flags"
++#define DUMP_ADDR_NAME                "addr"
++
++#define DUMP_SYSRQ_KEY                'd'     /* key to use for MAGIC_SYSRQ key   */
++
++/* CTL_DUMP names: */
++enum
++{
++      CTL_DUMP_DEVICE=1,
++      CTL_DUMP_COMPRESS=3,
++      CTL_DUMP_LEVEL=3,
++      CTL_DUMP_FLAGS=4,
++      CTL_DUMP_ADDR=5,
++      CTL_DUMP_TEST=6,
++};
++
++
++/* page size for gzip compression -- buffered slightly beyond hardware PAGE_SIZE used by DUMP */
++#define DUMP_DPC_PAGE_SIZE    (DUMP_PAGE_SIZE + 512)
++
++/* dump ioctl() control options */
++#define DIOSDUMPDEV           1       /* set the dump device              */
++#define DIOGDUMPDEV           2       /* get the dump device              */
++#define DIOSDUMPLEVEL         3       /* set the dump level               */
++#define DIOGDUMPLEVEL         4       /* get the dump level               */
++#define DIOSDUMPFLAGS         5       /* set the dump flag parameters     */
++#define DIOGDUMPFLAGS         6       /* get the dump flag parameters     */
++#define DIOSDUMPCOMPRESS      7       /* set the dump compress level      */
++#define DIOGDUMPCOMPRESS      8       /* get the dump compress level      */
++
++/* these ioctls are used only by netdump module */
++#define DIOSTARGETIP          9       /* set the target m/c's ip          */
++#define DIOGTARGETIP          10      /* get the target m/c's ip          */
++#define DIOSTARGETPORT                11      /* set the target m/c's port        */
++#define DIOGTARGETPORT                12      /* get the target m/c's port        */
++#define DIOSSOURCEPORT                13      /* set the source m/c's port        */
++#define DIOGSOURCEPORT                14      /* get the source m/c's port        */
++#define DIOSETHADDR           15      /* set ethernet address             */
++#define DIOGETHADDR           16      /* get ethernet address             */
++
++/*
++ * Structure: __dump_header
++ *  Function: This is the header dumped at the top of every valid crash
++ *            dump.  
++ */
++struct __dump_header {
++      /* the dump magic number -- unique to verify dump is valid */
++      u64     dh_magic_number;
++
++      /* the version number of this dump */
++      u32     dh_version;
++
++      /* the size of this header (in case we can't read it) */
++      u32     dh_header_size;
++
++      /* the level of this dump (just a header?) */
++      u32     dh_dump_level;
++
++      /* 
++       * We assume dump_page_size to be 4K in every case.
++       * Store here the configurable system page size (4K, 8K, 16K, etc.) 
++       */
++      u32     dh_page_size;
++
++      /* the size of all physical memory */
++      u64     dh_memory_size;
++
++      /* the start of physical memory */
++      u64     dh_memory_start;
++
++      /* the end of physical memory */
++      u64     dh_memory_end;
++
++      /* the number of hardware/physical pages in this dump specifically */
++      u32     dh_num_dump_pages;
++
++      /* the panic string, if available */
++      char    dh_panic_string[DUMP_PANIC_LEN];
++
++      /* timeval depends on architecture, two long values */
++      struct {
++              u64 tv_sec;
++              u64 tv_usec;
++      } dh_time; /* the time of the system crash */
++
++      /* the NEW utsname (uname) information -- in character form */
++      /* we do this so we don't have to include utsname.h         */
++      /* plus it helps us be more architecture independent        */
++      /* now maybe one day soon they'll make the [65] a #define!  */
++      char    dh_utsname_sysname[65];
++      char    dh_utsname_nodename[65];
++      char    dh_utsname_release[65];
++      char    dh_utsname_version[65];
++      char    dh_utsname_machine[65];
++      char    dh_utsname_domainname[65];
++
++      /* the address of current task (OLD = void *, NEW = u64) */
++      u64     dh_current_task;
++
++      /* what type of compression we're using in this dump (if any) */
++      u32     dh_dump_compress;
++
++      /* any additional flags */
++      u32     dh_dump_flags;
++
++      /* any additional flags */
++      u32     dh_dump_device;
++} __attribute__((packed));
++
++/*
++ * Structure: __dump_page
++ *  Function: To act as the header associated to each physical page of
++ *            memory saved in the system crash dump.  This allows for
++ *            easy reassembly of each crash dump page.  The address bits
++ *            are split to make things easier for 64-bit/32-bit system
++ *            conversions.
++ *
++ * dp_byte_offset and dp_page_index are landmarks that are helpful when
++ * looking at a hex dump of /dev/vmdump,
++ */
++struct __dump_page {
++      /* the address of this dump page */
++      u64     dp_address;
++
++      /* the size of this dump page */
++      u32     dp_size;
++
++      /* flags (currently DUMP_COMPRESSED, DUMP_RAW or DUMP_END) */
++      u32     dp_flags;
++} __attribute__((packed));
++
++/*
++ * Structure: __lkcdinfo
++ * Function:  This structure contains information needed for the lkcdutils
++ *            package (particularly lcrash) to determine what information is
++ *            associated to this kernel, specifically.
++ */
++struct __lkcdinfo {
++      int     arch;
++      int     ptrsz;
++      int     byte_order;
++      int     linux_release;
++      int     page_shift;
++      int     page_size;
++      u64     page_mask;
++      u64     page_offset;
++      int     stack_offset;
++};
++
++#ifdef __KERNEL__
++
++/*
++ * Structure: __dump_compress
++ *  Function: This is what an individual compression mechanism can use
++ *            to plug in their own compression techniques.  It's always
++ *            best to build these as individual modules so that people
++ *            can put in whatever they want.
++ */
++struct __dump_compress {
++      /* the list_head structure for list storage */
++      struct list_head list;
++
++      /* the type of compression to use (DUMP_COMPRESS_XXX) */
++      int compress_type;
++      const char *compress_name;
++
++      /* the compression function to call */
++      u16 (*compress_func)(const u8 *, u16, u8 *, u16);
++};
++
++/* functions for dump compression registration */
++extern void dump_register_compression(struct __dump_compress *);
++extern void dump_unregister_compression(int);
++
++/*
++ * Structure dump_mbank[]:
++ *
++ * For CONFIG_DISCONTIGMEM systems this array specifies the
++ * memory banks/chunks that need to be dumped after a panic.
++ *
++ * For classic systems it specifies a single set of pages from
++ * 0 to max_mapnr.
++ */
++struct __dump_mbank {
++      u64     start;
++      u64     end;
++      int     type;
++      int     pad1;
++      long    pad2;
++};
++
++#define DUMP_MBANK_TYPE_CONVENTIONAL_MEMORY           1
++#define DUMP_MBANK_TYPE_OTHER                         2
++
++#define MAXCHUNKS 256
++extern int dump_mbanks;
++extern struct __dump_mbank dump_mbank[MAXCHUNKS];
++
++/* notification event codes */
++#define DUMP_BEGIN            0x0001  /* dump beginning */
++#define DUMP_END              0x0002  /* dump ending */
++
++/* Scheduler soft spin control.
++ *
++ * 0 - no dump in progress
++ * 1 - cpu0 is dumping, ...
++ */
++extern unsigned long dump_oncpu;
++extern void dump_execute(const char *, const struct pt_regs *);
++
++/*
++ *    Notifier list for kernel code which wants to be called
++ *    at kernel dump. 
++ */
++extern struct notifier_block *dump_notifier_list;
++static inline int register_dump_notifier(struct notifier_block *nb)
++{
++      return notifier_chain_register(&dump_notifier_list, nb);
++}
++static inline int unregister_dump_notifier(struct notifier_block * nb)
++{
++      return notifier_chain_unregister(&dump_notifier_list, nb);
++}
++
++extern void (*dump_function_ptr)(const char *, const struct pt_regs *);
++static inline void dump(char * str, struct pt_regs * regs)
++{
++      if (dump_function_ptr)
++              dump_function_ptr(str, regs);
++}
++
++/*
++ * Common Arch Specific Functions should be declared here.
++ * This allows the C compiler to detect discrepancies.
++ */
++extern void   __dump_open(void);
++extern void   __dump_cleanup(void);
++extern void   __dump_init(u64);
++extern void   __dump_save_regs(struct pt_regs *, const struct pt_regs *);
++extern int    __dump_configure_header(const struct pt_regs *);
++extern void   __dump_irq_enable(void);
++extern void   __dump_irq_restore(void);
++extern int    __dump_page_valid(unsigned long index);
++#ifdef CONFIG_SMP
++extern void   __dump_save_other_cpus(void);
++#else
++#define       __dump_save_other_cpus()
++#endif
++
++/* to track all used (compound + zero order) pages */
++#define PageInuse(p)   (PageCompound(p) || page_count(p))
++
++#endif /* __KERNEL__ */
++
++#else /* !CONFIG_CRASH_DUMP */
++
++/* If not configured then make code disappear! */
++#define register_dump_watchdog(x)     do { } while(0)
++#define unregister_dump_watchdog(x)   do { } while(0)
++#define register_dump_notifier(x)     do { } while(0)
++#define unregister_dump_notifier(x)   do { } while(0)
++#define dump_in_progress()            0
++#define dump(x, y)                    do { } while(0)
++
++#endif        /* !CONFIG_CRASH_DUMP */
++
++#endif /* _DUMP_H */
+Index: linux-2.6.0-test5/include/linux/dump_netdev.h
+===================================================================
+--- linux-2.6.0-test5.orig/include/linux/dump_netdev.h 2003-09-26 14:26:34.000000000 +0800
++++ linux-2.6.0-test5/include/linux/dump_netdev.h      2003-09-26 14:26:34.000000000 +0800
+@@ -0,0 +1,82 @@
++/*
++ *  linux/drivers/net/netconsole.h
++ *
++ *  Copyright (C) 2001  Ingo Molnar <mingo@redhat.com>
++ *
++ *  This file contains the implementation of an IRQ-safe, crash-safe
++ *  kernel console implementation that outputs kernel messages to the
++ *  network.
++ *
++ * Modification history:
++ *
++ * 2001-09-17    started by Ingo Molnar.
++ */
++
++/****************************************************************
++ *      This program is free software; you can redistribute it and/or modify
++ *      it under the terms of the GNU General Public License as published by
++ *      the Free Software Foundation; either version 2, or (at your option)
++ *      any later version.
++ *
++ *      This program is distributed in the hope that it will be useful,
++ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *      GNU General Public License for more details.
++ *
++ *      You should have received a copy of the GNU General Public License
++ *      along with this program; if not, write to the Free Software
++ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ ****************************************************************/
++
++#define NETCONSOLE_VERSION 0x03
++
++enum netdump_commands {
++      COMM_NONE = 0,
++      COMM_SEND_MEM = 1,
++      COMM_EXIT = 2,
++      COMM_REBOOT = 3,
++      COMM_HELLO = 4,
++      COMM_GET_NR_PAGES = 5,
++      COMM_GET_PAGE_SIZE = 6,
++      COMM_START_NETDUMP_ACK = 7,
++      COMM_GET_REGS = 8,
++      COMM_GET_MAGIC = 9,
++      COMM_START_WRITE_NETDUMP_ACK = 10,
++      COMM_SYSRQ = 11,
++};
++
++typedef struct netdump_req_s {
++      u64 magic;
++      u32 nr;
++      u32 command;
++      u32 from;
++      u32 to;
++} req_t;
++
++enum netdump_replies {
++      REPLY_NONE = 0,
++      REPLY_ERROR = 1,
++      REPLY_LOG = 2,
++      REPLY_MEM = 3,
++      REPLY_RESERVED = 4,
++      REPLY_HELLO = 5,
++      REPLY_NR_PAGES = 6,
++      REPLY_PAGE_SIZE = 7,
++      REPLY_START_NETDUMP = 8,
++      REPLY_END_NETDUMP = 9,
++      REPLY_REGS = 10,
++      REPLY_MAGIC = 11,
++      REPLY_START_WRITE_NETDUMP = 12,
++      REPLY_SYSRQ = 13,
++};
++
++typedef struct netdump_reply_s {
++      u32 nr;
++      u32 code;
++      u32 info;
++} reply_t;
++
++#define HEADER_LEN (1 + sizeof(reply_t))
++
++
+Index: linux-2.6.0-test5/include/asm-i386/dump.h
+===================================================================
+--- linux-2.6.0-test5.orig/include/asm-i386/dump.h     2003-09-26 14:26:34.000000000 +0800
++++ linux-2.6.0-test5/include/asm-i386/dump.h  2003-09-26 14:26:34.000000000 +0800
+@@ -0,0 +1,93 @@
++/*
++ * Kernel header file for Linux crash dumps.
++ *
++ * Created by: Matt Robinson (yakker@sgi.com)
++ *
++ * Copyright 1999 Silicon Graphics, Inc. All rights reserved.
++ *
++ * This code is released under version 2 of the GNU GPL.
++ */
++
++/* This header file holds the architecture specific crash dump header */
++#ifndef _ASM_DUMP_H
++#define _ASM_DUMP_H
++
++/* necessary header files */
++#include <asm/ptrace.h>
++#include <asm/page.h>
++#include <linux/threads.h>
++#include <linux/mm.h>
++
++/* definitions */
++#define DUMP_ASM_MAGIC_NUMBER 0xdeaddeadULL   /* magic number            */
++#define DUMP_ASM_VERSION_NUMBER       0x3     /* version number          */
++
++/* max number of cpus */
++#define DUMP_MAX_NUM_CPUS 32
++
++/*
++ * Structure: __dump_header_asm
++ *  Function: This is the header for architecture-specific stuff.  It
++ *            follows right after the dump header.
++ */
++struct __dump_header_asm {
++      /* the dump magic number -- unique to verify dump is valid */
++      u64             dha_magic_number;
++
++      /* the version number of this dump */
++      u32             dha_version;
++
++      /* the size of this header (in case we can't read it) */
++      u32             dha_header_size;
++
++      /* the esp for i386 systems */
++      u32             dha_esp;
++
++      /* the eip for i386 systems */
++      u32             dha_eip;
++
++      /* the dump registers */
++      struct pt_regs  dha_regs;
++
++      /* smp specific */
++      u32             dha_smp_num_cpus;
++      u32             dha_dumping_cpu;
++      struct pt_regs  dha_smp_regs[DUMP_MAX_NUM_CPUS];
++      u32             dha_smp_current_task[DUMP_MAX_NUM_CPUS];
++      u32             dha_stack[DUMP_MAX_NUM_CPUS];
++      u32             dha_stack_ptr[DUMP_MAX_NUM_CPUS];
++} __attribute__((packed));
++
++#ifdef __KERNEL__
++
++extern struct __dump_header_asm dump_header_asm;
++
++#ifdef CONFIG_SMP
++extern cpumask_t irq_affinity[];
++extern int (*dump_ipi_function_ptr)(struct pt_regs *);
++extern void dump_send_ipi(void);
++#else
++#define dump_send_ipi() do { } while(0)
++#endif
++
++static inline void get_current_regs(struct pt_regs *regs)
++{
++      __asm__ __volatile__("movl %%ebx,%0" : "=m"(regs->ebx));
++      __asm__ __volatile__("movl %%ecx,%0" : "=m"(regs->ecx));
++      __asm__ __volatile__("movl %%edx,%0" : "=m"(regs->edx));
++      __asm__ __volatile__("movl %%esi,%0" : "=m"(regs->esi));
++      __asm__ __volatile__("movl %%edi,%0" : "=m"(regs->edi));
++      __asm__ __volatile__("movl %%ebp,%0" : "=m"(regs->ebp));
++      __asm__ __volatile__("movl %%eax,%0" : "=m"(regs->eax));
++      __asm__ __volatile__("movl %%esp,%0" : "=m"(regs->esp));
++      __asm__ __volatile__("movw %%ss, %%ax;" :"=a"(regs->xss));
++      __asm__ __volatile__("movw %%cs, %%ax;" :"=a"(regs->xcs));
++      __asm__ __volatile__("movw %%ds, %%ax;" :"=a"(regs->xds));
++      __asm__ __volatile__("movw %%es, %%ax;" :"=a"(regs->xes));
++      __asm__ __volatile__("pushfl; popl %0" :"=m"(regs->eflags));
++      regs->eip = (unsigned long)current_text_addr();
++}
++
++#endif /* __KERNEL__ */
++
++#endif /* _ASM_DUMP_H */
+Index: linux-2.6.0-test5/init/kerntypes.c
+===================================================================
+--- linux-2.6.0-test5.orig/init/kerntypes.c    2003-09-26 14:26:34.000000000 +0800
++++ linux-2.6.0-test5/init/kerntypes.c 2003-09-26 14:26:34.000000000 +0800
+@@ -0,0 +1,31 @@
++/*
++ * kerntypes.c
++ *
++ * Copyright (C) 2000 Tom Morano (tjm@sgi.com) and
++ *                    Matt D. Robinson (yakker@alacritech.com)
++ *
++ * Dummy module that includes headers for all kernel types of interest. 
++ * The kernel type information is used by the lcrash utility when 
++ * analyzing system crash dumps or the live system. Using the type 
++ * information for the running system, rather than kernel header files,
++ * makes for a more flexible and robust analysis tool.
++ *
++ * This source code is released under version 2 of the GNU GPL.
++ */
++
++#include <linux/compile.h>
++#include <linux/module.h>
++#include <linux/mm.h>
++#include <linux/config.h>
++#include <linux/utsname.h>
++#include <linux/dump.h>
++
++#ifdef LINUX_COMPILE_VERSION_ID_TYPE
++/* Define version type for version validation of dump and kerntypes */
++LINUX_COMPILE_VERSION_ID_TYPE;
++#endif
++
++void
++kerntypes_dummy(void)
++{
++}
+Index: linux-2.6.0-test5/drivers/dump/dump_methods.h
+===================================================================
+--- linux-2.6.0-test5.orig/drivers/dump/dump_methods.h 2003-09-26 14:26:34.000000000 +0800
++++ linux-2.6.0-test5/drivers/dump/dump_methods.h      2003-09-26 14:26:34.000000000 +0800
+@@ -0,0 +1,348 @@
++/*
++ * Generic interfaces for flexible system dump 
++ *
++ * Started: Oct 2002 -  Suparna Bhattacharya (suparna@in.ibm.com)
++ *
++ * Copyright (C) 2002 International Business Machines Corp. 
++ *
++ * This code is released under version 2 of the GNU GPL.
++ */
++
++#ifndef _LINUX_DUMP_METHODS_H
++#define _LINUX_DUMP_METHODS_H
++
++/*
++ * Inspired by Matt Robinson's suggestion of introducing dump 
++ * methods as a way to enable different crash dump facilities to 
++ * coexist where each employs its own scheme or dumping policy.
++ *
++ * The code here creates a framework for flexible dump by defining 
++ * a set of methods and providing associated helpers that differentiate
++ * between the underlying mechanism (how to dump), overall scheme 
++ * (sequencing of stages and data dumped and associated quiescing), 
++ * output format (what the dump output looks like), target type 
++ * (where to save the dump; see dumpdev.h), and selection policy 
++ * (state/data to dump).
++ * 
++ * These sets of interfaces can be mixed and matched to build a 
++ * dumper suitable for a given situation, allowing for 
++ * flexibility as well appropriate degree of code reuse.
++ * For example all features and options of lkcd (including
++ * granular selective dumping in the near future) should be
++ * available even when say, the 2 stage soft-boot based mechanism 
++ * is used for taking disruptive dumps.
++ *
++ * Todo: Additionally modules or drivers may supply their own
++ * custom dumpers which extend dump with module specific
++ * information or hardware state, and can even tweak the
++ * mechanism when it comes to saving state relevant to
++ * them.
++ */
++
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/highmem.h>
++#include <linux/dumpdev.h>
++
++#define MAX_PASSES    6
++#define MAX_DEVS      4
++
++
++/* To customise selection of pages to be dumped in a given pass/group */
++struct dump_data_filter{
++      char name[32];
++      int (*selector)(int, unsigned long, unsigned long);
++      ulong level_mask; /* dump level(s) for which this filter applies */
++      loff_t start, end; /* location range applicable */
++};
++
++
++/* 
++ * Determined by the kind of dump mechanism and appropriate 
++ * overall scheme 
++ */ 
++struct dump_scheme_ops {
++      /* sets aside memory, inits data structures etc */
++      int (*configure)(unsigned long devid); 
++      /* releases  resources */
++      int (*unconfigure)(void); 
++
++      /* ordering of passes, invoking iterator */
++      int (*sequencer)(void); 
++        /* iterates over system data, selects and acts on data to dump */
++      int (*iterator)(int, int (*)(unsigned long, unsigned long), 
++              struct dump_data_filter *); 
++        /* action when data is selected for dump */
++      int (*save_data)(unsigned long, unsigned long); 
++        /* action when data is to be excluded from dump */
++      int (*skip_data)(unsigned long, unsigned long); 
++      /* policies for space, multiple dump devices etc */
++      int (*write_buffer)(void *, unsigned long); 
++};
++
++struct dump_scheme {
++      /* the name serves as an anchor to locate the scheme after reboot */
++      char name[32]; 
++      struct dump_scheme_ops *ops;
++      struct list_head list;
++};
++
++/* Quiescing/Silence levels (controls IPI callback behaviour) */
++extern enum dump_silence_levels {
++      DUMP_SOFT_SPIN_CPUS     = 1,
++      DUMP_HARD_SPIN_CPUS     = 2,
++      DUMP_HALT_CPUS          = 3,
++} dump_silence_level;
++
++/* determined by the dump (file) format */
++struct dump_fmt_ops {
++      /* build header */
++      int (*configure_header)(const char *, const struct pt_regs *); 
++      int (*update_header)(void); /* update header and write it out */
++      /* save curr context  */
++      void (*save_context)(int, const struct pt_regs *, 
++              struct task_struct *); 
++      /* typically called by the save_data action */
++      /* add formatted data to the dump buffer */
++      int (*add_data)(unsigned long, unsigned long); 
++      int (*update_end_marker)(void);
++};
++
++struct dump_fmt {
++      unsigned long magic; 
++      char name[32];  /* lcrash, crash, elf-core etc */
++      struct dump_fmt_ops *ops;
++      struct list_head list;
++};
++
++/* 
++ * Modules will be able add their own data capture schemes by 
++ * registering their own dumpers. Typically they would use the 
++ * primary dumper as a template and tune it with their routines.
++ * Still Todo.
++ */
++
++/* The combined dumper profile (mechanism, scheme, dev, fmt) */
++struct dumper {
++      char name[32]; /* singlestage, overlay (stg1), passthru(stg2), pull */
++      struct dump_scheme *scheme;
++      struct dump_fmt *fmt;
++      struct __dump_compress *compress;
++      struct dump_data_filter *filter;
++      struct dump_dev *dev; 
++      /* state valid only for active dumper(s) - per instance */
++      /* run time state/context */
++      int curr_pass;
++      unsigned long count;
++      loff_t curr_offset; /* current logical offset into dump device */
++      loff_t curr_loc; /* current memory location */
++      void *curr_buf; /* current position in the dump buffer */
++      void *dump_buf; /* starting addr of dump buffer */
++      int header_dirty; /* whether the header needs to be written out */
++      int header_len; 
++      struct list_head dumper_list; /* links to other dumpers */
++};    
++
++/* Starting point to get to the current configured state */
++struct dump_config {
++      ulong level;
++      ulong flags;
++      struct dumper *dumper;
++      unsigned long dump_device;
++      unsigned long dump_addr; /* relevant only for in-memory dumps */
++      struct list_head dump_dev_list;
++};    
++
++extern struct dump_config dump_config;
++
++/* Used to save the dump config across a reboot for 2-stage dumps: 
++ * 
++ * Note: The scheme, format, compression and device type should be 
++ * registered at bootup, for this config to be sharable across soft-boot. 
++ * The function addresses could have changed and become invalid, and
++ * need to be set up again.
++ */
++struct dump_config_block {
++      u64 magic; /* for a quick sanity check after reboot */
++      struct dump_memdev memdev; /* handle to dump stored in memory */
++      struct dump_config config;
++      struct dumper dumper;
++      struct dump_scheme scheme;
++      struct dump_fmt fmt;
++      struct __dump_compress compress;
++      struct dump_data_filter filter_table[MAX_PASSES];
++      struct dump_anydev dev[MAX_DEVS]; /* target dump device */
++};
++
++
++/* Wrappers that invoke the methods for the current (active) dumper */
++
++/* Scheme operations */
++
++static inline int dump_sequencer(void)
++{
++      return dump_config.dumper->scheme->ops->sequencer();
++}
++
++static inline int dump_iterator(int pass, int (*action)(unsigned long, 
++      unsigned long), struct dump_data_filter *filter)
++{
++      return dump_config.dumper->scheme->ops->iterator(pass, action, filter);
++}
++
++#define dump_save_data dump_config.dumper->scheme->ops->save_data
++#define dump_skip_data dump_config.dumper->scheme->ops->skip_data
++
++static inline int dump_write_buffer(void *buf, unsigned long len)
++{
++      return dump_config.dumper->scheme->ops->write_buffer(buf, len);
++}
++
++static inline int dump_configure(unsigned long devid)
++{
++      return dump_config.dumper->scheme->ops->configure(devid);
++}
++
++static inline int dump_unconfigure(void)
++{
++      return dump_config.dumper->scheme->ops->unconfigure();
++}
++
++/* Format operations */
++
++static inline int dump_configure_header(const char *panic_str, 
++      const struct pt_regs *regs)
++{
++      return dump_config.dumper->fmt->ops->configure_header(panic_str, regs);
++}
++
++static inline void dump_save_context(int cpu, const struct pt_regs *regs, 
++              struct task_struct *tsk)
++{
++      dump_config.dumper->fmt->ops->save_context(cpu, regs, tsk);
++}
++
++static inline int dump_save_this_cpu(const struct pt_regs *regs)
++{
++      int cpu = smp_processor_id();
++
++      dump_save_context(cpu, regs, current);
++      return 1;
++}
++
++static inline int dump_update_header(void)
++{
++      return dump_config.dumper->fmt->ops->update_header();
++}
++
++static inline int dump_update_end_marker(void)
++{
++      return dump_config.dumper->fmt->ops->update_end_marker();
++}
++
++static inline int dump_add_data(unsigned long loc, unsigned long sz)
++{
++      return dump_config.dumper->fmt->ops->add_data(loc, sz);
++}
++
++/* Compression operation */
++static inline int dump_compress_data(char *src, int slen, char *dst)
++{
++      return dump_config.dumper->compress->compress_func(src, slen, 
++              dst, DUMP_DPC_PAGE_SIZE);
++}
++
++
++/* Prototypes of some default implementations of dump methods */
++
++extern struct __dump_compress dump_none_compression;
++
++/* Default scheme methods (dump_scheme.c) */
++
++extern int dump_generic_sequencer(void);
++extern int dump_page_iterator(int pass, int (*action)(unsigned long, unsigned
++      long), struct dump_data_filter *filter);
++extern int dump_generic_save_data(unsigned long loc, unsigned long sz);
++extern int dump_generic_skip_data(unsigned long loc, unsigned long sz);
++extern int dump_generic_write_buffer(void *buf, unsigned long len);
++extern int dump_generic_configure(unsigned long);
++extern int dump_generic_unconfigure(void);
++
++/* Default scheme template */
++extern struct dump_scheme dump_scheme_singlestage;
++
++/* Default dump format methods */
++
++extern int dump_lcrash_configure_header(const char *panic_str, 
++      const struct pt_regs *regs);
++extern void dump_lcrash_save_context(int  cpu, const struct pt_regs *regs, 
++      struct task_struct *tsk);
++extern int dump_generic_update_header(void);
++extern int dump_lcrash_add_data(unsigned long loc, unsigned long sz);
++extern int dump_lcrash_update_end_marker(void);
++
++/* Default format (lcrash) template */
++extern struct dump_fmt dump_fmt_lcrash;
++
++/* Default dump selection filter table */
++
++/* 
++ * Entries listed in order of importance and correspond to passes
++ * The last entry (with a level_mask of zero) typically reflects data that 
++ * won't be dumped  -- this may for example be used to identify data 
++ * that will be skipped for certain so the corresponding memory areas can be 
++ * utilized as scratch space.
++ */   
++extern struct dump_data_filter dump_filter_table[];
++
++/* Some pre-defined dumpers */
++extern struct dumper dumper_singlestage;
++extern struct dumper dumper_stage1;
++extern struct dumper dumper_stage2;
++
++/* These are temporary */
++#define DUMP_MASK_HEADER      DUMP_LEVEL_HEADER
++#define DUMP_MASK_KERN                DUMP_LEVEL_KERN
++#define DUMP_MASK_USED                DUMP_LEVEL_USED
++#define DUMP_MASK_UNUSED      DUMP_LEVEL_ALL_RAM
++#define DUMP_MASK_REST                0 /* dummy for now */
++
++/* Helpers - move these to dump.h later ? */
++
++int dump_generic_execute(const char *panic_str, const struct pt_regs *regs);
++extern int dump_ll_write(void *buf, unsigned long len); 
++int dump_check_and_free_page(struct dump_memdev *dev, struct page *page);
++
++static inline void dumper_reset(void)
++{
++      dump_config.dumper->curr_buf = dump_config.dumper->dump_buf;
++      dump_config.dumper->curr_loc = 0;
++      dump_config.dumper->curr_offset = 0;
++      dump_config.dumper->count = 0;
++      dump_config.dumper->curr_pass = 0;
++}
++
++/* 
++ * May later be moulded to perform boot-time allocations so we can dump 
++ * earlier during bootup 
++ */
++static inline void *dump_alloc_mem(unsigned long size)
++{
++      return kmalloc(size, GFP_KERNEL);
++}
++
++static inline void dump_free_mem(void *buf)
++{
++      struct page *page;
++
++      /* ignore reserved pages (e.g. post soft boot stage) */
++      if (buf && (page = virt_to_page(buf))) {
++              if (PageReserved(page))
++                      return;
++      }
++
++      kfree(buf);
++}
++
++
++#endif /*  _LINUX_DUMP_METHODS_H */
+Index: linux-2.6.0-test5/Makefile
+===================================================================
+--- linux-2.6.0-test5.orig/Makefile    2003-09-26 14:26:29.000000000 +0800
++++ linux-2.6.0-test5/Makefile 2003-09-26 14:26:34.000000000 +0800
+@@ -289,6 +289,10 @@
+ export MODVERDIR := .tmp_versions
++ifeq ($(CONFIG_CRASH_DUMP),)
++      CFLAGS += -g
++endif
++
+ # The temporary file to save gcc -MD generated dependencies must not
+ # contain a comma
+ comma := ,
diff --git a/lustre/kernel_patches/patches/lkcd-kernel-changes-2.6.0-test6.patch b/lustre/kernel_patches/patches/lkcd-kernel-changes-2.6.0-test6.patch
new file mode 100644 (file)
index 0000000..fa429d5
--- /dev/null
@@ -0,0 +1,615 @@
+ 0 files changed
+
+Index: linux-2.6.0-test6/drivers/Makefile
+===================================================================
+--- linux-2.6.0-test6.orig/drivers/Makefile    2003-09-28 08:50:41.000000000 +0800
++++ linux-2.6.0-test6/drivers/Makefile 2003-10-09 20:57:41.884807280 +0800
+@@ -49,3 +49,4 @@
+ obj-$(CONFIG_MCA)             += mca/
+ obj-$(CONFIG_EISA)            += eisa/
+ obj-$(CONFIG_CPU_FREQ)                += cpufreq/
++obj-$(CONFIG_CRASH_DUMP)      += dump/
+Index: linux-2.6.0-test6/include/linux/sysctl.h
+===================================================================
+--- linux-2.6.0-test6.orig/include/linux/sysctl.h      2003-10-09 20:52:02.839350024 +0800
++++ linux-2.6.0-test6/include/linux/sysctl.h   2003-10-09 20:57:41.885807128 +0800
+@@ -127,6 +127,7 @@
+       KERN_PANIC_ON_OOPS=57,  /* int: whether we will panic on an oops */
+       KERN_HPPA_PWRSW=58,     /* int: hppa soft-power enable */
+       KERN_HPPA_UNALIGNED=59, /* int: hppa unaligned-trap enable */
++      KERN_DUMP=60,           /* directory: dump parameters */
+ };
+Index: linux-2.6.0-test6/include/linux/major.h
+===================================================================
+--- linux-2.6.0-test6.orig/include/linux/major.h       2003-09-28 08:50:13.000000000 +0800
++++ linux-2.6.0-test6/include/linux/major.h    2003-10-09 20:57:41.885807128 +0800
+@@ -157,6 +157,8 @@
+ #define OSST_MAJOR            206     /* OnStream-SCx0 SCSI tape */
++#define CRASH_DUMP_MAJOR      221     /* crash dump interface */
++
+ #define IBM_TTY3270_MAJOR     227
+ #define IBM_FS3270_MAJOR      228
+Index: linux-2.6.0-test6/include/asm-i386/mach-default/irq_vectors.h
+===================================================================
+--- linux-2.6.0-test6.orig/include/asm-i386/mach-default/irq_vectors.h 2003-10-09 20:52:02.764361424 +0800
++++ linux-2.6.0-test6/include/asm-i386/mach-default/irq_vectors.h      2003-10-09 20:57:41.885807128 +0800
+@@ -48,6 +48,7 @@
+ #define INVALIDATE_TLB_VECTOR 0xfd
+ #define RESCHEDULE_VECTOR     0xfc
+ #define CALL_FUNCTION_VECTOR  0xfb
++#define DUMP_VECTOR           0xfa
+ #define THERMAL_APIC_VECTOR   0xf0
+ /*
+Index: linux-2.6.0-test6/include/asm-i386/kmap_types.h
+===================================================================
+--- linux-2.6.0-test6.orig/include/asm-i386/kmap_types.h       2003-10-09 20:52:02.764361424 +0800
++++ linux-2.6.0-test6/include/asm-i386/kmap_types.h    2003-10-09 20:57:41.886806976 +0800
+@@ -33,6 +33,7 @@
+        * Add new entries in pairs:
+        * the 4G/4G virtual stack must be 8K aligned on each cpu.
+        */
+-      KM_TYPE_NR
++      KM_DUMP,
++      KM_TYPE_NR,
+ };
+ #endif
+Index: linux-2.6.0-test6/include/asm-i386/smp.h
+===================================================================
+--- linux-2.6.0-test6.orig/include/asm-i386/smp.h      2003-09-28 08:50:29.000000000 +0800
++++ linux-2.6.0-test6/include/asm-i386/smp.h   2003-10-09 20:57:41.886806976 +0800
+@@ -37,6 +37,7 @@
+ extern int cpu_sibling_map[];
+ extern void smp_flush_tlb(void);
++extern void dump_send_ipi(void);
+ extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs);
+ extern void smp_send_reschedule(int cpu);
+ extern void smp_invalidate_rcv(void);         /* Process an NMI */
+Index: linux-2.6.0-test6/arch/i386/kernel/i386_ksyms.c
+===================================================================
+--- linux-2.6.0-test6.orig/arch/i386/kernel/i386_ksyms.c       2003-10-09 20:56:19.104391816 +0800
++++ linux-2.6.0-test6/arch/i386/kernel/i386_ksyms.c    2003-10-09 20:58:33.601945080 +0800
+@@ -16,6 +16,7 @@
+ #include <linux/tty.h>
+ #include <linux/highmem.h>
+ #include <linux/time.h>
++#include <linux/nmi.h>
+ #include <asm/semaphore.h>
+ #include <asm/processor.h>
+@@ -34,6 +35,7 @@
+ #include <asm/nmi.h>
+ #include <asm/edd.h>
+ #include <asm/ist.h>
++#include <asm/e820.h>
+ #include <asm/netconsole.h>
+ extern void dump_thread(struct pt_regs *, struct user *);
+ extern spinlock_t rtc_lock;
+@@ -220,3 +222,20 @@
+ #if defined(CONFIG_X86_SPEEDSTEP_SMI) || defined(CONFIG_X86_SPEEDSTEP_SMI_MODULE)
+ EXPORT_SYMBOL(ist_info);
+ #endif
++
++#ifdef CONFIG_CRASH_DUMP_MODULE
++#ifdef CONFIG_SMP
++extern irq_desc_t irq_desc[NR_IRQS];
++extern unsigned long irq_affinity[NR_IRQS];
++extern void stop_this_cpu(void *);
++EXPORT_SYMBOL(irq_desc);
++EXPORT_SYMBOL(irq_affinity);
++EXPORT_SYMBOL(stop_this_cpu);
++EXPORT_SYMBOL(dump_send_ipi);
++#endif
++extern int pfn_is_ram(unsigned long);
++EXPORT_SYMBOL(pfn_is_ram);
++#ifdef ARCH_HAS_NMI_WATCHDOG
++EXPORT_SYMBOL(touch_nmi_watchdog);
++#endif
++#endif
+Index: linux-2.6.0-test6/arch/i386/kernel/nmi.c
+===================================================================
+--- linux-2.6.0-test6.orig/arch/i386/kernel/nmi.c      2003-10-09 20:52:02.026473600 +0800
++++ linux-2.6.0-test6/arch/i386/kernel/nmi.c   2003-10-09 20:57:41.887806824 +0800
+@@ -24,6 +24,7 @@
+ #include <linux/kernel_stat.h>
+ #include <linux/module.h>
+ #include <linux/nmi.h>
++#include <linux/dump.h>
+ #include <linux/sysdev.h>
+ #include <asm/smp.h>
+@@ -460,6 +461,7 @@
+                       bust_spinlocks(1);
+                       printk("NMI Watchdog detected LOCKUP on CPU%d, eip %08lx, registers:\n", cpu, regs->eip);
+                       show_registers(regs);
++                      dump("NMI Watchdog detected LOCKUP", regs);
+                       printk("console shuts up ...\n");
+                       console_silent();
+                       spin_unlock(&nmi_print_lock);
+Index: linux-2.6.0-test6/arch/i386/kernel/setup.c
+===================================================================
+--- linux-2.6.0-test6.orig/arch/i386/kernel/setup.c    2003-10-09 20:52:02.028473296 +0800
++++ linux-2.6.0-test6/arch/i386/kernel/setup.c 2003-10-09 20:57:41.888806672 +0800
+@@ -471,6 +471,7 @@
+       print_memory_map(who);
+ } /* setup_memory_region */
++unsigned long crashdump_addr = 0xdeadbeef;
+ static void __init parse_cmdline_early (char ** cmdline_p)
+ {
+@@ -588,6 +589,9 @@
+               if (c == ' ' && !memcmp(from, "highmem=", 8))
+                       highmem_pages = memparse(from+8, &from) >> PAGE_SHIFT;
+       
++              if (c == ' ' && !memcmp(from, "crashdump=", 10))
++                      crashdump_addr = memparse(from+10, &from); 
++                      
+               c = *(from++);
+               if (!c)
+                       break;
+@@ -1030,6 +1034,8 @@
+ __setup("noreplacement", noreplacement_setup); 
++extern void crashdump_reserve(void);
++ 
+ /*
+  * Determine if we were loaded by an EFI loader.  If so, then we have also been
+  * passed the efi memmap, systab, etc., so we should use these data structures
+Index: linux-2.6.0-test6/arch/i386/kernel/smp.c
+===================================================================
+--- linux-2.6.0-test6.orig/arch/i386/kernel/smp.c      2003-10-09 20:52:02.031472840 +0800
++++ linux-2.6.0-test6/arch/i386/kernel/smp.c   2003-10-09 20:57:41.889806520 +0800
+@@ -19,6 +19,7 @@
+ #include <linux/mc146818rtc.h>
+ #include <linux/cache.h>
+ #include <linux/interrupt.h>
++#include <linux/dump.h>
+ #include <asm/mtrr.h>
+ #include <asm/pgalloc.h>
+@@ -144,6 +145,13 @@
+        */
+       cfg = __prepare_ICR(shortcut, vector);
++      if (vector == DUMP_VECTOR) {
++              /*
++               * Setup DUMP IPI to be delivered as an NMI
++               */
++              cfg = (cfg&~APIC_VECTOR_MASK)|APIC_DM_NMI;
++      }
++
+       /*
+        * Send the IPI. The write to APIC_ICR fires this off.
+        */
+@@ -477,6 +485,11 @@
+       send_IPI_mask(cpumask_of_cpu(cpu), RESCHEDULE_VECTOR);
+ }
++void dump_send_ipi(void)
++{
++      send_IPI_allbutself(DUMP_VECTOR);
++}
++
+ /*
+  * Structure and data for smp_call_function(). This is designed to minimise
+  * static memory requirements. It also looks cleaner.
+@@ -545,7 +558,7 @@
+       return 0;
+ }
+-static void stop_this_cpu (void * dummy)
++void stop_this_cpu (void * dummy)
+ {
+       /*
+        * Remove this CPU:
+@@ -606,4 +619,3 @@
+               atomic_inc(&call_data->finished);
+       }
+ }
+-
+Index: linux-2.6.0-test6/arch/i386/kernel/traps.c
+===================================================================
+--- linux-2.6.0-test6.orig/arch/i386/kernel/traps.c    2003-10-09 20:52:02.033472536 +0800
++++ linux-2.6.0-test6/arch/i386/kernel/traps.c 2003-10-09 20:57:41.889806520 +0800
+@@ -25,6 +25,7 @@
+ #include <linux/highmem.h>
+ #include <linux/kallsyms.h>
+ #include <linux/ptrace.h>
++#include <linux/dump.h>
+ #ifdef CONFIG_EISA
+ #include <linux/ioport.h>
+@@ -322,6 +323,7 @@
+ #endif
+       CHK_REMOTE_DEBUG(0,SIGTRAP,err,regs,)
+       show_registers(regs);
++      dump((char *)str, regs);
+       bust_spinlocks(0);
+       spin_unlock_irq(&die_lock);
+       if (in_interrupt())
+Index: linux-2.6.0-test6/arch/i386/mm/init.c
+===================================================================
+--- linux-2.6.0-test6.orig/arch/i386/mm/init.c 2003-10-09 20:52:02.041471320 +0800
++++ linux-2.6.0-test6/arch/i386/mm/init.c      2003-10-09 20:57:41.890806368 +0800
+@@ -115,6 +115,12 @@
+               SetPageReserved(page);
+ }
++/* To enable modules to check if a page is in RAM */
++int pfn_is_ram(unsigned long pfn)
++{
++      return (page_is_ram(pfn));
++}
++
+ #ifdef CONFIG_HIGHMEM
+ #ifndef CONFIG_DISCONTIGMEM
+Index: linux-2.6.0-test6/arch/i386/boot/Makefile
+===================================================================
+--- linux-2.6.0-test6.orig/arch/i386/boot/Makefile     2003-09-28 08:50:16.000000000 +0800
++++ linux-2.6.0-test6/arch/i386/boot/Makefile  2003-10-09 20:57:41.890806368 +0800
+@@ -100,3 +100,4 @@
+ install: $(BOOTIMAGE)
+       sh $(srctree)/$(src)/install.sh $(KERNELRELEASE) $< System.map "$(INSTALL_PATH)"
++      if [ -f init/kerntypes.o ]; then cp init/kerntypes.o $(INSTALL_PATH)/Kerntypes; fi
+Index: linux-2.6.0-test6/arch/i386/Kconfig
+===================================================================
+--- linux-2.6.0-test6.orig/arch/i386/Kconfig   2003-10-09 20:52:01.999477704 +0800
++++ linux-2.6.0-test6/arch/i386/Kconfig        2003-10-09 20:57:41.891806216 +0800
+@@ -1239,6 +1239,56 @@
+ menu "Kernel hacking"
++config CRASH_DUMP
++      tristate "Crash dump support (EXPERIMENTAL)"
++      depends on EXPERIMENTAL
++      default n
++      ---help---
++        Say Y here to enable saving an image of system memory when a panic
++        or other error occurs. Dumps can also be forced with the SysRq+d
++        key if MAGIC_SYSRQ is enabled.
++
++config CRASH_DUMP_BLOCKDEV
++      tristate "Crash dump block device driver"
++      depends on CRASH_DUMP
++      help
++        Say Y to allow saving crash dumps directly to a disk device.
++
++config CRASH_DUMP_NETDEV
++      tristate "Crash dump network device driver"
++      depends on CRASH_DUMP
++      help
++        Say Y to allow saving crash dumps over a network device.
++
++config CRASH_DUMP_MEMDEV
++      bool "Crash dump staged memory driver"
++      depends on CRASH_DUMP
++      help
++        Say Y to allow intermediate saving crash dumps in spare 
++        memory pages which would then be written out to disk
++        later.
++
++config CRASH_DUMP_SOFTBOOT
++      bool "Save crash dump across a soft reboot"
++      depends on CRASH_DUMP_MEMDEV
++      help
++        Say Y to allow a crash dump to be preserved in memory
++        pages across a soft reboot and written out to disk
++        thereafter. For this to work, CRASH_DUMP must be 
++        configured as part of the kernel (not as a module).
++
++config CRASH_DUMP_COMPRESS_RLE
++      tristate "Crash dump RLE compression"
++      depends on CRASH_DUMP
++      help
++        Say Y to allow saving dumps with Run Length Encoding compression.
++
++config CRASH_DUMP_COMPRESS_GZIP
++      tristate "Crash dump GZIP compression"
++      depends on CRASH_DUMP
++      help
++        Say Y to allow saving dumps with Gnu Zip compression.
++
+ config DEBUG_KERNEL
+       bool "Kernel debugging"
+       help
+Index: linux-2.6.0-test6/arch/s390/boot/Makefile
+===================================================================
+--- linux-2.6.0-test6.orig/arch/s390/boot/Makefile     2003-09-28 08:51:21.000000000 +0800
++++ linux-2.6.0-test6/arch/s390/boot/Makefile  2003-10-09 20:57:41.892806064 +0800
+@@ -15,4 +15,4 @@
+ install: $(CONFIGURE) $(obj)/image
+       sh -x $(obj)/install.sh $(KERNELRELEASE) $(obj)/image \
+-            System.map Kerntypes "$(INSTALL_PATH)"
++            System.map init/kerntypes.o "$(INSTALL_PATH)"
+Index: linux-2.6.0-test6/arch/s390/boot/install.sh
+===================================================================
+--- linux-2.6.0-test6.orig/arch/s390/boot/install.sh   2003-09-28 08:50:30.000000000 +0800
++++ linux-2.6.0-test6/arch/s390/boot/install.sh        2003-10-09 20:57:41.892806064 +0800
+@@ -16,7 +16,8 @@
+ #   $1 - kernel version
+ #   $2 - kernel image file
+ #   $3 - kernel map file
+-#   $4 - default install path (blank if root directory)
++#   $4 - kernel type file
++#   $5 - default install path (blank if root directory)
+ #
+ # User may have a custom install script
+@@ -26,13 +27,22 @@
+ # Default install - same as make zlilo
+-if [ -f $4/vmlinuz ]; then
+-      mv $4/vmlinuz $4/vmlinuz.old
++if [ -f $5/vmlinuz ]; then
++      mv $5/vmlinuz $5/vmlinuz.old
+ fi
+-if [ -f $4/System.map ]; then
+-      mv $4/System.map $4/System.old
++if [ -f $5/System.map ]; then
++      mv $5/System.map $5/System.old
+ fi
+-cat $2 > $4/vmlinuz
+-cp $3 $4/System.map
++if [ -f $5/Kerntypes ]; then
++      mv $5/Kerntypes $5/Kerntypes.old
++fi
++
++cat $2 > $5/vmlinuz
++cp $3 $5/System.map
++
++# copy the kernel type file if it exists
++if [ -f $4 ]; then
++      cp $4 $5/Kerntypes
++fi
+Index: linux-2.6.0-test6/scripts/mkcompile_h
+===================================================================
+--- linux-2.6.0-test6.orig/scripts/mkcompile_h 2003-09-28 08:51:28.000000000 +0800
++++ linux-2.6.0-test6/scripts/mkcompile_h      2003-10-09 20:57:41.892806064 +0800
+@@ -33,7 +33,7 @@
+ UTS_LEN=64
+ UTS_TRUNCATE="sed -e s/\(.\{1,$UTS_LEN\}\).*/\1/"
+-
++LINUX_COMPILE_VERSION_ID="__linux_compile_version_id__`hostname | tr -c '[0-9A-Za-z\n]' '__'`_`LANG=C date | tr -c '[0-9A-Za-z\n]' '_'`"
+ # Generate a temporary compile.h
+ ( echo /\* This file is auto generated, version $VERSION \*/
+@@ -55,6 +55,8 @@
+   fi
+   echo \#define LINUX_COMPILER \"`$CC -v 2>&1 | tail -n 1`\"
++  echo \#define LINUX_COMPILE_VERSION_ID $LINUX_COMPILE_VERSION_ID
++  echo \#define LINUX_COMPILE_VERSION_ID_TYPE typedef char* "$LINUX_COMPILE_VERSION_ID""_t"
+ ) > .tmpcompile
+ # Only replace the real compile.h if the new one is different,
+Index: linux-2.6.0-test6/kernel/ksyms.c
+===================================================================
+--- linux-2.6.0-test6.orig/kernel/ksyms.c      2003-10-09 20:52:02.855347592 +0800
++++ linux-2.6.0-test6/kernel/ksyms.c   2003-10-09 20:57:41.893805912 +0800
+@@ -58,6 +58,8 @@
+ #include <linux/backing-dev.h>
+ #include <linux/percpu_counter.h>
+ #include <asm/checksum.h>
++#include <linux/dump.h>
++#include <linux/bootmem.h>
+ #if defined(CONFIG_PROC_FS)
+ #include <linux/proc_fs.h>
+@@ -378,3 +380,9 @@
+ EXPORT_SYMBOL(console_printk);
+ EXPORT_SYMBOL(current_kernel_time);
++
++#ifdef CONFIG_CRASH_DUMP_MODULE
++EXPORT_SYMBOL(min_low_pfn);
++EXPORT_SYMBOL(dump_oncpu);
++EXPORT_SYMBOL(dump_function_ptr);
++#endif
+Index: linux-2.6.0-test6/kernel/panic.c
+===================================================================
+--- linux-2.6.0-test6.orig/kernel/panic.c      2003-09-28 08:51:05.000000000 +0800
++++ linux-2.6.0-test6/kernel/panic.c   2003-10-09 20:57:41.893805912 +0800
+@@ -18,11 +18,16 @@
+ #include <linux/interrupt.h>
+ #include <linux/nmi.h>
++#ifdef CONFIG_KEXEC
++#include <linux/kexec.h>
++#endif
++
+ asmlinkage void sys_sync(void);       /* it's really int */
+ int panic_timeout;
+ int panic_on_oops;
+ int tainted;
++void (*dump_function_ptr)(const char *, const struct pt_regs *) = 0;
+ struct notifier_block *panic_notifier_list;
+@@ -55,6 +60,7 @@
+       va_start(args, fmt);
+       vsnprintf(buf, sizeof(buf), fmt, args);
+       va_end(args);
++
+       printk(KERN_EMERG "Kernel panic: %s\n",buf);
+       if (in_interrupt())
+               printk(KERN_EMERG "In interrupt handler - not syncing\n");
+@@ -78,6 +84,19 @@
+                * We can't use the "normal" timers since we just panicked..
+                */
+               printk(KERN_EMERG "Rebooting in %d seconds..",panic_timeout);
++#ifdef CONFIG_KEXEC
++              {
++                      struct kimage *image;
++                      image = xchg(&kexec_image, 0);
++                      if (image) {
++                              printk(KERN_EMERG "by starting a new kernel ..\n");
++                              mdelay(panic_timeout*1000);
++                              machine_kexec(image);
++                      }
++              }
++#endif
++ 
++
+               for (i = 0; i < panic_timeout; i++) {
+                       touch_nmi_watchdog();
+                       mdelay(1000);
+Index: linux-2.6.0-test6/kernel/sched.c
+===================================================================
+--- linux-2.6.0-test6.orig/kernel/sched.c      2003-10-09 20:52:02.864346224 +0800
++++ linux-2.6.0-test6/kernel/sched.c   2003-10-09 20:57:41.895805608 +0800
+@@ -44,6 +44,9 @@
+ #define cpu_to_node_mask(cpu) (cpu_online_map)
+ #endif
++/* used to soft spin in sched while dump is in progress */
++int dump_oncpu;
++
+ /*
+  * Convert user-nice values [ -20 ... 0 ... 19 ]
+  * to static priority [ MAX_RT_PRIO..MAX_PRIO-1 ],
+@@ -1463,6 +1466,15 @@
+       unsigned long run_time;
+       int idx;
++      /*
++       * If crash dump is in progress, this other cpu's
++       * need to wait until it completes.
++       * NB: this code is optimized away for kernels without
++       * dumping enabled.
++       */
++      if (unlikely(dump_oncpu))
++              goto dump_scheduling_disabled;
++
+       /*
+        * Test if we are atomic.  Since do_exit() needs to call into
+        * schedule() atomically, we ignore that path for now.
+@@ -1586,6 +1598,16 @@
+       preempt_enable_no_resched();
+       if (test_thread_flag(TIF_NEED_RESCHED))
+               goto need_resched;
++
++      return;
++
++ dump_scheduling_disabled:
++      /* allow scheduling only if this is the dumping cpu */
++      if (dump_oncpu != smp_processor_id()+1) {
++              while (dump_oncpu)
++                      cpu_relax();
++      }
++      return;
+ }
+ EXPORT_SYMBOL(schedule);
+Index: linux-2.6.0-test6/lib/Kconfig
+===================================================================
+--- linux-2.6.0-test6.orig/lib/Kconfig 2003-09-28 08:50:29.000000000 +0800
++++ linux-2.6.0-test6/lib/Kconfig      2003-10-09 20:57:41.895805608 +0800
+@@ -16,10 +16,17 @@
+ # compression support is select'ed if needed
+ #
+ config ZLIB_INFLATE
+-      tristate
++      tristate
++      default y if CRAMFS=y || PPP_DEFLATE=y || JFFS2_FS=y || ZISOFS_FS=y || BINFMT_ZFLAT=y || CRYPTO_DEFLATE=y || CRASH_DUMP_COMPRESS_GZIP=y
++      default m if CRAMFS=m || PPP_DEFLATE=m || JFFS2_FS=m || ZISOFS_FS=m || BINFMT_ZFLAT=m || CRYPTO_DEFLATE=m || CRASH_DUMP_COMPRESS_GZIP=m
+ config ZLIB_DEFLATE
+       tristate
+-
++      default m if PPP_DEFLATE!=y && JFFS2_FS!=y && CRYPTO_DEFLATE!=y && \
++              (PPP_DEFLATE=m || JFFS2_FS=m || CRYPTO_DEFLATE=m \
++                      || CRASH_DUMP_COMPRESS_GZIP=m )
++      default y if PPP_DEFLATE=y || JFFS2_FS=y || CRYPTO_DEFLATE=y \
++              || CRASH_DUMP_COMPRESS_GZIP=y
++ 
+ endmenu
+Index: linux-2.6.0-test6/mm/page_alloc.c
+===================================================================
+--- linux-2.6.0-test6.orig/mm/page_alloc.c     2003-10-09 20:52:02.881343640 +0800
++++ linux-2.6.0-test6/mm/page_alloc.c  2003-10-09 20:57:41.897805304 +0800
+@@ -89,7 +89,8 @@
+       page->mapping = NULL;
+ }
+-#ifndef CONFIG_HUGETLB_PAGE
++#if !defined(CONFIG_HUGETLB_PAGE) && !defined(CONFIG_CRASH_DUMP) \
++      && !defined(CONFIG_CRASH_DUMP_MODULE)
+ #define prep_compound_page(page, order) do { } while (0)
+ #define destroy_compound_page(page, order) do { } while (0)
+ #else
+Index: linux-2.6.0-test6/init/Makefile
+===================================================================
+--- linux-2.6.0-test6.orig/init/Makefile       2003-09-28 08:50:17.000000000 +0800
++++ linux-2.6.0-test6/init/Makefile    2003-10-09 20:57:41.897805304 +0800
+@@ -9,6 +9,9 @@
+ mounts-$(CONFIG_BLK_DEV_INITRD)       += do_mounts_initrd.o
+ mounts-$(CONFIG_BLK_DEV_MD)   += do_mounts_md.o
++extra-$(CONFIG_CRASH_DUMP)    += kerntypes.o
++CFLAGS_kerntypes.o            := -gstabs
++
+ # files to be removed upon make clean
+ clean-files := ../include/linux/compile.h
+@@ -24,3 +27,4 @@
+ include/linux/compile.h: FORCE
+       @echo '  CHK     $@'
+       @sh $(srctree)/scripts/mkcompile_h $@ "$(UTS_MACHINE)" "$(CONFIG_SMP)" "$(CC) $(CFLAGS)"
++
+Index: linux-2.6.0-test6/init/main.c
+===================================================================
+--- linux-2.6.0-test6.orig/init/main.c 2003-10-09 20:52:02.850348352 +0800
++++ linux-2.6.0-test6/init/main.c      2003-10-09 20:57:41.897805304 +0800
+@@ -97,6 +97,16 @@
+ int system_running = 0;
+ /*
++ * The kernel_magic value represents the address of _end, which allows
++ * namelist tools to "match" each other respectively.  That way a tool
++ * that looks at /dev/mem can verify that it is using the right System.map
++ * file -- if kernel_magic doesn't equal the namelist value of _end,
++ * something's wrong.
++ */
++extern unsigned long _end;
++unsigned long *kernel_magic = &_end;
++
++/*
+  * Boot command-line arguments
+  */
+ #define MAX_INIT_ARGS 8
+Index: linux-2.6.0-test6/init/version.c
+===================================================================
+--- linux-2.6.0-test6.orig/init/version.c      2003-09-28 08:50:20.000000000 +0800
++++ linux-2.6.0-test6/init/version.c   2003-10-09 20:57:41.898805152 +0800
+@@ -10,6 +10,7 @@
+ #include <linux/uts.h>
+ #include <linux/utsname.h>
+ #include <linux/version.h>
++#include <linux/stringify.h>
+ #define version(a) Version_ ## a
+ #define version_string(a) version(a)
+@@ -28,3 +29,6 @@
+ const char *linux_banner = 
+       "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@"
+       LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n";
++
++const char *LINUX_COMPILE_VERSION_ID = __stringify(LINUX_COMPILE_VERSION_ID);
++LINUX_COMPILE_VERSION_ID_TYPE;
diff --git a/lustre/kernel_patches/patches/nfs_export_kernel-2.4.20-hp.patch b/lustre/kernel_patches/patches/nfs_export_kernel-2.4.20-hp.patch
new file mode 100644 (file)
index 0000000..ea4734e
--- /dev/null
@@ -0,0 +1,741 @@
+ fs/Makefile        |    3 
+ fs/file_table.c    |   11 ++
+ fs/inode.c         |   23 ++++-
+ fs/namei.c         |   12 ++
+ fs/nfsd/export.c   |    5 +
+ fs/nfsd/nfsfh.c    |   65 +++++++++++++-
+ fs/nfsd/vfs.c      |  240 ++++++++++++++++++++++++++++++++++++++++++++++++-----
+ include/linux/fs.h |   10 ++
+ kernel/ksyms.c     |    2 
+ 9 files changed, 337 insertions(+), 34 deletions(-)
+
+--- linux-2.4.20-hp4-pnnl13/fs/file_table.c~nfs_export_kernel-2.4.20-hp        2002-11-29 02:53:15.000000000 +0300
++++ linux-2.4.20-hp4-pnnl13-alexey/fs/file_table.c     2003-10-08 10:54:08.000000000 +0400
+@@ -82,7 +82,8 @@ struct file * get_empty_filp(void)
+  * and call the open function (if any).  The caller must verify that
+  * inode->i_fop is not NULL.
+  */
+-int init_private_file(struct file *filp, struct dentry *dentry, int mode)
++int init_private_file_it(struct file *filp, struct dentry *dentry, int mode,
++                         struct lookup_intent *it)
+ {
+       memset(filp, 0, sizeof(*filp));
+       filp->f_mode   = mode;
+@@ -90,12 +91,20 @@ int init_private_file(struct file *filp,
+       filp->f_dentry = dentry;
+       filp->f_uid    = current->fsuid;
+       filp->f_gid    = current->fsgid;
++      if (it)
++              filp->f_it = it;
+       filp->f_op     = dentry->d_inode->i_fop;
+       if (filp->f_op->open)
+               return filp->f_op->open(dentry->d_inode, filp);
+       else
+               return 0;
+ }
++EXPORT_SYMBOL(init_private_file_it);
++
++int init_private_file(struct file *filp, struct dentry *dentry, int mode)
++{
++      return init_private_file_it(filp, dentry, mode, NULL);
++}
+ void fput(struct file * file)
+ {
+--- linux-2.4.20-hp4-pnnl13/fs/inode.c~nfs_export_kernel-2.4.20-hp     2003-09-14 17:34:20.000000000 +0400
++++ linux-2.4.20-hp4-pnnl13-alexey/fs/inode.c  2003-10-08 11:38:11.000000000 +0400
+@@ -964,9 +964,10 @@ struct inode *igrab(struct inode *inode)
+       return inode;
+ }
+-struct inode *iget4_locked(struct super_block *sb, unsigned long ino, find_inode_t find_actor, void *opaque)
++struct inode *ifind(struct super_block *sb, unsigned long ino,
++                              struct list_head *head,
++                              find_inode_t find_actor, void *opaque)
+ {
+-      struct list_head * head = inode_hashtable + hash(sb,ino);
+       struct inode * inode;
+       spin_lock(&inode_lock);
+@@ -979,6 +980,24 @@ struct inode *iget4_locked(struct super_
+       }
+       spin_unlock(&inode_lock);
++      return NULL;
++}
++
++struct inode *ilookup4(struct super_block *sb, unsigned long ino,
++                       find_inode_t find_actor, void *opaque)
++{
++      struct list_head * head = inode_hashtable + hash(sb,ino);
++      return ifind(sb, ino, head, find_actor, opaque);
++}
++
++struct inode *iget4_locked(struct super_block *sb, unsigned long ino,
++                    find_inode_t find_actor, void *opaque)
++{
++      struct list_head * head = inode_hashtable + hash(sb,ino);
++      struct inode *inode = ifind(sb, ino, head, find_actor, opaque);
++      if (inode)
++              return inode;
++
+       /*
+        * get_new_inode() will do the right thing, re-trying the search
+        * in case it had to block at any point.
+--- linux-2.4.20-hp4-pnnl13/fs/Makefile~nfs_export_kernel-2.4.20-hp    2003-09-14 17:34:22.000000000 +0400
++++ linux-2.4.20-hp4-pnnl13-alexey/fs/Makefile 2003-10-08 10:54:37.000000000 +0400
+@@ -7,7 +7,8 @@
+ O_TARGET := fs.o
+-export-objs :=        filesystems.o open.o dcache.o buffer.o dquot.o inode.o
++export-objs :=        filesystems.o open.o dcache.o buffer.o dquot.o inode.o \
++              namei.o file_table.o
+ mod-subdirs :=        nls xfs
+ obj-y :=      open.o read_write.o devices.o file_table.o buffer.o \
+--- linux-2.4.20-hp4-pnnl13/fs/namei.c~nfs_export_kernel-2.4.20-hp     2003-09-14 17:34:20.000000000 +0400
++++ linux-2.4.20-hp4-pnnl13-alexey/fs/namei.c  2003-10-08 10:54:08.000000000 +0400
+@@ -22,6 +22,7 @@
+ #include <linux/dnotify.h>
+ #include <linux/smp_lock.h>
+ #include <linux/personality.h>
++#include <linux/module.h>
+ #include <asm/namei.h>
+ #include <asm/uaccess.h>
+@@ -100,6 +101,7 @@ void intent_release(struct lookup_intent
+               it->it_op_release(it);
+ }
++EXPORT_SYMBOL(intent_release);
+ /* In order to reduce some races, while at the same time doing additional
+  * checking and hopefully speeding things up, we copy filenames to the
+@@ -917,7 +919,8 @@ struct dentry * lookup_hash(struct qstr 
+ /* SMP-safe */
+-struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
++struct dentry * lookup_one_len_it(const char * name, struct dentry * base,
++                                  int len, struct lookup_intent *it)
+ {
+       unsigned long hash;
+       struct qstr this;
+@@ -937,11 +940,16 @@ struct dentry * lookup_one_len(const cha
+       }
+       this.hash = end_name_hash(hash);
+-      return lookup_hash_it(&this, base, NULL);
++      return lookup_hash_it(&this, base, it);
+ access:
+       return ERR_PTR(-EACCES);
+ }
++struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
++{
++      return lookup_one_len_it(name, base, len, NULL);
++}
++
+ /*
+  *    namei()
+  *
+--- linux-2.4.20-hp4-pnnl13/fs/nfsd/export.c~nfs_export_kernel-2.4.20-hp       2002-11-29 02:53:15.000000000 +0300
++++ linux-2.4.20-hp4-pnnl13-alexey/fs/nfsd/export.c    2003-10-08 10:54:08.000000000 +0400
+@@ -222,6 +222,11 @@ exp_export(struct nfsctl_export *nxp)
+       inode = nd.dentry->d_inode;
+       dev = inode->i_dev;
+       ino = inode->i_ino;
++      if ((inode->i_sb->s_type->fs_flags & FS_NFSEXP_FSID) &&
++          !(nxp->ex_flags & NFSEXP_FSID)) {
++          nxp->ex_dev = inode->i_sb->s_dev;
++          nxp->ex_flags |= NFSEXP_FSID;
++      }
+       err = -EINVAL;
+       exp = exp_get(clp, dev, ino);
+--- linux-2.4.20-hp4-pnnl13/fs/nfsd/nfsfh.c~nfs_export_kernel-2.4.20-hp        2002-11-29 02:53:15.000000000 +0300
++++ linux-2.4.20-hp4-pnnl13-alexey/fs/nfsd/nfsfh.c     2003-10-08 10:54:08.000000000 +0400
+@@ -36,6 +36,15 @@ struct nfsd_getdents_callback {
+       int sequence;           /* sequence counter */
+ };
++static struct dentry *lookup_it(struct inode *inode, struct dentry * dentry)
++{
++      if (inode->i_op->lookup_it)
++          return inode->i_op->lookup_it(inode, dentry, NULL, 0);
++      else
++          return inode->i_op->lookup(inode, dentry);
++              
++}
++
+ /*
+  * A rather strange filldir function to capture
+  * the name matching the specified inode number.
+@@ -75,6 +84,8 @@ static int nfsd_get_name(struct dentry *
+       int error;
+       struct file file;
+       struct nfsd_getdents_callback buffer;
++      struct lookup_intent it;
++      struct file *filp = NULL;
+       error = -ENOTDIR;
+       if (!dir || !S_ISDIR(dir->i_mode))
+@@ -85,9 +96,37 @@ static int nfsd_get_name(struct dentry *
+       /*
+        * Open the directory ...
+        */
+-      error = init_private_file(&file, dentry, FMODE_READ);
+-      if (error)
++      if (dentry->d_op && dentry->d_op->d_revalidate_it) {
++              if ((dentry->d_flags & DCACHE_NFSD_DISCONNECTED) &&
++                  (dentry->d_parent == dentry) ) {
++                      it.it_op_release = NULL;
++                      /* 
++                       * XXX Temporary Hack: Simulating init_private_file without
++                       * f_op->open for disconnected dentry Since we don't have actual
++                       * dentry->d_name to revalidate in revalidate_it()
++                       */
++                      filp = &file;
++                      memset(filp, 0, sizeof(*filp));
++                      filp->f_mode   = FMODE_READ;
++                      atomic_set(&filp->f_count, 1);
++                      filp->f_dentry = dentry;
++                      filp->f_uid = current->fsuid;
++                      filp->f_gid = current->fsgid;
++                      filp->f_op = dentry->d_inode->i_fop;
++                      error = 0;
++              } else {
++                      intent_init(&it, IT_OPEN, 0);
++                      error = revalidate_it(dentry, &it);
++                      if (error)
++                              goto out;
++                      error = init_private_file_it(&file, dentry, FMODE_READ, &it);
++              }
++      } else {
++              error = init_private_file_it(&file, dentry, FMODE_READ, NULL);
++      }
++      if (error) 
+               goto out;
++
+       error = -EINVAL;
+       if (!file.f_op->readdir)
+               goto out_close;
+@@ -113,9 +152,13 @@ static int nfsd_get_name(struct dentry *
+       }
+ out_close:
+-      if (file.f_op->release)
++      if (file.f_op->release && !filp)
+               file.f_op->release(dir, &file);
+ out:
++      if (dentry->d_op &&
++          dentry->d_op->d_revalidate_it &&
++          it.it_op_release && !filp)
++              intent_release(&it);
+       return error;
+ }
+@@ -274,7 +317,7 @@ struct dentry *nfsd_findparent(struct de
+        * it is well connected.  But nobody returns different dentrys do they?
+        */
+       down(&child->d_inode->i_sem);
+-      pdentry = child->d_inode->i_op->lookup(child->d_inode, tdentry);
++      pdentry = lookup_it(child->d_inode, tdentry);
+       up(&child->d_inode->i_sem);
+       d_drop(tdentry); /* we never want ".." hashed */
+       if (!pdentry && tdentry->d_inode == NULL) {
+@@ -306,6 +349,8 @@ struct dentry *nfsd_findparent(struct de
+                               igrab(tdentry->d_inode);
+                               pdentry->d_flags |= DCACHE_NFSD_DISCONNECTED;
+                       }
++                      if (child->d_op && child->d_op->d_revalidate_it)
++                              pdentry->d_op = child->d_op;
+               }
+               if (pdentry == NULL)
+                       pdentry = ERR_PTR(-ENOMEM);
+@@ -463,6 +508,8 @@ find_fh_dentry(struct super_block *sb, _
+               struct dentry *pdentry;
+               struct inode *parent;
++              if (result->d_op && result->d_op->d_revalidate_it)
++                      dentry->d_op = result->d_op;
+               pdentry = nfsd_findparent(dentry);
+               err = PTR_ERR(pdentry);
+               if (IS_ERR(pdentry))
+@@ -662,6 +709,11 @@ fh_verify(struct svc_rqst *rqstp, struct
+       inode = dentry->d_inode;
++      /* cache coherency for non-device filesystems */
++      if (inode->i_op && inode->i_op->revalidate_it) {
++          inode->i_op->revalidate_it(dentry, NULL);
++      }
++
+       /* Type check. The correct error return for type mismatches
+        * does not seem to be generally agreed upon. SunOS seems to
+        * use EISDIR if file isn't S_IFREG; a comment in the NFSv3
+@@ -900,8 +952,9 @@ out_negative:
+               dentry->d_parent->d_name.name, dentry->d_name.name);
+       goto out;
+ out_uptodate:
+-      printk(KERN_ERR "fh_update: %s/%s already up-to-date!\n",
+-              dentry->d_parent->d_name.name, dentry->d_name.name);
++      if(!dentry->d_parent->d_inode->i_op->mkdir_raw)
++              printk(KERN_ERR "fh_update: %s/%s already up-to-date!\n",
++                      dentry->d_parent->d_name.name, dentry->d_name.name);
+       goto out;
+ }
+--- linux-2.4.20-hp4-pnnl13/fs/nfsd/vfs.c~nfs_export_kernel-2.4.20-hp  2002-11-29 02:53:15.000000000 +0300
++++ linux-2.4.20-hp4-pnnl13-alexey/fs/nfsd/vfs.c       2003-10-08 10:54:08.000000000 +0400
+@@ -77,6 +77,128 @@ struct raparms {
+ static struct raparms *               raparml;
+ static struct raparms *               raparm_cache;
++static int link_raw(struct dentry *dold, struct dentry *ddir,
++                    struct dentry *dnew)
++{
++      int err;
++
++      struct nameidata old_nd = { .dentry = dold };
++      struct nameidata nd = { .dentry = ddir, .last = dnew->d_name };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->link_raw(&old_nd, &nd);
++      d_instantiate(dnew, dold->d_inode);
++      if(dold->d_inode->i_op && dold->d_inode->i_op->revalidate_it)
++              dold->d_inode->i_op->revalidate_it(dnew, NULL);
++
++      return err;
++}
++
++static int unlink_raw(struct dentry *dentry, char *fname, int flen,
++                      struct dentry *rdentry)
++{
++      int err;
++        struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->unlink_raw(&nd);
++      if (!err)
++              d_delete(rdentry);
++
++      return err;
++}
++
++static int rmdir_raw(struct dentry *dentry, char *fname, int flen,
++                     struct dentry *rdentry)
++{
++      int err;
++        struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->rmdir_raw(&nd);
++      if(!err) {
++              rdentry->d_inode->i_flags |= S_DEAD;
++              d_delete(rdentry);
++      }
++
++      return err;
++}
++
++static int symlink_raw(struct dentry *dentry,  char *fname, int flen,
++                       char *path)
++{
++      int err;
++        struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->symlink_raw(&nd, path);
++
++      return err;
++}
++
++static int mkdir_raw(struct dentry *dentry, char *fname, int flen, int mode)
++{
++      int err;
++        struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->mkdir_raw(&nd, mode);
++
++      return err;
++}
++
++static int mknod_raw(struct dentry *dentry, char *fname, int flen, int mode,
++                     dev_t dev)
++{
++      int err;
++        struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->mknod_raw(&nd, mode, dev);
++
++      return err;
++}     
++
++static int rename_raw(struct dentry *fdentry, struct dentry *tdentry,
++                      struct dentry *odentry, struct dentry *ndentry)
++{
++      int err;
++
++      struct nameidata old_nd = { .dentry = fdentry, .last = odentry->d_name};
++      struct nameidata new_nd = { .dentry = tdentry, .last = ndentry->d_name};
++      struct inode_operations *op = old_nd.dentry->d_inode->i_op;
++      err = op->rename_raw(&old_nd, &new_nd);
++      d_move(odentry, ndentry);
++
++      return err;
++}
++
++static int setattr_raw(struct inode *inode, struct iattr *iap)
++{
++      int err;
++
++      iap->ia_valid |= ATTR_RAW;
++      err = inode->i_op->setattr_raw(inode, iap);
++
++      return err;
++}
++
++int revalidate_it(struct dentry *dentry, struct lookup_intent *it)
++{
++      int err = 0;
++
++      if (dentry && dentry->d_op && dentry->d_op->d_revalidate_it) {
++              if (!dentry->d_op->d_revalidate_it(dentry, 0, it) &&
++                      !d_invalidate(dentry)) {
++                      dput(dentry);
++                      err = -EINVAL;
++                      dentry = NULL;
++                      return err;
++              }
++      }
++
++      return err;
++}
++
+ /*
+  * Look up one component of a pathname.
+  * N.B. After this call _both_ fhp and resfh need an fh_put
+@@ -300,7 +422,10 @@ nfsd_setattr(struct svc_rqst *rqstp, str
+       }
+       err = nfserr_notsync;
+       if (!check_guard || guardtime == inode->i_ctime) {
+-              err = notify_change(dentry, iap);
++              if ( dentry->d_inode->i_op && dentry->d_inode->i_op->setattr_raw)
++                      err = setattr_raw(dentry->d_inode, iap);
++              else
++                      err = notify_change(dentry, iap);
+               err = nfserrno(err);
+       }
+       if (size_change) {
+@@ -427,6 +552,7 @@ nfsd_open(struct svc_rqst *rqstp, struct
+ {
+       struct dentry   *dentry;
+       struct inode    *inode;
++      struct lookup_intent it;
+       int             err;
+       /* If we get here, then the client has already done an "open", and (hopefully)
+@@ -473,6 +599,14 @@ nfsd_open(struct svc_rqst *rqstp, struct
+               filp->f_mode  = FMODE_READ;
+       }
++      intent_init(&it, IT_OPEN, (filp->f_flags & ~O_ACCMODE) | filp->f_mode);
++
++      err = revalidate_it(dentry, &it);
++      if (err)
++              goto out_nfserr;
++      
++      filp->f_it = &it;
++      
+       err = 0;
+       if (filp->f_op && filp->f_op->open) {
+               err = filp->f_op->open(inode, filp);
+@@ -487,7 +621,11 @@ nfsd_open(struct svc_rqst *rqstp, struct
+                       atomic_dec(&filp->f_count);
+               }
+       }
++
+ out_nfserr:
++      if (it.it_op_release)
++              intent_release(&it);
++
+       if (err)
+               err = nfserrno(err);
+ out:
+@@ -818,7 +956,7 @@ nfsd_create(struct svc_rqst *rqstp, stru
+ {
+       struct dentry   *dentry, *dchild;
+       struct inode    *dirp;
+-      int             err;
++      int             err, error = -EOPNOTSUPP;
+       err = nfserr_perm;
+       if (!flen)
+@@ -834,20 +972,44 @@ nfsd_create(struct svc_rqst *rqstp, stru
+       dentry = fhp->fh_dentry;
+       dirp = dentry->d_inode;
++      switch (type) {
++                      case S_IFDIR:
++                              if (dirp->i_op->mkdir_raw)
++                          error = mkdir_raw(dentry, fname, flen, iap->ia_mode);
++                              break;
++                      case S_IFCHR:
++                      case S_IFBLK:
++                      case S_IFIFO:
++                      case S_IFSOCK:
++                      case S_IFREG:
++                          if (dirp->i_op->mknod_raw) {
++                                      if (type == S_IFREG)
++                                              rdev = 0;
++                                      error = mknod_raw(dentry, fname, flen, iap->ia_mode, rdev);
++                              }
++                              break;
++                              default:
++                      printk("nfsd: bad file type %o in nfsd_create\n", type);
++      }
++
+       err = nfserr_notdir;
+-      if(!dirp->i_op || !dirp->i_op->lookup)
++      if(!dirp->i_op || !(dirp->i_op->lookup || dirp->i_op->lookup_it))
+               goto out;
+       /*
+        * Check whether the response file handle has been verified yet.
+        * If it has, the parent directory should already be locked.
+        */
+-      if (!resfhp->fh_dentry) {
+-              /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */
+-              fh_lock(fhp);
++      if (!resfhp->fh_dentry || dirp->i_op->lookup_it) {
++              /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create
++                 and nfsd_proc_create in case of lustre
++              */
++              if (!resfhp->fh_dentry)
++                      fh_lock(fhp);
+               dchild = lookup_one_len(fname, dentry, flen);
+               err = PTR_ERR(dchild);
+               if (IS_ERR(dchild))
+                       goto out_nfserr;
++              resfhp->fh_dentry = NULL;
+               err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);
+               if (err)
+                       goto out;
+@@ -868,10 +1030,12 @@ nfsd_create(struct svc_rqst *rqstp, stru
+        * Make sure the child dentry is still negative ...
+        */
+       err = nfserr_exist;
+-      if (dchild->d_inode) {
+-              dprintk("nfsd_create: dentry %s/%s not negative!\n",
+-                      dentry->d_name.name, dchild->d_name.name);
+-              goto out; 
++      if ( error == -EOPNOTSUPP) {
++              if (dchild->d_inode) {
++                      dprintk("nfsd_create: dentry %s/%s not negative!\n",
++                              dentry->d_name.name, dchild->d_name.name);
++                      goto out; 
++              }
+       }
+       if (!(iap->ia_valid & ATTR_MODE))
+@@ -884,16 +1048,19 @@ nfsd_create(struct svc_rqst *rqstp, stru
+       err = nfserr_perm;
+       switch (type) {
+       case S_IFREG:
+-              err = vfs_create(dirp, dchild, iap->ia_mode);
++              if (error == -EOPNOTSUPP)
++                      err = vfs_create(dirp, dchild, iap->ia_mode);
+               break;
+       case S_IFDIR:
+-              err = vfs_mkdir(dirp, dchild, iap->ia_mode);
++              if (error == -EOPNOTSUPP)
++                      err = vfs_mkdir(dirp, dchild, iap->ia_mode);
+               break;
+       case S_IFCHR:
+       case S_IFBLK:
+       case S_IFIFO:
+       case S_IFSOCK:
+-              err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
++              if (error == -EOPNOTSUPP)       
++                      err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
+               break;
+       default:
+               printk("nfsd: bad file type %o in nfsd_create\n", type);
+@@ -962,7 +1129,13 @@ nfsd_create_v3(struct svc_rqst *rqstp, s
+       /* Get all the sanity checks out of the way before
+        * we lock the parent. */
+       err = nfserr_notdir;
+-      if(!dirp->i_op || !dirp->i_op->lookup)
++      if (dirp->i_op->mknod_raw) {
++              err = mknod_raw(dentry, fname, flen, iap->ia_mode, 0);
++              if (err && err != -EOPNOTSUPP)
++                      goto out;
++      }
++
++      if(!dirp->i_op ||  !(dirp->i_op->lookup || dirp->i_op->lookup_it))
+               goto out;
+       fh_lock(fhp);
+@@ -1013,6 +1186,8 @@ nfsd_create_v3(struct svc_rqst *rqstp, s
+               case NFS3_CREATE_GUARDED:
+                       err = nfserr_exist;
+               }
++              if(dirp->i_op->mknod_raw)
++                      err = 0;
+               goto out;
+       }
+@@ -1119,7 +1294,7 @@ nfsd_symlink(struct svc_rqst *rqstp, str
+                               struct iattr *iap)
+ {
+       struct dentry   *dentry, *dnew;
+-      int             err, cerr;
++      int             err, cerr, error = -EOPNOTSUPP;
+       err = nfserr_noent;
+       if (!flen || !plen)
+@@ -1133,12 +1308,18 @@ nfsd_symlink(struct svc_rqst *rqstp, str
+               goto out;
+       fh_lock(fhp);
+       dentry = fhp->fh_dentry;
++      
++      if (dentry->d_inode->i_op->symlink_raw)
++              error = symlink_raw(dentry, fname, flen, path);
++
+       dnew = lookup_one_len(fname, dentry, flen);
+       err = PTR_ERR(dnew);
+       if (IS_ERR(dnew))
+               goto out_nfserr;
+-      err = vfs_symlink(dentry->d_inode, dnew, path);
++      err = error;
++      if (err == -EOPNOTSUPP || !dentry->d_inode->i_op->symlink_raw)
++              err = vfs_symlink(dentry->d_inode, dnew, path);
+       if (!err) {
+               if (EX_ISSYNC(fhp->fh_export))
+                       nfsd_sync_dir(dentry);
+@@ -1148,7 +1329,10 @@ nfsd_symlink(struct svc_rqst *rqstp, str
+                               iap->ia_valid |= ATTR_CTIME;
+                               iap->ia_mode = (iap->ia_mode&S_IALLUGO)
+                                       | S_IFLNK;
+-                              err = notify_change(dnew, iap);
++                              if (dnew->d_inode->i_op && dnew->d_inode->i_op->setattr_raw)
++                                      err = setattr_raw(dnew->d_inode, iap);
++                              else
++                                      err = notify_change(dnew, iap);
+                               if (!err && EX_ISSYNC(fhp->fh_export))
+                                       write_inode_now(dentry->d_inode, 1);
+                      }
+@@ -1206,7 +1390,10 @@ nfsd_link(struct svc_rqst *rqstp, struct
+       dold = tfhp->fh_dentry;
+       dest = dold->d_inode;
+-      err = vfs_link(dold, dirp, dnew);
++      if (dirp->i_op->link_raw)
++              err = link_raw(dold, ddir, dnew);
++      else
++              err = vfs_link(dold, dirp, dnew);
+       if (!err) {
+               if (EX_ISSYNC(ffhp->fh_export)) {
+                       nfsd_sync_dir(ddir);
+@@ -1291,7 +1478,10 @@ nfsd_rename(struct svc_rqst *rqstp, stru
+                       err = nfserr_perm;
+       } else
+ #endif
+-      err = vfs_rename(fdir, odentry, tdir, ndentry);
++      if(fdir->i_op->rename_raw)
++              err = rename_raw(fdentry, tdentry, odentry, ndentry);
++      else
++              err = vfs_rename(fdir, odentry, tdir, ndentry);
+       if (!err && EX_ISSYNC(tfhp->fh_export)) {
+               nfsd_sync_dir(tdentry);
+               nfsd_sync_dir(fdentry);
+@@ -1312,7 +1502,7 @@ nfsd_rename(struct svc_rqst *rqstp, stru
+       fill_post_wcc(tfhp);
+       double_up(&tdir->i_sem, &fdir->i_sem);
+       ffhp->fh_locked = tfhp->fh_locked = 0;
+-      
++
+ out:
+       return err;
+ }
+@@ -1358,9 +1548,15 @@ nfsd_unlink(struct svc_rqst *rqstp, stru
+                       err = nfserr_perm;
+               } else
+ #endif
+-              err = vfs_unlink(dirp, rdentry);
++              if (dirp->i_op->unlink_raw)
++                      err = unlink_raw(dentry, fname, flen, rdentry);
++              else
++                      err = vfs_unlink(dirp, rdentry);
+       } else { /* It's RMDIR */
+-              err = vfs_rmdir(dirp, rdentry);
++              if (dirp->i_op->rmdir_raw)
++                      err = rmdir_raw(dentry, fname, flen, rdentry);
++              else
++                      err = vfs_rmdir(dirp, rdentry);
+       }
+       dput(rdentry);
+--- linux-2.4.20-hp4-pnnl13/include/linux/fs.h~nfs_export_kernel-2.4.20-hp     2003-09-14 17:34:24.000000000 +0400
++++ linux-2.4.20-hp4-pnnl13-alexey/include/linux/fs.h  2003-10-08 11:39:07.000000000 +0400
+@@ -93,6 +93,9 @@ extern int leases_enable, dir_notify_ena
+ #define FS_SINGLE     8 /* Filesystem that can have only one superblock */
+ #define FS_NOMOUNT    16 /* Never mount from userland */
+ #define FS_LITTER     32 /* Keeps the tree in dcache */
++#define FS_NFSEXP_FSID 64 /* Use file system specific fsid for
++                         * exporting non device filesystems.
++                         */
+ #define FS_ODD_RENAME 32768   /* Temporary stuff; will go away as soon
+                                 * as nfs_rename() will be cleaned up
+                                 */
+@@ -1116,6 +1119,9 @@ extern int open_namei_it(const char *fil
+                        struct nameidata *nd, struct lookup_intent *it);
+ extern struct file *dentry_open_it(struct dentry *dentry, struct vfsmount *mnt,
+                           int flags, struct lookup_intent *it);
++extern int revalidate_it(struct dentry *dentry, struct lookup_intent *it);
++extern int init_private_file_it(struct file *, struct dentry *dentry, int mode,
++                                struct lookup_intent *it);
+ extern int filp_close(struct file *, fl_owner_t id);
+ extern char * getname(const char *);
+@@ -1386,6 +1392,8 @@ extern void path_release(struct nameidat
+ extern int follow_down(struct vfsmount **, struct dentry **);
+ extern int follow_up(struct vfsmount **, struct dentry **);
+ extern struct dentry * lookup_one_len(const char *, struct dentry *, int);
++extern struct dentry * lookup_one_len_it(const char *, struct dentry *, int,
++                                         struct lookup_intent *);
+ extern struct dentry * lookup_hash(struct qstr *, struct dentry *);
+ #define user_path_walk(name,nd)        __user_walk(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd)
+ #define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd)
+@@ -1403,6 +1411,8 @@ typedef int (*find_inode_t)(struct inode
+ extern struct inode * iget4_locked(struct super_block *, unsigned long,
+                                  find_inode_t, void *);
++extern struct inode * ilookup4(struct super_block *, unsigned long,
++                               find_inode_t, void *);
+ static inline struct inode *iget4(struct super_block *sb, unsigned long ino,
+                                 find_inode_t find_actor, void *opaque)
+--- linux-2.4.20-hp4-pnnl13/kernel/ksyms.c~nfs_export_kernel-2.4.20-hp 2003-09-14 17:34:22.000000000 +0400
++++ linux-2.4.20-hp4-pnnl13-alexey/kernel/ksyms.c      2003-10-08 11:39:42.000000000 +0400
+@@ -169,6 +169,7 @@ EXPORT_SYMBOL(fget);
+ EXPORT_SYMBOL(igrab);
+ EXPORT_SYMBOL(iunique);
+ EXPORT_SYMBOL(iget4_locked);
++EXPORT_SYMBOL(ilookup4);
+ EXPORT_SYMBOL(unlock_new_inode);
+ EXPORT_SYMBOL(iput);
+ EXPORT_SYMBOL(inode_init_once);
+@@ -181,6 +182,7 @@ EXPORT_SYMBOL(path_walk);
+ EXPORT_SYMBOL(path_release);
+ EXPORT_SYMBOL(__user_walk);
+ EXPORT_SYMBOL(lookup_one_len);
++EXPORT_SYMBOL(lookup_one_len_it);
+ EXPORT_SYMBOL(lookup_hash);
+ EXPORT_SYMBOL(sys_close);
+ EXPORT_SYMBOL(dcache_lock);
+
+_
diff --git a/lustre/kernel_patches/patches/nfs_export_kernel-2.4.20-rh.patch b/lustre/kernel_patches/patches/nfs_export_kernel-2.4.20-rh.patch
new file mode 100644 (file)
index 0000000..8ae5b78
--- /dev/null
@@ -0,0 +1,741 @@
+ fs/Makefile        |    3 
+ fs/file_table.c    |   11 ++
+ fs/inode.c         |   23 ++++-
+ fs/namei.c         |   12 ++
+ fs/nfsd/export.c   |    5 +
+ fs/nfsd/nfsfh.c    |   65 +++++++++++++-
+ fs/nfsd/vfs.c      |  240 ++++++++++++++++++++++++++++++++++++++++++++++++-----
+ include/linux/fs.h |   10 ++
+ kernel/ksyms.c     |    2 
+ 9 files changed, 337 insertions(+), 34 deletions(-)
+
+--- linux-2.4.20-rh-20.9/fs/file_table.c~nfs_export_kernel-2.4.20-rh   2002-11-29 02:53:15.000000000 +0300
++++ linux-2.4.20-rh-20.9-alexey/fs/file_table.c        2003-10-08 10:48:38.000000000 +0400
+@@ -82,7 +82,8 @@ struct file * get_empty_filp(void)
+  * and call the open function (if any).  The caller must verify that
+  * inode->i_fop is not NULL.
+  */
+-int init_private_file(struct file *filp, struct dentry *dentry, int mode)
++int init_private_file_it(struct file *filp, struct dentry *dentry, int mode,
++                         struct lookup_intent *it)
+ {
+       memset(filp, 0, sizeof(*filp));
+       filp->f_mode   = mode;
+@@ -90,12 +91,20 @@ int init_private_file(struct file *filp,
+       filp->f_dentry = dentry;
+       filp->f_uid    = current->fsuid;
+       filp->f_gid    = current->fsgid;
++      if (it)
++              filp->f_it = it;
+       filp->f_op     = dentry->d_inode->i_fop;
+       if (filp->f_op->open)
+               return filp->f_op->open(dentry->d_inode, filp);
+       else
+               return 0;
+ }
++EXPORT_SYMBOL(init_private_file_it);
++
++int init_private_file(struct file *filp, struct dentry *dentry, int mode)
++{
++      return init_private_file_it(filp, dentry, mode, NULL);
++}
+ void fput(struct file * file)
+ {
+--- linux-2.4.20-rh-20.9/fs/inode.c~nfs_export_kernel-2.4.20-rh        2003-09-14 17:35:22.000000000 +0400
++++ linux-2.4.20-rh-20.9-alexey/fs/inode.c     2003-10-08 10:48:38.000000000 +0400
+@@ -1063,9 +1063,10 @@ struct inode *igrab(struct inode *inode)
+ }
+-struct inode *iget4(struct super_block *sb, unsigned long ino, find_inode_t find_actor, void *opaque)
++static inline struct inode *ifind(struct super_block *sb, unsigned long ino,
++                                  struct list_head *head,
++                                  find_inode_t find_actor, void *opaque)
+ {
+-      struct list_head * head = inode_hashtable + hash(sb,ino);
+       struct inode * inode;
+       spin_lock(&inode_lock);
+@@ -1078,6 +1079,24 @@ struct inode *iget4(struct super_block *
+       }
+       spin_unlock(&inode_lock);
++      return NULL;
++}
++
++struct inode *ilookup4(struct super_block *sb, unsigned long ino,
++                       find_inode_t find_actor, void *opaque)
++{
++      struct list_head * head = inode_hashtable + hash(sb,ino);
++      return ifind(sb, ino, head, find_actor, opaque);
++}
++
++struct inode *iget4(struct super_block *sb, unsigned long ino,
++                    find_inode_t find_actor, void *opaque)
++{
++      struct list_head * head = inode_hashtable + hash(sb,ino);
++      struct inode *inode = ifind(sb, ino, head, find_actor, opaque);
++      if (inode)
++              return inode;
++
+       /*
+        * get_new_inode() will do the right thing, re-trying the search
+        * in case it had to block at any point.
+--- linux-2.4.20-rh-20.9/fs/Makefile~nfs_export_kernel-2.4.20-rh       2003-09-14 17:35:20.000000000 +0400
++++ linux-2.4.20-rh-20.9-alexey/fs/Makefile    2003-10-08 10:49:33.000000000 +0400
+@@ -9,7 +9,8 @@
+ O_TARGET := fs.o
+-export-objs :=        filesystems.o open.o dcache.o buffer.o dquot.o dcookies.o inode.o
++export-objs :=        filesystems.o open.o dcache.o buffer.o dquot.o dcookies.o inode.o \
++              namei.o file_table.o
+ mod-subdirs :=        nls
+ obj-y :=      open.o read_write.o devices.o file_table.o buffer.o \
+--- linux-2.4.20-rh-20.9/fs/namei.c~nfs_export_kernel-2.4.20-rh        2003-09-14 17:35:22.000000000 +0400
++++ linux-2.4.20-rh-20.9-alexey/fs/namei.c     2003-10-08 10:48:38.000000000 +0400
+@@ -22,6 +22,7 @@
+ #include <linux/dnotify.h>
+ #include <linux/smp_lock.h>
+ #include <linux/personality.h>
++#include <linux/module.h>
+ #include <asm/namei.h>
+ #include <asm/uaccess.h>
+@@ -100,6 +101,7 @@ void intent_release(struct lookup_intent
+               it->it_op_release(it);
+ }
++EXPORT_SYMBOL(intent_release);
+ static void *lock_dir(struct inode *dir, struct qstr *name)
+ {
+@@ -959,7 +961,8 @@ struct dentry * lookup_hash(struct qstr 
+ /* SMP-safe */
+-struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
++struct dentry * lookup_one_len_it(const char * name, struct dentry * base,
++                                  int len, struct lookup_intent *it)
+ {
+       unsigned long hash;
+       struct qstr this;
+@@ -979,11 +982,16 @@ struct dentry * lookup_one_len(const cha
+       }
+       this.hash = end_name_hash(hash);
+-      return lookup_hash_it(&this, base, NULL);
++      return lookup_hash_it(&this, base, it);
+ access:
+       return ERR_PTR(-EACCES);
+ }
++struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
++{
++      return lookup_one_len_it(name, base, len, NULL);
++}
++
+ /*
+  *    namei()
+  *
+--- linux-2.4.20-rh-20.9/fs/nfsd/export.c~nfs_export_kernel-2.4.20-rh  2003-09-13 19:34:35.000000000 +0400
++++ linux-2.4.20-rh-20.9-alexey/fs/nfsd/export.c       2003-10-08 10:48:38.000000000 +0400
+@@ -222,6 +222,11 @@ exp_export(struct nfsctl_export *nxp)
+       inode = nd.dentry->d_inode;
+       dev = inode->i_dev;
+       ino = inode->i_ino;
++      if ((inode->i_sb->s_type->fs_flags & FS_NFSEXP_FSID) &&
++          !(nxp->ex_flags & NFSEXP_FSID)) {
++          nxp->ex_dev = inode->i_sb->s_dev;
++          nxp->ex_flags |= NFSEXP_FSID;
++      }
+       err = -EINVAL;
+       exp = exp_get(clp, dev, ino);
+--- linux-2.4.20-rh-20.9/fs/nfsd/nfsfh.c~nfs_export_kernel-2.4.20-rh   2003-09-13 19:34:15.000000000 +0400
++++ linux-2.4.20-rh-20.9-alexey/fs/nfsd/nfsfh.c        2003-10-08 10:48:38.000000000 +0400
+@@ -36,6 +36,15 @@ struct nfsd_getdents_callback {
+       int sequence;           /* sequence counter */
+ };
++static struct dentry *lookup_it(struct inode *inode, struct dentry * dentry)
++{
++      if (inode->i_op->lookup_it)
++          return inode->i_op->lookup_it(inode, dentry, NULL, 0);
++      else
++          return inode->i_op->lookup(inode, dentry);
++              
++}
++
+ /*
+  * A rather strange filldir function to capture
+  * the name matching the specified inode number.
+@@ -75,6 +84,8 @@ static int nfsd_get_name(struct dentry *
+       int error;
+       struct file file;
+       struct nfsd_getdents_callback buffer;
++      struct lookup_intent it;
++      struct file *filp = NULL;
+       error = -ENOTDIR;
+       if (!dir || !S_ISDIR(dir->i_mode))
+@@ -85,9 +96,37 @@ static int nfsd_get_name(struct dentry *
+       /*
+        * Open the directory ...
+        */
+-      error = init_private_file(&file, dentry, FMODE_READ);
+-      if (error)
++      if (dentry->d_op && dentry->d_op->d_revalidate_it) {
++              if ((dentry->d_flags & DCACHE_NFSD_DISCONNECTED) &&
++                  (dentry->d_parent == dentry) ) {
++                      it.it_op_release = NULL;
++                      /* 
++                       * XXX Temporary Hack: Simulating init_private_file without
++                       * f_op->open for disconnected dentry Since we don't have actual
++                       * dentry->d_name to revalidate in revalidate_it()
++                       */
++                      filp = &file;
++                      memset(filp, 0, sizeof(*filp));
++                      filp->f_mode   = FMODE_READ;
++                      atomic_set(&filp->f_count, 1);
++                      filp->f_dentry = dentry;
++                      filp->f_uid = current->fsuid;
++                      filp->f_gid = current->fsgid;
++                      filp->f_op = dentry->d_inode->i_fop;
++                      error = 0;
++              } else {
++                      intent_init(&it, IT_OPEN, 0);
++                      error = revalidate_it(dentry, &it);
++                      if (error)
++                              goto out;
++                      error = init_private_file_it(&file, dentry, FMODE_READ, &it);
++              }
++      } else {
++              error = init_private_file_it(&file, dentry, FMODE_READ, NULL);
++      }
++      if (error) 
+               goto out;
++
+       error = -EINVAL;
+       if (!file.f_op->readdir)
+               goto out_close;
+@@ -113,9 +152,13 @@ static int nfsd_get_name(struct dentry *
+       }
+ out_close:
+-      if (file.f_op->release)
++      if (file.f_op->release && !filp)
+               file.f_op->release(dir, &file);
+ out:
++      if (dentry->d_op &&
++          dentry->d_op->d_revalidate_it &&
++          it.it_op_release && !filp)
++              intent_release(&it);
+       return error;
+ }
+@@ -274,7 +317,7 @@ struct dentry *nfsd_findparent(struct de
+        * it is well connected.  But nobody returns different dentrys do they?
+        */
+       down(&child->d_inode->i_sem);
+-      pdentry = child->d_inode->i_op->lookup(child->d_inode, tdentry);
++      pdentry = lookup_it(child->d_inode, tdentry);
+       up(&child->d_inode->i_sem);
+       d_drop(tdentry); /* we never want ".." hashed */
+       if (!pdentry && tdentry->d_inode == NULL) {
+@@ -306,6 +349,8 @@ struct dentry *nfsd_findparent(struct de
+                               igrab(tdentry->d_inode);
+                               pdentry->d_flags |= DCACHE_NFSD_DISCONNECTED;
+                       }
++                      if (child->d_op && child->d_op->d_revalidate_it)
++                              pdentry->d_op = child->d_op;
+               }
+               if (pdentry == NULL)
+                       pdentry = ERR_PTR(-ENOMEM);
+@@ -463,6 +508,8 @@ find_fh_dentry(struct super_block *sb, _
+               struct dentry *pdentry;
+               struct inode *parent;
++              if (result->d_op && result->d_op->d_revalidate_it)
++                      dentry->d_op = result->d_op;
+               pdentry = nfsd_findparent(dentry);
+               err = PTR_ERR(pdentry);
+               if (IS_ERR(pdentry))
+@@ -669,6 +716,11 @@ fh_verify(struct svc_rqst *rqstp, struct
+       inode = dentry->d_inode;
++      /* cache coherency for non-device filesystems */
++      if (inode->i_op && inode->i_op->revalidate_it) {
++          inode->i_op->revalidate_it(dentry, NULL);
++      }
++
+       /* Type check. The correct error return for type mismatches
+        * does not seem to be generally agreed upon. SunOS seems to
+        * use EISDIR if file isn't S_IFREG; a comment in the NFSv3
+@@ -912,8 +964,9 @@ out_negative:
+               dentry->d_parent->d_name.name, dentry->d_name.name);
+       goto out;
+ out_uptodate:
+-      printk(KERN_ERR "fh_update: %s/%s already up-to-date!\n",
+-              dentry->d_parent->d_name.name, dentry->d_name.name);
++      if(!dentry->d_parent->d_inode->i_op->mkdir_raw)
++              printk(KERN_ERR "fh_update: %s/%s already up-to-date!\n",
++                      dentry->d_parent->d_name.name, dentry->d_name.name);
+       goto out;
+ }
+--- linux-2.4.20-rh-20.9/fs/nfsd/vfs.c~nfs_export_kernel-2.4.20-rh     2003-09-13 19:34:15.000000000 +0400
++++ linux-2.4.20-rh-20.9-alexey/fs/nfsd/vfs.c  2003-10-08 10:48:38.000000000 +0400
+@@ -77,6 +77,128 @@ struct raparms {
+ static struct raparms *               raparml;
+ static struct raparms *               raparm_cache;
++static int link_raw(struct dentry *dold, struct dentry *ddir,
++                    struct dentry *dnew)
++{
++      int err;
++
++      struct nameidata old_nd = { .dentry = dold };
++      struct nameidata nd = { .dentry = ddir, .last = dnew->d_name };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->link_raw(&old_nd, &nd);
++      d_instantiate(dnew, dold->d_inode);
++      if(dold->d_inode->i_op && dold->d_inode->i_op->revalidate_it)
++              dold->d_inode->i_op->revalidate_it(dnew, NULL);
++
++      return err;
++}
++
++static int unlink_raw(struct dentry *dentry, char *fname, int flen,
++                      struct dentry *rdentry)
++{
++      int err;
++        struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->unlink_raw(&nd);
++      if (!err)
++              d_delete(rdentry);
++
++      return err;
++}
++
++static int rmdir_raw(struct dentry *dentry, char *fname, int flen,
++                     struct dentry *rdentry)
++{
++      int err;
++        struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->rmdir_raw(&nd);
++      if(!err) {
++              rdentry->d_inode->i_flags |= S_DEAD;
++              d_delete(rdentry);
++      }
++
++      return err;
++}
++
++static int symlink_raw(struct dentry *dentry,  char *fname, int flen,
++                       char *path)
++{
++      int err;
++        struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->symlink_raw(&nd, path);
++
++      return err;
++}
++
++static int mkdir_raw(struct dentry *dentry, char *fname, int flen, int mode)
++{
++      int err;
++        struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->mkdir_raw(&nd, mode);
++
++      return err;
++}
++
++static int mknod_raw(struct dentry *dentry, char *fname, int flen, int mode,
++                     dev_t dev)
++{
++      int err;
++        struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->mknod_raw(&nd, mode, dev);
++
++      return err;
++}     
++
++static int rename_raw(struct dentry *fdentry, struct dentry *tdentry,
++                      struct dentry *odentry, struct dentry *ndentry)
++{
++      int err;
++
++      struct nameidata old_nd = { .dentry = fdentry, .last = odentry->d_name};
++      struct nameidata new_nd = { .dentry = tdentry, .last = ndentry->d_name};
++      struct inode_operations *op = old_nd.dentry->d_inode->i_op;
++      err = op->rename_raw(&old_nd, &new_nd);
++      d_move(odentry, ndentry);
++
++      return err;
++}
++
++static int setattr_raw(struct inode *inode, struct iattr *iap)
++{
++      int err;
++
++      iap->ia_valid |= ATTR_RAW;
++      err = inode->i_op->setattr_raw(inode, iap);
++
++      return err;
++}
++
++int revalidate_it(struct dentry *dentry, struct lookup_intent *it)
++{
++      int err = 0;
++
++      if (dentry && dentry->d_op && dentry->d_op->d_revalidate_it) {
++              if (!dentry->d_op->d_revalidate_it(dentry, 0, it) &&
++                      !d_invalidate(dentry)) {
++                      dput(dentry);
++                      err = -EINVAL;
++                      dentry = NULL;
++                      return err;
++              }
++      }
++
++      return err;
++}
++
+ /*
+  * Look up one component of a pathname.
+  * N.B. After this call _both_ fhp and resfh need an fh_put
+@@ -302,7 +424,10 @@ nfsd_setattr(struct svc_rqst *rqstp, str
+       }
+       err = nfserr_notsync;
+       if (!check_guard || guardtime == inode->i_ctime) {
+-              err = notify_change(dentry, iap);
++              if ( dentry->d_inode->i_op && dentry->d_inode->i_op->setattr_raw)
++                      err = setattr_raw(dentry->d_inode, iap);
++              else
++                      err = notify_change(dentry, iap);
+               err = nfserrno(err);
+       }
+       if (size_change) {
+@@ -429,6 +554,7 @@ nfsd_open(struct svc_rqst *rqstp, struct
+ {
+       struct dentry   *dentry;
+       struct inode    *inode;
++      struct lookup_intent it;
+       int             err;
+       /* If we get here, then the client has already done an "open", and (hopefully)
+@@ -475,6 +601,14 @@ nfsd_open(struct svc_rqst *rqstp, struct
+               filp->f_mode  = FMODE_READ;
+       }
++      intent_init(&it, IT_OPEN, (filp->f_flags & ~O_ACCMODE) | filp->f_mode);
++
++      err = revalidate_it(dentry, &it);
++      if (err)
++              goto out_nfserr;
++      
++      filp->f_it = &it;
++      
+       err = 0;
+       if (filp->f_op && filp->f_op->open) {
+               err = filp->f_op->open(inode, filp);
+@@ -489,7 +623,11 @@ nfsd_open(struct svc_rqst *rqstp, struct
+                       atomic_dec(&filp->f_count);
+               }
+       }
++
+ out_nfserr:
++      if (it.it_op_release)
++              intent_release(&it);
++
+       if (err)
+               err = nfserrno(err);
+ out:
+@@ -820,7 +958,7 @@ nfsd_create(struct svc_rqst *rqstp, stru
+ {
+       struct dentry   *dentry, *dchild;
+       struct inode    *dirp;
+-      int             err;
++      int             err, error = -EOPNOTSUPP;
+       err = nfserr_perm;
+       if (!flen)
+@@ -836,20 +974,44 @@ nfsd_create(struct svc_rqst *rqstp, stru
+       dentry = fhp->fh_dentry;
+       dirp = dentry->d_inode;
++      switch (type) {
++                      case S_IFDIR:
++                              if (dirp->i_op->mkdir_raw)
++                          error = mkdir_raw(dentry, fname, flen, iap->ia_mode);
++                              break;
++                      case S_IFCHR:
++                      case S_IFBLK:
++                      case S_IFIFO:
++                      case S_IFSOCK:
++                      case S_IFREG:
++                          if (dirp->i_op->mknod_raw) {
++                                      if (type == S_IFREG)
++                                              rdev = 0;
++                                      error = mknod_raw(dentry, fname, flen, iap->ia_mode, rdev);
++                              }
++                              break;
++                              default:
++                      printk("nfsd: bad file type %o in nfsd_create\n", type);
++      }
++
+       err = nfserr_notdir;
+-      if(!dirp->i_op || !dirp->i_op->lookup)
++      if(!dirp->i_op || !(dirp->i_op->lookup || dirp->i_op->lookup_it))
+               goto out;
+       /*
+        * Check whether the response file handle has been verified yet.
+        * If it has, the parent directory should already be locked.
+        */
+-      if (!resfhp->fh_dentry) {
+-              /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */
+-              fh_lock(fhp);
++      if (!resfhp->fh_dentry || dirp->i_op->lookup_it) {
++              /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create
++                 and nfsd_proc_create in case of lustre
++              */
++              if (!resfhp->fh_dentry)
++                      fh_lock(fhp);
+               dchild = lookup_one_len(fname, dentry, flen);
+               err = PTR_ERR(dchild);
+               if (IS_ERR(dchild))
+                       goto out_nfserr;
++              resfhp->fh_dentry = NULL;
+               err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);
+               if (err)
+                       goto out;
+@@ -870,10 +1032,12 @@ nfsd_create(struct svc_rqst *rqstp, stru
+        * Make sure the child dentry is still negative ...
+        */
+       err = nfserr_exist;
+-      if (dchild->d_inode) {
+-              dprintk("nfsd_create: dentry %s/%s not negative!\n",
+-                      dentry->d_name.name, dchild->d_name.name);
+-              goto out; 
++      if ( error == -EOPNOTSUPP) {
++              if (dchild->d_inode) {
++                      dprintk("nfsd_create: dentry %s/%s not negative!\n",
++                              dentry->d_name.name, dchild->d_name.name);
++                      goto out; 
++              }
+       }
+       if (!(iap->ia_valid & ATTR_MODE))
+@@ -886,16 +1050,19 @@ nfsd_create(struct svc_rqst *rqstp, stru
+       err = nfserr_perm;
+       switch (type) {
+       case S_IFREG:
+-              err = vfs_create(dirp, dchild, iap->ia_mode);
++              if (error == -EOPNOTSUPP)
++                      err = vfs_create(dirp, dchild, iap->ia_mode);
+               break;
+       case S_IFDIR:
+-              err = vfs_mkdir(dirp, dchild, iap->ia_mode);
++              if (error == -EOPNOTSUPP)
++                      err = vfs_mkdir(dirp, dchild, iap->ia_mode);
+               break;
+       case S_IFCHR:
+       case S_IFBLK:
+       case S_IFIFO:
+       case S_IFSOCK:
+-              err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
++              if (error == -EOPNOTSUPP)       
++                      err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
+               break;
+       default:
+               printk("nfsd: bad file type %o in nfsd_create\n", type);
+@@ -964,7 +1131,13 @@ nfsd_create_v3(struct svc_rqst *rqstp, s
+       /* Get all the sanity checks out of the way before
+        * we lock the parent. */
+       err = nfserr_notdir;
+-      if(!dirp->i_op || !dirp->i_op->lookup)
++      if (dirp->i_op->mknod_raw) {
++              err = mknod_raw(dentry, fname, flen, iap->ia_mode, 0);
++              if (err && err != -EOPNOTSUPP)
++                      goto out;
++      }
++
++      if(!dirp->i_op ||  !(dirp->i_op->lookup || dirp->i_op->lookup_it))
+               goto out;
+       fh_lock(fhp);
+@@ -1015,6 +1188,8 @@ nfsd_create_v3(struct svc_rqst *rqstp, s
+               case NFS3_CREATE_GUARDED:
+                       err = nfserr_exist;
+               }
++              if(dirp->i_op->mknod_raw)
++                      err = 0;
+               goto out;
+       }
+@@ -1121,7 +1296,7 @@ nfsd_symlink(struct svc_rqst *rqstp, str
+                               struct iattr *iap)
+ {
+       struct dentry   *dentry, *dnew;
+-      int             err, cerr;
++      int             err, cerr, error = -EOPNOTSUPP;
+       err = nfserr_noent;
+       if (!flen || !plen)
+@@ -1135,12 +1310,18 @@ nfsd_symlink(struct svc_rqst *rqstp, str
+               goto out;
+       fh_lock(fhp);
+       dentry = fhp->fh_dentry;
++      
++      if (dentry->d_inode->i_op->symlink_raw)
++              error = symlink_raw(dentry, fname, flen, path);
++
+       dnew = lookup_one_len(fname, dentry, flen);
+       err = PTR_ERR(dnew);
+       if (IS_ERR(dnew))
+               goto out_nfserr;
+-      err = vfs_symlink(dentry->d_inode, dnew, path);
++      err = error;
++      if (err == -EOPNOTSUPP || !dentry->d_inode->i_op->symlink_raw)
++              err = vfs_symlink(dentry->d_inode, dnew, path);
+       if (!err) {
+               if (EX_ISSYNC(fhp->fh_export))
+                       nfsd_sync_dir(dentry);
+@@ -1150,7 +1331,10 @@ nfsd_symlink(struct svc_rqst *rqstp, str
+                               iap->ia_valid |= ATTR_CTIME;
+                               iap->ia_mode = (iap->ia_mode&S_IALLUGO)
+                                       | S_IFLNK;
+-                              err = notify_change(dnew, iap);
++                              if (dnew->d_inode->i_op && dnew->d_inode->i_op->setattr_raw)
++                                      err = setattr_raw(dnew->d_inode, iap);
++                              else
++                                      err = notify_change(dnew, iap);
+                               if (!err && EX_ISSYNC(fhp->fh_export))
+                                       write_inode_now(dentry->d_inode, 1);
+                      }
+@@ -1208,7 +1392,10 @@ nfsd_link(struct svc_rqst *rqstp, struct
+       dold = tfhp->fh_dentry;
+       dest = dold->d_inode;
+-      err = vfs_link(dold, dirp, dnew);
++      if (dirp->i_op->link_raw)
++              err = link_raw(dold, ddir, dnew);
++      else
++              err = vfs_link(dold, dirp, dnew);
+       if (!err) {
+               if (EX_ISSYNC(ffhp->fh_export)) {
+                       nfsd_sync_dir(ddir);
+@@ -1293,7 +1480,10 @@ nfsd_rename(struct svc_rqst *rqstp, stru
+                       err = nfserr_perm;
+       } else
+ #endif
+-      err = vfs_rename(fdir, odentry, tdir, ndentry);
++      if(fdir->i_op->rename_raw)
++              err = rename_raw(fdentry, tdentry, odentry, ndentry);
++      else
++              err = vfs_rename(fdir, odentry, tdir, ndentry);
+       if (!err && EX_ISSYNC(tfhp->fh_export)) {
+               nfsd_sync_dir(tdentry);
+               nfsd_sync_dir(fdentry);
+@@ -1314,7 +1504,7 @@ nfsd_rename(struct svc_rqst *rqstp, stru
+       fill_post_wcc(tfhp);
+       double_up(&tdir->i_sem, &fdir->i_sem);
+       ffhp->fh_locked = tfhp->fh_locked = 0;
+-      
++
+ out:
+       return err;
+ }
+@@ -1360,9 +1550,15 @@ nfsd_unlink(struct svc_rqst *rqstp, stru
+                       err = nfserr_perm;
+               } else
+ #endif
+-              err = vfs_unlink(dirp, rdentry);
++              if (dirp->i_op->unlink_raw)
++                      err = unlink_raw(dentry, fname, flen, rdentry);
++              else
++                      err = vfs_unlink(dirp, rdentry);
+       } else { /* It's RMDIR */
+-              err = vfs_rmdir(dirp, rdentry);
++              if (dirp->i_op->rmdir_raw)
++                      err = rmdir_raw(dentry, fname, flen, rdentry);
++              else
++                      err = vfs_rmdir(dirp, rdentry);
+       }
+       dput(rdentry);
+--- linux-2.4.20-rh-20.9/include/linux/fs.h~nfs_export_kernel-2.4.20-rh        2003-09-14 17:35:22.000000000 +0400
++++ linux-2.4.20-rh-20.9-alexey/include/linux/fs.h     2003-10-08 10:48:38.000000000 +0400
+@@ -94,6 +94,9 @@ extern int leases_enable, dir_notify_ena
+ #define FS_SINGLE     8 /* Filesystem that can have only one superblock */
+ #define FS_NOMOUNT    16 /* Never mount from userland */
+ #define FS_LITTER     32 /* Keeps the tree in dcache */
++#define FS_NFSEXP_FSID 64 /* Use file system specific fsid for
++                         * exporting non device filesystems.
++                         */
+ #define FS_ODD_RENAME 32768   /* Temporary stuff; will go away as soon
+                                 * as nfs_rename() will be cleaned up
+                                 */
+@@ -1124,6 +1127,9 @@ extern int open_namei_it(const char *fil
+                        struct nameidata *nd, struct lookup_intent *it);
+ extern struct file *dentry_open_it(struct dentry *dentry, struct vfsmount *mnt,
+                           int flags, struct lookup_intent *it);
++extern int revalidate_it(struct dentry *dentry, struct lookup_intent *it);
++extern int init_private_file_it(struct file *, struct dentry *dentry, int mode,
++                                struct lookup_intent *it);
+ extern int filp_close(struct file *, fl_owner_t id);
+ extern char * getname(const char *);
+@@ -1423,6 +1429,8 @@ extern void path_release(struct nameidat
+ extern int follow_down(struct vfsmount **, struct dentry **);
+ extern int follow_up(struct vfsmount **, struct dentry **);
+ extern struct dentry * lookup_one_len(const char *, struct dentry *, int);
++extern struct dentry * lookup_one_len_it(const char *, struct dentry *, int,
++                                         struct lookup_intent *);
+ extern struct dentry * lookup_hash(struct qstr *, struct dentry *);
+ #define user_path_walk(name,nd)        __user_walk(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd)
+ #define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd)
+@@ -1439,6 +1447,8 @@ extern ino_t iunique(struct super_block 
+ typedef int (*find_inode_t)(struct inode *, unsigned long, void *);
+ extern struct inode * iget4(struct super_block *, unsigned long, find_inode_t, void *);
++extern struct inode * ilookup4(struct super_block *, unsigned long,
++                               find_inode_t, void *);
+ static inline struct inode *iget(struct super_block *sb, unsigned long ino)
+ {
+       return iget4(sb, ino, NULL, NULL);
+--- linux-2.4.20-rh-20.9/kernel/ksyms.c~nfs_export_kernel-2.4.20-rh    2003-09-14 17:35:20.000000000 +0400
++++ linux-2.4.20-rh-20.9-alexey/kernel/ksyms.c 2003-10-08 10:48:38.000000000 +0400
+@@ -164,6 +164,7 @@ EXPORT_SYMBOL(fget);
+ EXPORT_SYMBOL(igrab);
+ EXPORT_SYMBOL(iunique);
+ EXPORT_SYMBOL(iget4);
++EXPORT_SYMBOL(ilookup4);
+ EXPORT_SYMBOL(iput);
+ EXPORT_SYMBOL(inode_init_once);
+ EXPORT_SYMBOL(force_delete);
+@@ -175,6 +176,7 @@ EXPORT_SYMBOL(path_walk);
+ EXPORT_SYMBOL(path_release);
+ EXPORT_SYMBOL(__user_walk);
+ EXPORT_SYMBOL(lookup_one_len);
++EXPORT_SYMBOL(lookup_one_len_it);
+ EXPORT_SYMBOL(lookup_hash);
+ EXPORT_SYMBOL(sys_close);
+ EXPORT_SYMBOL(sys_read);
+
+_
diff --git a/lustre/kernel_patches/patches/nfs_export_kernel-2.4.22-rh.patch b/lustre/kernel_patches/patches/nfs_export_kernel-2.4.22-rh.patch
new file mode 100644 (file)
index 0000000..40285b8
--- /dev/null
@@ -0,0 +1,730 @@
+ fs/Makefile        |    3 
+ fs/file_table.c    |   11 ++
+ fs/inode.c         |   23 ++++-
+ fs/namei.c         |   12 ++
+ fs/nfsd/export.c   |    5 +
+ fs/nfsd/nfsfh.c    |   65 +++++++++++++-
+ fs/nfsd/vfs.c      |  235 ++++++++++++++++++++++++++++++++++++++++++++++++-----
+ include/linux/fs.h |   11 ++
+ kernel/ksyms.c     |    2 
+ 9 files changed, 333 insertions(+), 34 deletions(-)
+
+--- linux-2.4.22-ac1/fs/file_table.c~nfs_export_kernel-2.4.22-rh       2002-11-29 02:53:15.000000000 +0300
++++ linux-2.4.22-ac1-alexey/fs/file_table.c    2003-10-08 13:41:27.000000000 +0400
+@@ -82,7 +82,8 @@ struct file * get_empty_filp(void)
+  * and call the open function (if any).  The caller must verify that
+  * inode->i_fop is not NULL.
+  */
+-int init_private_file(struct file *filp, struct dentry *dentry, int mode)
++int init_private_file_it(struct file *filp, struct dentry *dentry, int mode,
++                         struct lookup_intent *it)
+ {
+       memset(filp, 0, sizeof(*filp));
+       filp->f_mode   = mode;
+@@ -90,12 +91,20 @@ int init_private_file(struct file *filp,
+       filp->f_dentry = dentry;
+       filp->f_uid    = current->fsuid;
+       filp->f_gid    = current->fsgid;
++      if (it)
++              filp->f_it = it;
+       filp->f_op     = dentry->d_inode->i_fop;
+       if (filp->f_op->open)
+               return filp->f_op->open(dentry->d_inode, filp);
+       else
+               return 0;
+ }
++EXPORT_SYMBOL(init_private_file_it);
++
++int init_private_file(struct file *filp, struct dentry *dentry, int mode)
++{
++      return init_private_file_it(filp, dentry, mode, NULL);
++}
+ void fput(struct file * file)
+ {
+--- linux-2.4.22-ac1/fs/inode.c~nfs_export_kernel-2.4.22-rh    2003-09-26 00:57:28.000000000 +0400
++++ linux-2.4.22-ac1-alexey/fs/inode.c 2003-10-08 13:43:31.000000000 +0400
+@@ -998,9 +998,10 @@ struct inode *igrab(struct inode *inode)
+       return inode;
+ }
+-struct inode *iget4_locked(struct super_block *sb, unsigned long ino, find_inode_t find_actor, void *opaque)
++struct inode *ifind(struct super_block *sb, unsigned long ino,
++                      struct list_head *head,
++                      find_inode_t find_actor, void *opaque)
+ {
+-      struct list_head * head = inode_hashtable + hash(sb,ino);
+       struct inode * inode;
+       spin_lock(&inode_lock);
+@@ -1013,6 +1014,24 @@ struct inode *iget4_locked(struct super_
+       }
+       spin_unlock(&inode_lock);
++      return NULL;
++}
++
++struct inode *ilookup4(struct super_block *sb, unsigned long ino,
++                       find_inode_t find_actor, void *opaque)
++{
++      struct list_head * head = inode_hashtable + hash(sb,ino);
++      return ifind(sb, ino, head, find_actor, opaque);
++}
++
++struct inode *iget4_locked(struct super_block *sb, unsigned long ino,
++                    find_inode_t find_actor, void *opaque)
++{
++      struct list_head * head = inode_hashtable + hash(sb,ino);
++      struct inode *inode = ifind(sb, ino, head, find_actor, opaque);
++      if (inode)
++              return inode;
++
+       /*
+        * get_new_inode() will do the right thing, re-trying the search
+        * in case it had to block at any point.
+--- linux-2.4.22-ac1/fs/Makefile~nfs_export_kernel-2.4.22-rh   2003-09-26 00:57:28.000000000 +0400
++++ linux-2.4.22-ac1-alexey/fs/Makefile        2003-10-08 13:41:55.000000000 +0400
+@@ -7,7 +7,8 @@
+ O_TARGET := fs.o
+-export-objs :=        filesystems.o open.o dcache.o buffer.o dquot.o dcookies.o inode.o
++export-objs :=        filesystems.o open.o dcache.o buffer.o dquot.o dcookies.o inode.o \
++              namei.o file_table.o
+ mod-subdirs :=        nls xfs
+ obj-y :=      open.o read_write.o devices.o file_table.o buffer.o \
+--- linux-2.4.22-ac1/fs/namei.c~nfs_export_kernel-2.4.22-rh    2003-09-26 00:57:27.000000000 +0400
++++ linux-2.4.22-ac1-alexey/fs/namei.c 2003-10-08 13:41:27.000000000 +0400
+@@ -22,6 +22,7 @@
+ #include <linux/dnotify.h>
+ #include <linux/smp_lock.h>
+ #include <linux/personality.h>
++#include <linux/module.h>
+ #include <asm/namei.h>
+ #include <asm/uaccess.h>
+@@ -100,6 +101,7 @@ void intent_release(struct lookup_intent
+               it->it_op_release(it);
+ }
++EXPORT_SYMBOL(intent_release);
+ /* In order to reduce some races, while at the same time doing additional
+  * checking and hopefully speeding things up, we copy filenames to the
+@@ -903,7 +905,8 @@ struct dentry * lookup_hash(struct qstr 
+ /* SMP-safe */
+-struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
++struct dentry * lookup_one_len_it(const char * name, struct dentry * base,
++                                  int len, struct lookup_intent *it)
+ {
+       unsigned long hash;
+       struct qstr this;
+@@ -923,11 +926,16 @@ struct dentry * lookup_one_len(const cha
+       }
+       this.hash = end_name_hash(hash);
+-      return lookup_hash_it(&this, base, NULL);
++      return lookup_hash_it(&this, base, it);
+ access:
+       return ERR_PTR(-EACCES);
+ }
++struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
++{
++      return lookup_one_len_it(name, base, len, NULL);
++}
++
+ /*
+  *    namei()
+  *
+--- linux-2.4.22-ac1/fs/nfsd/export.c~nfs_export_kernel-2.4.22-rh      2003-09-25 14:16:29.000000000 +0400
++++ linux-2.4.22-ac1-alexey/fs/nfsd/export.c   2003-10-08 13:41:27.000000000 +0400
+@@ -223,6 +223,11 @@ exp_export(struct nfsctl_export *nxp)
+       inode = nd.dentry->d_inode;
+       dev = inode->i_dev;
+       ino = inode->i_ino;
++      if ((inode->i_sb->s_type->fs_flags & FS_NFSEXP_FSID) &&
++          !(nxp->ex_flags & NFSEXP_FSID)) {
++          nxp->ex_dev = inode->i_sb->s_dev;
++          nxp->ex_flags |= NFSEXP_FSID;
++      }
+       err = -EINVAL;
+       exp = exp_get(clp, dev, ino);
+--- linux-2.4.22-ac1/fs/nfsd/nfsfh.c~nfs_export_kernel-2.4.22-rh       2003-08-25 15:44:43.000000000 +0400
++++ linux-2.4.22-ac1-alexey/fs/nfsd/nfsfh.c    2003-10-08 13:41:27.000000000 +0400
+@@ -36,6 +36,15 @@ struct nfsd_getdents_callback {
+       int sequence;           /* sequence counter */
+ };
++static struct dentry *lookup_it(struct inode *inode, struct dentry * dentry)
++{
++      if (inode->i_op->lookup_it)
++          return inode->i_op->lookup_it(inode, dentry, NULL, 0);
++      else
++          return inode->i_op->lookup(inode, dentry);
++              
++}
++
+ /*
+  * A rather strange filldir function to capture
+  * the name matching the specified inode number.
+@@ -75,6 +84,8 @@ static int nfsd_get_name(struct dentry *
+       int error;
+       struct file file;
+       struct nfsd_getdents_callback buffer;
++      struct lookup_intent it;
++      struct file *filp = NULL;
+       error = -ENOTDIR;
+       if (!dir || !S_ISDIR(dir->i_mode))
+@@ -85,9 +96,37 @@ static int nfsd_get_name(struct dentry *
+       /*
+        * Open the directory ...
+        */
+-      error = init_private_file(&file, dentry, FMODE_READ);
+-      if (error)
++      if (dentry->d_op && dentry->d_op->d_revalidate_it) {
++              if ((dentry->d_flags & DCACHE_NFSD_DISCONNECTED) &&
++                  (dentry->d_parent == dentry) ) {
++                      it.it_op_release = NULL;
++                      /* 
++                       * XXX Temporary Hack: Simulating init_private_file without
++                       * f_op->open for disconnected dentry Since we don't have actual
++                       * dentry->d_name to revalidate in revalidate_it()
++                       */
++                      filp = &file;
++                      memset(filp, 0, sizeof(*filp));
++                      filp->f_mode   = FMODE_READ;
++                      atomic_set(&filp->f_count, 1);
++                      filp->f_dentry = dentry;
++                      filp->f_uid = current->fsuid;
++                      filp->f_gid = current->fsgid;
++                      filp->f_op = dentry->d_inode->i_fop;
++                      error = 0;
++              } else {
++                      intent_init(&it, IT_OPEN, 0);
++                      error = revalidate_it(dentry, &it);
++                      if (error)
++                              goto out;
++                      error = init_private_file_it(&file, dentry, FMODE_READ, &it);
++              }
++      } else {
++              error = init_private_file_it(&file, dentry, FMODE_READ, NULL);
++      }
++      if (error) 
+               goto out;
++
+       error = -EINVAL;
+       if (!file.f_op->readdir)
+               goto out_close;
+@@ -113,9 +152,13 @@ static int nfsd_get_name(struct dentry *
+       }
+ out_close:
+-      if (file.f_op->release)
++      if (file.f_op->release && !filp)
+               file.f_op->release(dir, &file);
+ out:
++      if (dentry->d_op &&
++          dentry->d_op->d_revalidate_it &&
++          it.it_op_release && !filp)
++              intent_release(&it);
+       return error;
+ }
+@@ -274,7 +317,7 @@ struct dentry *nfsd_findparent(struct de
+        * it is well connected.  But nobody returns different dentrys do they?
+        */
+       down(&child->d_inode->i_sem);
+-      pdentry = child->d_inode->i_op->lookup(child->d_inode, tdentry);
++      pdentry = lookup_it(child->d_inode, tdentry);
+       up(&child->d_inode->i_sem);
+       d_drop(tdentry); /* we never want ".." hashed */
+       if (!pdentry && tdentry->d_inode == NULL) {
+@@ -306,6 +349,8 @@ struct dentry *nfsd_findparent(struct de
+                               igrab(tdentry->d_inode);
+                               pdentry->d_flags |= DCACHE_NFSD_DISCONNECTED;
+                       }
++                      if (child->d_op && child->d_op->d_revalidate_it)
++                              pdentry->d_op = child->d_op;
+               }
+               if (pdentry == NULL)
+                       pdentry = ERR_PTR(-ENOMEM);
+@@ -463,6 +508,8 @@ find_fh_dentry(struct super_block *sb, _
+               struct dentry *pdentry;
+               struct inode *parent;
++              if (result->d_op && result->d_op->d_revalidate_it)
++                      dentry->d_op = result->d_op;
+               pdentry = nfsd_findparent(dentry);
+               err = PTR_ERR(pdentry);
+               if (IS_ERR(pdentry))
+@@ -669,6 +716,11 @@ fh_verify(struct svc_rqst *rqstp, struct
+       inode = dentry->d_inode;
++      /* cache coherency for non-device filesystems */
++      if (inode->i_op && inode->i_op->revalidate_it) {
++          inode->i_op->revalidate_it(dentry, NULL);
++      }
++
+       /* Type check. The correct error return for type mismatches
+        * does not seem to be generally agreed upon. SunOS seems to
+        * use EISDIR if file isn't S_IFREG; a comment in the NFSv3
+@@ -902,8 +954,9 @@ out_negative:
+               dentry->d_parent->d_name.name, dentry->d_name.name);
+       goto out;
+ out_uptodate:
+-      printk(KERN_ERR "fh_update: %s/%s already up-to-date!\n",
+-              dentry->d_parent->d_name.name, dentry->d_name.name);
++      if(!dentry->d_parent->d_inode->i_op->mkdir_raw)
++              printk(KERN_ERR "fh_update: %s/%s already up-to-date!\n",
++                      dentry->d_parent->d_name.name, dentry->d_name.name);
+       goto out;
+ }
+--- linux-2.4.22-ac1/fs/nfsd/vfs.c~nfs_export_kernel-2.4.22-rh 2003-08-25 15:44:43.000000000 +0400
++++ linux-2.4.22-ac1-alexey/fs/nfsd/vfs.c      2003-10-08 13:41:27.000000000 +0400
+@@ -77,6 +77,128 @@ struct raparms {
+ static struct raparms *               raparml;
+ static struct raparms *               raparm_cache;
++static int link_raw(struct dentry *dold, struct dentry *ddir,
++                    struct dentry *dnew)
++{
++      int err;
++
++      struct nameidata old_nd = { .dentry = dold };
++      struct nameidata nd = { .dentry = ddir, .last = dnew->d_name };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->link_raw(&old_nd, &nd);
++      d_instantiate(dnew, dold->d_inode);
++      if(dold->d_inode->i_op && dold->d_inode->i_op->revalidate_it)
++              dold->d_inode->i_op->revalidate_it(dnew, NULL);
++
++      return err;
++}
++
++static int unlink_raw(struct dentry *dentry, char *fname, int flen,
++                      struct dentry *rdentry)
++{
++      int err;
++        struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->unlink_raw(&nd);
++      if (!err)
++              d_delete(rdentry);
++
++      return err;
++}
++
++static int rmdir_raw(struct dentry *dentry, char *fname, int flen,
++                     struct dentry *rdentry)
++{
++      int err;
++        struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->rmdir_raw(&nd);
++      if(!err) {
++              rdentry->d_inode->i_flags |= S_DEAD;
++              d_delete(rdentry);
++      }
++
++      return err;
++}
++
++static int symlink_raw(struct dentry *dentry,  char *fname, int flen,
++                       char *path)
++{
++      int err;
++        struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->symlink_raw(&nd, path);
++
++      return err;
++}
++
++static int mkdir_raw(struct dentry *dentry, char *fname, int flen, int mode)
++{
++      int err;
++        struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->mkdir_raw(&nd, mode);
++
++      return err;
++}
++
++static int mknod_raw(struct dentry *dentry, char *fname, int flen, int mode,
++                     dev_t dev)
++{
++      int err;
++        struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->mknod_raw(&nd, mode, dev);
++
++      return err;
++}     
++
++static int rename_raw(struct dentry *fdentry, struct dentry *tdentry,
++                      struct dentry *odentry, struct dentry *ndentry)
++{
++      int err;
++
++      struct nameidata old_nd = { .dentry = fdentry, .last = odentry->d_name};
++      struct nameidata new_nd = { .dentry = tdentry, .last = ndentry->d_name};
++      struct inode_operations *op = old_nd.dentry->d_inode->i_op;
++      err = op->rename_raw(&old_nd, &new_nd);
++      d_move(odentry, ndentry);
++
++      return err;
++}
++
++static int setattr_raw(struct inode *inode, struct iattr *iap)
++{
++      int err;
++
++      iap->ia_valid |= ATTR_RAW;
++      err = inode->i_op->setattr_raw(inode, iap);
++
++      return err;
++}
++
++int revalidate_it(struct dentry *dentry, struct lookup_intent *it)
++{
++      int err = 0;
++
++      if (dentry && dentry->d_op && dentry->d_op->d_revalidate_it) {
++              if (!dentry->d_op->d_revalidate_it(dentry, 0, it) &&
++                      !d_invalidate(dentry)) {
++                      dput(dentry);
++                      err = -EINVAL;
++                      dentry = NULL;
++                      return err;
++              }
++      }
++
++      return err;
++}
++
+ /*
+  * Look up one component of a pathname.
+  * N.B. After this call _both_ fhp and resfh need an fh_put
+@@ -302,7 +424,10 @@ nfsd_setattr(struct svc_rqst *rqstp, str
+       }
+       err = nfserr_notsync;
+       if (!check_guard || guardtime == inode->i_ctime) {
+-              err = notify_change(dentry, iap);
++              if ( dentry->d_inode->i_op && dentry->d_inode->i_op->setattr_raw)
++                      err = setattr_raw(dentry->d_inode, iap);
++              else
++                      err = notify_change(dentry, iap);
+               err = nfserrno(err);
+       }
+       if (size_change) {
+@@ -429,6 +554,7 @@ nfsd_open(struct svc_rqst *rqstp, struct
+ {
+       struct dentry   *dentry;
+       struct inode    *inode;
++      struct lookup_intent it;
+       int             err;
+       /* If we get here, then the client has already done an "open", and (hopefully)
+@@ -475,6 +601,14 @@ nfsd_open(struct svc_rqst *rqstp, struct
+               filp->f_mode  = FMODE_READ;
+       }
++      intent_init(&it, IT_OPEN, (filp->f_flags & ~O_ACCMODE) | filp->f_mode);
++
++      err = revalidate_it(dentry, &it);
++      if (err)
++              goto out_nfserr;
++      
++      filp->f_it = &it;
++      
+       err = 0;
+       if (filp->f_op && filp->f_op->open) {
+               err = filp->f_op->open(inode, filp);
+@@ -489,7 +623,11 @@ nfsd_open(struct svc_rqst *rqstp, struct
+                       atomic_dec(&filp->f_count);
+               }
+       }
++
+ out_nfserr:
++      if (it.it_op_release)
++              intent_release(&it);
++
+       if (err)
+               err = nfserrno(err);
+ out:
+@@ -820,7 +958,7 @@ nfsd_create(struct svc_rqst *rqstp, stru
+ {
+       struct dentry   *dentry, *dchild;
+       struct inode    *dirp;
+-      int             err;
++      int             err, error = -EOPNOTSUPP;
+       err = nfserr_perm;
+       if (!flen)
+@@ -836,20 +974,44 @@ nfsd_create(struct svc_rqst *rqstp, stru
+       dentry = fhp->fh_dentry;
+       dirp = dentry->d_inode;
++      switch (type) {
++                      case S_IFDIR:
++                              if (dirp->i_op->mkdir_raw)
++                          error = mkdir_raw(dentry, fname, flen, iap->ia_mode);
++                              break;
++                      case S_IFCHR:
++                      case S_IFBLK:
++                      case S_IFIFO:
++                      case S_IFSOCK:
++                      case S_IFREG:
++                          if (dirp->i_op->mknod_raw) {
++                                      if (type == S_IFREG)
++                                              rdev = 0;
++                                      error = mknod_raw(dentry, fname, flen, iap->ia_mode, rdev);
++                              }
++                              break;
++                              default:
++                      printk("nfsd: bad file type %o in nfsd_create\n", type);
++      }
++
+       err = nfserr_notdir;
+-      if(!dirp->i_op || !dirp->i_op->lookup)
++      if(!dirp->i_op || !(dirp->i_op->lookup || dirp->i_op->lookup_it))
+               goto out;
+       /*
+        * Check whether the response file handle has been verified yet.
+        * If it has, the parent directory should already be locked.
+        */
+-      if (!resfhp->fh_dentry) {
+-              /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */
+-              fh_lock(fhp);
++      if (!resfhp->fh_dentry || dirp->i_op->lookup_it) {
++              /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create
++                 and nfsd_proc_create in case of lustre
++              */
++              if (!resfhp->fh_dentry)
++                      fh_lock(fhp);
+               dchild = lookup_one_len(fname, dentry, flen);
+               err = PTR_ERR(dchild);
+               if (IS_ERR(dchild))
+                       goto out_nfserr;
++              resfhp->fh_dentry = NULL;
+               err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);
+               if (err)
+                       goto out;
+@@ -870,10 +1032,12 @@ nfsd_create(struct svc_rqst *rqstp, stru
+        * Make sure the child dentry is still negative ...
+        */
+       err = nfserr_exist;
+-      if (dchild->d_inode) {
+-              dprintk("nfsd_create: dentry %s/%s not negative!\n",
+-                      dentry->d_name.name, dchild->d_name.name);
+-              goto out; 
++      if ( error == -EOPNOTSUPP) {
++              if (dchild->d_inode) {
++                      dprintk("nfsd_create: dentry %s/%s not negative!\n",
++                              dentry->d_name.name, dchild->d_name.name);
++                      goto out; 
++              }
+       }
+       if (!(iap->ia_valid & ATTR_MODE))
+@@ -886,16 +1050,19 @@ nfsd_create(struct svc_rqst *rqstp, stru
+       err = nfserr_perm;
+       switch (type) {
+       case S_IFREG:
+-              err = vfs_create(dirp, dchild, iap->ia_mode);
++              if (error == -EOPNOTSUPP)
++                      err = vfs_create(dirp, dchild, iap->ia_mode);
+               break;
+       case S_IFDIR:
+-              err = vfs_mkdir(dirp, dchild, iap->ia_mode);
++              if (error == -EOPNOTSUPP)
++                      err = vfs_mkdir(dirp, dchild, iap->ia_mode);
+               break;
+       case S_IFCHR:
+       case S_IFBLK:
+       case S_IFIFO:
+       case S_IFSOCK:
+-              err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
++              if (error == -EOPNOTSUPP)       
++                      err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
+               break;
+       default:
+               printk("nfsd: bad file type %o in nfsd_create\n", type);
+@@ -964,7 +1131,13 @@ nfsd_create_v3(struct svc_rqst *rqstp, s
+       /* Get all the sanity checks out of the way before
+        * we lock the parent. */
+       err = nfserr_notdir;
+-      if(!dirp->i_op || !dirp->i_op->lookup)
++      if (dirp->i_op->mknod_raw) {
++              err = mknod_raw(dentry, fname, flen, iap->ia_mode, 0);
++              if (err && err != -EOPNOTSUPP)
++                      goto out;
++      }
++
++      if(!dirp->i_op ||  !(dirp->i_op->lookup || dirp->i_op->lookup_it))
+               goto out;
+       fh_lock(fhp);
+@@ -1015,6 +1188,8 @@ nfsd_create_v3(struct svc_rqst *rqstp, s
+               case NFS3_CREATE_GUARDED:
+                       err = nfserr_exist;
+               }
++              if(dirp->i_op->mknod_raw)
++                      err = 0;
+               goto out;
+       }
+@@ -1121,7 +1296,7 @@ nfsd_symlink(struct svc_rqst *rqstp, str
+                               struct iattr *iap)
+ {
+       struct dentry   *dentry, *dnew;
+-      int             err, cerr;
++      int             err, cerr, error = -EOPNOTSUPP;
+       err = nfserr_noent;
+       if (!flen || !plen)
+@@ -1135,12 +1310,18 @@ nfsd_symlink(struct svc_rqst *rqstp, str
+               goto out;
+       fh_lock(fhp);
+       dentry = fhp->fh_dentry;
++      
++      if (dentry->d_inode->i_op->symlink_raw)
++              error = symlink_raw(dentry, fname, flen, path);
++
+       dnew = lookup_one_len(fname, dentry, flen);
+       err = PTR_ERR(dnew);
+       if (IS_ERR(dnew))
+               goto out_nfserr;
+-      err = vfs_symlink(dentry->d_inode, dnew, path);
++      err = error;
++      if (err == -EOPNOTSUPP || !dentry->d_inode->i_op->symlink_raw)
++              err = vfs_symlink(dentry->d_inode, dnew, path);
+       if (!err) {
+               if (EX_ISSYNC(fhp->fh_export))
+                       nfsd_sync_dir(dentry);
+@@ -1210,7 +1391,10 @@ nfsd_link(struct svc_rqst *rqstp, struct
+       dold = tfhp->fh_dentry;
+       dest = dold->d_inode;
+-      err = vfs_link(dold, dirp, dnew);
++      if (dirp->i_op->link_raw)
++              err = link_raw(dold, ddir, dnew);
++      else
++              err = vfs_link(dold, dirp, dnew);
+       if (!err) {
+               if (EX_ISSYNC(ffhp->fh_export)) {
+                       nfsd_sync_dir(ddir);
+@@ -1295,7 +1479,10 @@ nfsd_rename(struct svc_rqst *rqstp, stru
+                       err = nfserr_perm;
+       } else
+ #endif
+-      err = vfs_rename(fdir, odentry, tdir, ndentry);
++      if(fdir->i_op->rename_raw)
++              err = rename_raw(fdentry, tdentry, odentry, ndentry);
++      else
++              err = vfs_rename(fdir, odentry, tdir, ndentry);
+       if (!err && EX_ISSYNC(tfhp->fh_export)) {
+               nfsd_sync_dir(tdentry);
+               nfsd_sync_dir(fdentry);
+@@ -1316,7 +1503,7 @@ nfsd_rename(struct svc_rqst *rqstp, stru
+       fill_post_wcc(tfhp);
+       double_up(&tdir->i_sem, &fdir->i_sem);
+       ffhp->fh_locked = tfhp->fh_locked = 0;
+-      
++
+ out:
+       return err;
+ }
+@@ -1362,9 +1549,15 @@ nfsd_unlink(struct svc_rqst *rqstp, stru
+                       err = nfserr_perm;
+               } else
+ #endif
+-              err = vfs_unlink(dirp, rdentry);
++              if (dirp->i_op->unlink_raw)
++                      err = unlink_raw(dentry, fname, flen, rdentry);
++              else
++                      err = vfs_unlink(dirp, rdentry);
+       } else { /* It's RMDIR */
+-              err = vfs_rmdir(dirp, rdentry);
++              if (dirp->i_op->rmdir_raw)
++                      err = rmdir_raw(dentry, fname, flen, rdentry);
++              else
++                      err = vfs_rmdir(dirp, rdentry);
+       }
+       dput(rdentry);
+--- linux-2.4.22-ac1/include/linux/fs.h~nfs_export_kernel-2.4.22-rh    2003-09-26 01:00:26.000000000 +0400
++++ linux-2.4.22-ac1-alexey/include/linux/fs.h 2003-10-08 13:44:53.000000000 +0400
+@@ -93,6 +93,9 @@ extern int leases_enable, dir_notify_ena
+ #define FS_SINGLE     8 /* Filesystem that can have only one superblock */
+ #define FS_NOMOUNT    16 /* Never mount from userland */
+ #define FS_LITTER     32 /* Keeps the tree in dcache */
++#define FS_NFSEXP_FSID  64 /* Use file system specific fsid for
++                          * exporting non device filesystems.
++                          */
+ #define FS_ALWAYS_REVAL       16384   /* Always revalidate dentries returned by
+                                  link_path_walk */
+ #define FS_ODD_RENAME 32768   /* Temporary stuff; will go away as soon
+@@ -1121,6 +1124,9 @@ extern int open_namei_it(const char *fil
+                        struct nameidata *nd, struct lookup_intent *it);
+ extern struct file *dentry_open_it(struct dentry *dentry, struct vfsmount *mnt,
+                           int flags, struct lookup_intent *it);
++extern int revalidate_it(struct dentry *dentry, struct lookup_intent *it);
++extern int init_private_file_it(struct file *, struct dentry *dentry, int mode,
++                                struct lookup_intent *it);
+ extern int filp_close(struct file *, fl_owner_t id);
+ extern char * getname(const char *);
+@@ -1420,6 +1426,8 @@ extern void path_release(struct nameidat
+ extern int follow_down(struct vfsmount **, struct dentry **);
+ extern int follow_up(struct vfsmount **, struct dentry **);
+ extern struct dentry * lookup_one_len(const char *, struct dentry *, int);
++extern struct dentry * lookup_one_len_it(const char *, struct dentry *, int,
++                                         struct lookup_intent *);
+ extern struct dentry * lookup_hash(struct qstr *, struct dentry *);
+ #define user_path_walk(name,nd)        __user_walk(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd)
+ #define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd)
+@@ -1439,7 +1447,8 @@ typedef int (*find_inode_t)(struct inode
+ extern struct inode * iget4_locked(struct super_block *, unsigned long,
+                                  find_inode_t, void *);
+-
++extern struct inode * ilookup4(struct super_block *, unsigned long,
++                               find_inode_t, void *);
+ static inline struct inode *iget4(struct super_block *sb, unsigned long ino,
+                                 find_inode_t find_actor, void *opaque)
+ {
+--- linux-2.4.22-ac1/kernel/ksyms.c~nfs_export_kernel-2.4.22-rh        2003-09-26 00:57:28.000000000 +0400
++++ linux-2.4.22-ac1-alexey/kernel/ksyms.c     2003-10-08 13:45:20.000000000 +0400
+@@ -165,6 +165,7 @@ EXPORT_SYMBOL(fget);
+ EXPORT_SYMBOL(igrab);
+ EXPORT_SYMBOL(iunique);
+ EXPORT_SYMBOL(iget4_locked);
++EXPORT_SYMBOL(ilookup4);
+ EXPORT_SYMBOL(unlock_new_inode);
+ EXPORT_SYMBOL(iput);
+ EXPORT_SYMBOL(inode_init_once);
+@@ -178,6 +179,7 @@ EXPORT_SYMBOL(path_walk);
+ EXPORT_SYMBOL(path_release);
+ EXPORT_SYMBOL(__user_walk);
+ EXPORT_SYMBOL(lookup_one_len);
++EXPORT_SYMBOL(lookup_one_len_it);
+ EXPORT_SYMBOL(lookup_hash);
+ EXPORT_SYMBOL(sys_close);
+ EXPORT_SYMBOL(dcache_lock);
+
+_
diff --git a/lustre/kernel_patches/patches/vfs_intent_2.6.0-test6.patch b/lustre/kernel_patches/patches/vfs_intent_2.6.0-test6.patch
new file mode 100644 (file)
index 0000000..5dd86e0
--- /dev/null
@@ -0,0 +1,754 @@
+ fs/exec.c              |   18 +++++++---
+ fs/namei.c             |   86 +++++++++++++++++++++++++++++++++++++++++++++----
+ fs/namespace.c         |    2 +
+ fs/nfs/dir.c           |    4 +-
+ fs/open.c              |   62 +++++++++++++++++++++++------------
+ fs/stat.c              |   24 ++++++++++---
+ include/linux/dcache.h |    3 +
+ include/linux/fs.h     |    8 ++++
+ include/linux/namei.h  |   56 ++++++++++++++++++++++++++-----
+ kernel/ksyms.c         |    8 ++++
+ 10 files changed, 222 insertions(+), 49 deletions(-)
+
+Index: linux-2.6.0-test6/fs/exec.c
+===================================================================
+--- linux-2.6.0-test6.orig/fs/exec.c   2003-10-07 15:14:14.000000000 +0800
++++ linux-2.6.0-test6/fs/exec.c        2003-10-07 15:33:15.000000000 +0800
+@@ -120,8 +120,11 @@
+       struct file * file;
+       struct nameidata nd;
+       int error;
++      intent_init(&nd.intent, IT_OPEN);
+-      nd.intent.open.flags = O_RDONLY;
++      error = user_path_walk_it(library, &nd);
++
++      nd.intent.it_flags = O_RDONLY;
+       error = __user_walk(library, LOOKUP_FOLLOW|LOOKUP_OPEN, &nd);
+       if (error)
+               goto out;
+@@ -134,7 +137,7 @@
+       if (error)
+               goto exit;
+-      file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
++      file = dentry_open_it(nd.dentry, nd.mnt, O_RDONLY, &nd.intent);
+       error = PTR_ERR(file);
+       if (IS_ERR(file))
+               goto out;
+@@ -471,8 +474,13 @@
+ struct file *open_exec(const char *name)
+ {
+       struct nameidata nd;
+-      int err = path_lookup(name, LOOKUP_FOLLOW, &nd);
+-      struct file *file = ERR_PTR(err);
++      int err;
++      struct file *file;
++
++      intent_init(&nd.intent, IT_OPEN);
++      nd.intent.it_flags = O_RDONLY;
++      err = path_lookup(name, LOOKUP_FOLLOW, &nd);
++      file = ERR_PTR(err);
+       if (!err) {
+               struct inode *inode = nd.dentry->d_inode;
+@@ -484,7 +492,7 @@
+                               err = -EACCES;
+                       file = ERR_PTR(err);
+                       if (!err) {
+-                              file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
++                              file = dentry_open_it(nd.dentry, nd.mnt, O_RDONLY, &nd.intent);
+                               if (!IS_ERR(file)) {
+                                       err = deny_write_access(file);
+                                       if (err) {
+Index: linux-2.6.0-test6/fs/namei.c
+===================================================================
+--- linux-2.6.0-test6.orig/fs/namei.c  2003-10-07 15:14:14.000000000 +0800
++++ linux-2.6.0-test6/fs/namei.c       2003-10-07 15:33:15.000000000 +0800
+@@ -264,8 +264,19 @@
+       return 0;
+ }
++void intent_release(struct lookup_intent *it)
++{
++      if (!it)
++              return;
++      if (it->it_magic != INTENT_MAGIC)
++              return;
++      if (it->it_op_release)
++              it->it_op_release(it);
++}
++
+ void path_release(struct nameidata *nd)
+ {
++      intent_release(&nd->intent);
+       dput(nd->dentry);
+       mntput(nd->mnt);
+ }
+@@ -342,7 +353,10 @@
+ {
+       struct dentry * result;
+       struct inode *dir = parent->d_inode;
++        int counter = 0;
++again:
++        counter++;
+       down(&dir->i_sem);
+       /*
+        * First re-do the cached lookup just in case it was created
+@@ -381,7 +395,10 @@
+       if (result->d_op && result->d_op->d_revalidate) {
+               if (!result->d_op->d_revalidate(result, nd) && !d_invalidate(result)) {
+                       dput(result);
+-                      result = ERR_PTR(-ENOENT);
++                        if (counter > 10)
++                                result = ERR_PTR(-ESTALE);
++                        if (!IS_ERR(result))
++                                goto again;
+               }
+       }
+       return result;
+@@ -556,6 +573,31 @@
+       return PTR_ERR(dentry);
+ }
++static int revalidate_special(struct nameidata *nd)
++{
++      struct dentry *dentry = nd->dentry;
++      int err, counter = 0;
++
++      if (!dentry->d_op || !dentry->d_op->d_revalidate)
++              return 0;
++ revalidate_again:
++      if (!dentry->d_op->d_revalidate(dentry, nd)) {
++              struct dentry *new;
++              if ((err = permission(dentry->d_parent->d_inode, MAY_EXEC,nd)))
++                      return err;
++              new = real_lookup(dentry->d_parent, &dentry->d_name, nd);
++              d_invalidate(dentry);
++              dput(dentry);
++              dentry = new;
++              counter++;
++              if (counter < 10)
++                      goto revalidate_again;
++              printk("excessive revalidate_it loops\n");
++              return -ESTALE;
++      }
++      return 0;
++}
++
+ /*
+  * Name resolution.
+  *
+@@ -656,7 +698,9 @@
+               if (inode->i_op->follow_link) {
+                       mntget(next.mnt);
++                      nd->flags |= LOOKUP_LINK_NOTLAST;
+                       err = do_follow_link(next.dentry, nd);
++                      nd->flags &= ~LOOKUP_LINK_NOTLAST;
+                       dput(next.dentry);
+                       mntput(next.mnt);
+                       if (err)
+@@ -695,6 +739,11 @@
+                               inode = nd->dentry->d_inode;
+                               /* fallthrough */
+                       case 1:
++                              nd->flags |= LOOKUP_LAST;
++                              err = revalidate_special(nd);
++                              nd->flags &= ~LOOKUP_LAST;
++                              if (err)
++                                      break;
+                               goto return_reval;
+               }
+               if (nd->dentry->d_op && nd->dentry->d_op->d_hash) {
+@@ -702,7 +751,9 @@
+                       if (err < 0)
+                               break;
+               }
++              nd->flags |= LOOKUP_LAST;
+               err = do_lookup(nd, &this, &next);
++              nd->flags &= ~LOOKUP_LAST;
+               if (err)
+                       break;
+               follow_mount(&next.mnt, &next.dentry);
+@@ -928,7 +979,7 @@
+ }
+ /* SMP-safe */
+-struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
++struct dentry * lookup_one_len_it(const char * name, struct dentry * base, int len, struct nameidata *nd)
+ {
+       unsigned long hash;
+       struct qstr this;
+@@ -948,11 +999,16 @@
+       }
+       this.hash = end_name_hash(hash);
+-      return lookup_hash(&this, base);
++      return __lookup_hash(&this, base, nd);
+ access:
+       return ERR_PTR(-EACCES);
+ }
++struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
++{
++      return lookup_one_len_it(name, base, len, NULL);
++}
++
+ /*
+  *    namei()
+  *
+@@ -964,11 +1020,12 @@
+  * that namei follows links, while lnamei does not.
+  * SMP-safe
+  */
+-int __user_walk(const char __user *name, unsigned flags, struct nameidata *nd)
++int __user_walk_it(const char __user *name, unsigned flags, struct nameidata *nd)
+ {
+       char *tmp = getname(name);
+       int err = PTR_ERR(tmp);
++
+       if (!IS_ERR(tmp)) {
+               err = path_lookup(tmp, flags, nd);
+               putname(tmp);
+@@ -976,6 +1033,12 @@
+       return err;
+ }
++int __user_walk(const char __user *name, unsigned flags, struct nameidata *nd)
++{
++      intent_init(&nd->intent, IT_LOOKUP);
++      return __user_walk_it(name, flags, nd);
++}
++
+ /*
+  * It's inline, so penalty for filesystems that don't use sticky bit is
+  * minimal.
+@@ -1248,8 +1311,8 @@
+               acc_mode |= MAY_APPEND;
+       /* Fill in the open() intent data */
+-      nd->intent.open.flags = flag;
+-      nd->intent.open.create_mode = mode;
++      nd->intent.it_flags = flag;
++      nd->intent.it_create_mode = mode;
+       /*
+        * The simplest case - just a plain lookup.
+@@ -1265,6 +1328,7 @@
+       /*
+        * Create - we need to know the parent.
+        */
++      nd->intent.it_op |= IT_CREAT;
+       error = path_lookup(pathname, LOOKUP_PARENT|LOOKUP_OPEN|LOOKUP_CREATE, nd);
+       if (error)
+               return error;
+@@ -1281,7 +1345,9 @@
+       dir = nd->dentry;
+       nd->flags &= ~LOOKUP_PARENT;
+       down(&dir->d_inode->i_sem);
++      nd->flags |= LOOKUP_LAST;
+       dentry = __lookup_hash(&nd->last, nd->dentry, nd);
++      nd->flags &= ~LOOKUP_LAST;
+ do_last:
+       error = PTR_ERR(dentry);
+@@ -1386,7 +1452,9 @@
+       }
+       dir = nd->dentry;
+       down(&dir->d_inode->i_sem);
++      nd->flags |= LOOKUP_LAST;
+       dentry = __lookup_hash(&nd->last, nd->dentry, nd);
++      nd->flags &= ~LOOKUP_LAST;
+       putname(nd->last.name);
+       goto do_last;
+ }
+@@ -2148,7 +2216,9 @@
+ __vfs_follow_link(struct nameidata *nd, const char *link)
+ {
+       int res = 0;
++      struct lookup_intent it = nd->intent;
+       char *name;
++
+       if (IS_ERR(link))
+               goto fail;
+@@ -2158,6 +2228,10 @@
+                       /* weird __emul_prefix() stuff did it */
+                       goto out;
+       }
++
++      intent_init(&nd->intent, it.it_op);
++      nd->intent.it_flags = it.it_flags;
++      nd->intent.it_create_mode = it.it_create_mode;
+       res = link_path_walk(link, nd);
+ out:
+       if (current->link_count || res || nd->last_type!=LAST_NORM)
+Index: linux-2.6.0-test6/fs/namespace.c
+===================================================================
+--- linux-2.6.0-test6.orig/fs/namespace.c      2003-09-28 08:50:31.000000000 +0800
++++ linux-2.6.0-test6/fs/namespace.c   2003-10-07 15:33:15.000000000 +0800
+@@ -738,6 +738,7 @@
+       int retval = 0;
+       int mnt_flags = 0;
++      intent_init(&nd.intent, IT_LOOKUP);
+       /* Discard magic */
+       if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
+               flags &= ~MS_MGC_MSK;
+@@ -947,6 +948,7 @@
+               mntput(old_pwdmnt);
+       }
+ }
++EXPORT_SYMBOL(set_fs_pwd);
+ static void chroot_fs_refs(struct nameidata *old_nd, struct nameidata *new_nd)
+ {
+Index: linux-2.6.0-test6/fs/open.c
+===================================================================
+--- linux-2.6.0-test6.orig/fs/open.c   2003-10-07 15:14:14.000000000 +0800
++++ linux-2.6.0-test6/fs/open.c        2003-10-07 15:33:15.000000000 +0800
+@@ -202,7 +202,7 @@
+       struct nameidata nd;
+       struct inode * inode;
+       int error;
+-
++      intent_init(&nd.intent, IT_GETATTR);
+       error = -EINVAL;
+       if (length < 0) /* sorry, but loff_t says... */
+               goto out;
+@@ -461,6 +461,7 @@
+       int old_fsuid, old_fsgid;
+       kernel_cap_t old_cap;
+       int res;
++      intent_init(&nd.intent, IT_GETATTR);
+       if (mode & ~S_IRWXO)    /* where's F_OK, X_OK, W_OK, R_OK? */
+               return -EINVAL;
+@@ -492,6 +493,7 @@
+               if(!res && (mode & S_IWOTH) && IS_RDONLY(nd.dentry->d_inode)
+                  && !special_file(nd.dentry->d_inode->i_mode))
+                       res = -EROFS;
++
+               path_release(&nd);
+       }
+@@ -506,6 +508,7 @@
+ {
+       struct nameidata nd;
+       int error;
++      intent_init(&nd.intent, IT_GETATTR);
+       error = __user_walk(filename, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &nd);
+       if (error)
+@@ -557,6 +560,7 @@
+ {
+       struct nameidata nd;
+       int error;
++      intent_init(&nd.intent, IT_GETATTR);
+       error = __user_walk(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY | LOOKUP_NOALT, &nd);
+       if (error)
+@@ -629,7 +633,7 @@
+       error = -EROFS;
+       if (IS_RDONLY(inode))
+               goto dput_and_out;
+-
++      
+       error = -EPERM;
+       if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+               goto dput_and_out;
+@@ -737,25 +741,8 @@
+  * for the internal routines (ie open_namei()/follow_link() etc). 00 is
+  * used by symlinks.
+  */
+-struct file *filp_open(const char * filename, int flags, int mode)
+-{
+-      int namei_flags, error;
+-      struct nameidata nd;
+-
+-      namei_flags = flags;
+-      if ((namei_flags+1) & O_ACCMODE)
+-              namei_flags++;
+-      if (namei_flags & O_TRUNC)
+-              namei_flags |= 2;
+-
+-      error = open_namei(filename, namei_flags, mode, &nd);
+-      if (!error)
+-              return dentry_open(nd.dentry, nd.mnt, flags);
+-
+-      return ERR_PTR(error);
+-}
+-
+-struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
++struct file *dentry_open_it(struct dentry *dentry, struct vfsmount *mnt, int flags,
++                          struct lookup_intent *it)
+ {
+       struct file * f;
+       struct inode *inode;
+@@ -767,6 +754,7 @@
+               goto cleanup_dentry;
+       f->f_flags = flags;
+       f->f_mode = (flags+1) & O_ACCMODE;
++      f->f_it = it;
+       inode = dentry->d_inode;
+       if (f->f_mode & FMODE_WRITE) {
+               error = get_write_access(inode);
+@@ -786,6 +774,7 @@
+               error = f->f_op->open(inode,f);
+               if (error)
+                       goto cleanup_all;
++              intent_release(it);
+       }
+       f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
+@@ -810,11 +799,42 @@
+ cleanup_file:
+       put_filp(f);
+ cleanup_dentry:
++      intent_release(it);
+       dput(dentry);
+       mntput(mnt);
+       return ERR_PTR(error);
+ }
++struct file *filp_open(const char * filename, int flags, int mode)
++{
++      int namei_flags, error;
++      struct file * temp_filp;
++      struct nameidata nd;
++      intent_init(&nd.intent, IT_OPEN);
++
++      namei_flags = flags;
++      if ((namei_flags+1) & O_ACCMODE)
++              namei_flags++;
++      if (namei_flags & O_TRUNC)
++              namei_flags |= 2;
++
++      error = open_namei(filename, namei_flags, mode, &nd);
++      if (!error) {
++              temp_filp = dentry_open_it(nd.dentry, nd.mnt, flags, &nd.intent);
++              return temp_filp;
++      }       
++      return ERR_PTR(error);
++}
++
++
++struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
++{
++      struct lookup_intent it;
++      intent_init(&it, IT_LOOKUP);
++
++      return dentry_open_it(dentry, mnt, flags, &it);
++}
++
+ /*
+  * Find an empty file descriptor entry, and mark it busy.
+  */
+Index: linux-2.6.0-test6/fs/stat.c
+===================================================================
+--- linux-2.6.0-test6.orig/fs/stat.c   2003-09-28 08:50:10.000000000 +0800
++++ linux-2.6.0-test6/fs/stat.c        2003-10-07 15:33:15.000000000 +0800
+@@ -33,7 +33,7 @@
+       stat->blksize = inode->i_blksize;
+ }
+-int vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
++int vfs_getattr_it(struct vfsmount *mnt, struct dentry *dentry, struct lookup_intent *it, struct kstat *stat)
+ {
+       struct inode *inode = dentry->d_inode;
+       int retval;
+@@ -44,6 +44,8 @@
+       if (inode->i_op->getattr)
+               return inode->i_op->getattr(mnt, dentry, stat);
++      if (inode->i_op->getattr_it)
++              return inode->i_op->getattr_it(mnt, dentry, it, stat);
+       generic_fillattr(inode, stat);
+       if (!stat->blksize) {
+@@ -56,14 +58,20 @@
+       return 0;
+ }
++int vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
++{
++      return vfs_getattr_it(mnt, dentry, NULL, stat);
++}
++
+ int vfs_stat(char __user *name, struct kstat *stat)
+ {
+       struct nameidata nd;
+       int error;
++      intent_init(&nd.intent, IT_GETATTR);
+-      error = user_path_walk(name, &nd);
++      error = user_path_walk_it(name, &nd);
+       if (!error) {
+-              error = vfs_getattr(nd.mnt, nd.dentry, stat);
++              error = vfs_getattr_it(nd.mnt, nd.dentry, &nd.intent, stat);
+               path_release(&nd);
+       }
+       return error;
+@@ -73,10 +81,11 @@
+ {
+       struct nameidata nd;
+       int error;
++      intent_init(&nd.intent, IT_GETATTR);
+-      error = user_path_walk_link(name, &nd);
++      error = user_path_walk_link_it(name, &nd);
+       if (!error) {
+-              error = vfs_getattr(nd.mnt, nd.dentry, stat);
++              error = vfs_getattr_it(nd.mnt, nd.dentry, &nd.intent, stat);
+               path_release(&nd);
+       }
+       return error;
+@@ -86,9 +95,12 @@
+ {
+       struct file *f = fget(fd);
+       int error = -EBADF;
++      struct nameidata nd;
++      intent_init(&nd.intent, IT_GETATTR);
+       if (f) {
+-              error = vfs_getattr(f->f_vfsmnt, f->f_dentry, stat);
++              error = vfs_getattr_it(f->f_vfsmnt, f->f_dentry, &nd.intent, stat);
++              intent_release(&nd.intent);
+               fput(f);
+       }
+       return error;
+Index: linux-2.6.0-test6/include/linux/dcache.h
+===================================================================
+--- linux-2.6.0-test6.orig/include/linux/dcache.h      2003-09-28 08:51:16.000000000 +0800
++++ linux-2.6.0-test6/include/linux/dcache.h   2003-10-07 15:33:15.000000000 +0800
+@@ -4,6 +4,7 @@
+ #ifdef __KERNEL__
+ #include <asm/atomic.h>
++#include <linux/string.h>
+ #include <linux/list.h>
+ #include <linux/spinlock.h>
+ #include <linux/cache.h>
+@@ -35,6 +36,8 @@
+       char name_str[0];
+ };
++#include <linux/namei.h>
++
+ struct dentry_stat_t {
+       int nr_dentry;
+       int nr_unused;
+Index: linux-2.6.0-test6/include/linux/fs.h
+===================================================================
+--- linux-2.6.0-test6.orig/include/linux/fs.h  2003-10-07 15:14:15.000000000 +0800
++++ linux-2.6.0-test6/include/linux/fs.h       2003-10-07 15:34:10.000000000 +0800
+@@ -243,6 +243,8 @@
+ #define ATTR_ATTR_FLAG        1024
+ #define ATTR_KILL_SUID        2048
+ #define ATTR_KILL_SGID        4096
++#define ATTR_RAW              8192    /* file system, not vfs will massage attrs */
++#define ATTR_FROM_OPEN        16384    /* called from open path, ie O_TRUNC */
+ /*
+  * This is the Inode Attributes structure, used for notify_change().  It
+@@ -402,6 +404,7 @@
+       struct block_device     *i_bdev;
+       struct cdev             *i_cdev;
+       int                     i_cindex;
++      void                    *i_filterdata;
+       unsigned long           i_dnotify_mask; /* Directory notify events */
+       struct dnotify_struct   *i_dnotify; /* for directory notifications */
+@@ -530,6 +533,7 @@
+       struct list_head        f_ep_links;
+       spinlock_t              f_ep_lock;
+       struct address_space    *f_mapping;
++      struct lookup_intent    *f_it;
+ };
+ extern spinlock_t files_lock;
+ #define file_list_lock() spin_lock(&files_lock);
+@@ -839,7 +843,9 @@
+       void (*truncate) (struct inode *);
+       int (*permission) (struct inode *, int, struct nameidata *);
+       int (*setattr) (struct dentry *, struct iattr *);
++      int (*setattr_raw) (struct inode *, struct iattr *);
+       int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
++      int (*getattr_it) (struct vfsmount *, struct dentry *, struct lookup_intent *, 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);
+@@ -1052,6 +1058,7 @@
+ extern int unregister_filesystem(struct file_system_type *);
+ extern struct vfsmount *kern_mount(struct file_system_type *);
+ extern int may_umount(struct vfsmount *);
++struct vfsmount *do_kern_mount(const char *type, int flags, const char *name, void *data);
+ extern long do_mount(char *, char *, char *, unsigned long, void *);
+ extern int vfs_statfs(struct super_block *, struct kstatfs *);
+@@ -1119,6 +1126,7 @@
+ extern struct file *filp_open(const char *, int, int);
+ extern struct file * dentry_open(struct dentry *, struct vfsmount *, int);
++extern struct file * dentry_open_it(struct dentry *, struct vfsmount *, int, struct lookup_intent *);
+ extern int filp_close(struct file *, fl_owner_t id);
+ extern char * getname(const char __user *);
+Index: linux-2.6.0-test6/include/linux/namei.h
+===================================================================
+--- linux-2.6.0-test6.orig/include/linux/namei.h       2003-09-28 08:50:15.000000000 +0800
++++ linux-2.6.0-test6/include/linux/namei.h    2003-10-07 15:33:15.000000000 +0800
+@@ -2,25 +2,55 @@
+ #define _LINUX_NAMEI_H
+ #include <linux/linkage.h>
++#include <linux/string.h>
+ struct vfsmount;
++struct nameidata;
+-struct open_intent {
+-      int     flags;
+-      int     create_mode;
++/* intent opcodes */
++#define IT_OPEN     (1)
++#define IT_CREAT    (1<<1)
++#define IT_READDIR  (1<<2)
++#define IT_GETATTR  (1<<3)
++#define IT_LOOKUP   (1<<4)
++#define IT_UNLINK   (1<<5)
++#define IT_TRUNC    (1<<6)
++#define IT_GETXATTR (1<<7)
++
++struct lustre_intent_data {
++      int       it_disposition;
++      int       it_status;
++      __u64     it_lock_handle;
++      void     *it_data;
++      int       it_lock_mode;
+ };
++#define INTENT_MAGIC 0x19620323
++struct lookup_intent {
++      int     it_magic;
++      void    (*it_op_release)(struct lookup_intent *);
++      int     it_op;
++      int     it_flags;
++      int     it_create_mode;
++      union {
++              struct lustre_intent_data lustre;
++      } d;
++};
++
++static inline void intent_init(struct lookup_intent *it, int op)
++{
++      memset(it, 0, sizeof(*it));
++      it->it_magic = INTENT_MAGIC;
++      it->it_op = op;
++}
++
+ struct nameidata {
+       struct dentry   *dentry;
+       struct vfsmount *mnt;
+       struct qstr     last;
+       unsigned int    flags;
+       int             last_type;
+-
+-      /* Intent data */
+-      union {
+-              struct open_intent open;
+-      } intent;
++      struct lookup_intent intent;
+ };
+ /*
+@@ -41,6 +71,9 @@
+ #define LOOKUP_CONTINUE                4
+ #define LOOKUP_PARENT         16
+ #define LOOKUP_NOALT          32
++#define LOOKUP_LAST            (1<<6)
++#define LOOKUP_LINK_NOTLAST    (1<<7)
++
+ /*
+  * Intent data
+  */
+@@ -49,6 +82,12 @@
+ #define LOOKUP_ACCESS         (0x0400)
+ extern int FASTCALL(__user_walk(const char __user *, unsigned, struct nameidata *));
++extern int FASTCALL(__user_walk_it(const char __user *name, unsigned flags, struct nameidata *nd));
++#define user_path_walk_it(name,nd) \
++      __user_walk_it(name, LOOKUP_FOLLOW, nd)
++#define user_path_walk_link_it(name,nd) \
++      __user_walk_it(name, 0, nd)
++extern void intent_release(struct lookup_intent *);
+ #define user_path_walk(name,nd) \
+       __user_walk(name, LOOKUP_FOLLOW, nd)
+ #define user_path_walk_link(name,nd) \
+@@ -60,7 +99,6 @@
+ extern struct dentry * lookup_one_len(const char *, struct dentry *, int);
+ extern struct dentry * lookup_hash(struct qstr *, struct dentry *);
+-
+ extern int follow_down(struct vfsmount **, struct dentry **);
+ extern int follow_up(struct vfsmount **, struct dentry **);
+Index: linux-2.6.0-test6/kernel/ksyms.c
+===================================================================
+--- linux-2.6.0-test6.orig/kernel/ksyms.c      2003-10-07 15:21:57.000000000 +0800
++++ linux-2.6.0-test6/kernel/ksyms.c   2003-10-07 15:33:15.000000000 +0800
+@@ -220,11 +220,18 @@
+ EXPORT_SYMBOL(unregister_filesystem);
+ EXPORT_SYMBOL(__mntput);
+ EXPORT_SYMBOL(may_umount);
++EXPORT_SYMBOL(reparent_to_init);
+ /* interrupt handling */
+ EXPORT_SYMBOL(request_irq);
+ EXPORT_SYMBOL(free_irq);
++/* lustre */
++EXPORT_SYMBOL(do_kern_mount);
++EXPORT_SYMBOL(exit_files);
++//EXPORT_SYMBOL(kmem_cache_validate);
++
++
+ /* waitqueue handling */
+ EXPORT_SYMBOL(add_wait_queue);
+ EXPORT_SYMBOL(add_wait_queue_exclusive);
+Index: linux-2.6.0-test6/fs/nfs/dir.c
+===================================================================
+--- linux-2.6.0-test6.orig/fs/nfs/dir.c        2003-09-28 08:50:20.000000000 +0800
++++ linux-2.6.0-test6/fs/nfs/dir.c     2003-10-07 15:33:15.000000000 +0800
+@@ -652,7 +652,7 @@
+               return 0;
+       if (!nd || (nd->flags & LOOKUP_CONTINUE) || !(nd->flags & LOOKUP_CREATE))
+               return 0;
+-      return (nd->intent.open.flags & O_EXCL) != 0;
++      return (nd->intent.it_flags & O_EXCL) != 0;
+ }
+ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
+@@ -825,7 +825,7 @@
+       attr.ia_valid = ATTR_MODE;
+       if (nd && (nd->flags & LOOKUP_CREATE))
+-              open_flags = nd->intent.open.flags;
++              open_flags = nd->intent.it_flags;
+       /*
+        * The 0 argument passed into the create function should one day
+Index: linux-2.6.0-test6/fs/inode.c
+===================================================================
+--- linux-2.6.0-test6.orig/fs/inode.c  2003-10-07 15:14:14.000000000 +0800
++++ linux-2.6.0-test6/fs/inode.c       2003-10-07 15:38:08.000000000 +0800
+@@ -224,6 +224,7 @@
+       inodes_stat.nr_unused--;
+ }
++EXPORT_SYMBOL(__iget);
+ /**
+  * clear_inode - clear an inode
+  * @inode: inode to clear
diff --git a/lustre/kernel_patches/patches/vfs_nointent_2.6.0-test6.patch b/lustre/kernel_patches/patches/vfs_nointent_2.6.0-test6.patch
new file mode 100644 (file)
index 0000000..7c2ea35
--- /dev/null
@@ -0,0 +1,411 @@
+ 0 files changed
+
+Index: linux-2.6.0-test6/fs/namei.c
+===================================================================
+--- linux-2.6.0-test6.orig/fs/namei.c  2003-10-07 15:33:15.000000000 +0800
++++ linux-2.6.0-test6/fs/namei.c       2003-10-07 15:39:16.000000000 +0800
+@@ -1270,7 +1270,7 @@
+               if (!error) {
+                       DQUOT_INIT(inode);
+                       
+-                      error = do_truncate(dentry, 0);
++                      error = do_truncate(dentry, 0, 1);
+               }
+               put_write_access(inode);
+               if (error)
+@@ -1521,6 +1521,7 @@
+       char * tmp;
+       struct dentry * dentry;
+       struct nameidata nd;
++      intent_init(&nd.intent, IT_LOOKUP);
+       if (S_ISDIR(mode))
+               return -EPERM;
+@@ -1531,6 +1532,15 @@
+       error = path_lookup(tmp, LOOKUP_PARENT, &nd);
+       if (error)
+               goto out;
++
++      if (nd.dentry->d_inode->i_op->mknod_raw) {
++              struct inode_operations *op = nd.dentry->d_inode->i_op;
++              error = op->mknod_raw(&nd, mode, dev);
++              /* the file system wants to use normal vfs path now */
++              if (error != -EOPNOTSUPP)
++                      goto out2;
++      }
++
+       dentry = lookup_create(&nd, 0);
+       error = PTR_ERR(dentry);
+@@ -1557,6 +1567,7 @@
+               dput(dentry);
+       }
+       up(&nd.dentry->d_inode->i_sem);
++out2:
+       path_release(&nd);
+ out:
+       putname(tmp);
+@@ -1598,10 +1609,18 @@
+       if (!IS_ERR(tmp)) {
+               struct dentry *dentry;
+               struct nameidata nd;
++                intent_init(&nd.intent, IT_LOOKUP);
+               error = path_lookup(tmp, LOOKUP_PARENT, &nd);
+               if (error)
+                       goto out;
++              if (nd.dentry->d_inode->i_op->mkdir_raw) {
++                      struct inode_operations *op = nd.dentry->d_inode->i_op;
++                      error = op->mkdir_raw(&nd, mode);
++                      /* the file system wants to use normal vfs path now */
++                      if (error != -EOPNOTSUPP)
++                              goto out2;
++              }
+               dentry = lookup_create(&nd, 1);
+               error = PTR_ERR(dentry);
+               if (!IS_ERR(dentry)) {
+@@ -1611,6 +1630,7 @@
+                       dput(dentry);
+               }
+               up(&nd.dentry->d_inode->i_sem);
++out2:
+               path_release(&nd);
+ out:
+               putname(tmp);
+@@ -1691,6 +1711,7 @@
+       char * name;
+       struct dentry *dentry;
+       struct nameidata nd;
++        intent_init(&nd.intent, IT_LOOKUP);
+       name = getname(pathname);
+       if(IS_ERR(name))
+@@ -1711,6 +1732,16 @@
+                       error = -EBUSY;
+                       goto exit1;
+       }
++ 
++      if (nd.dentry->d_inode->i_op->rmdir_raw) {
++              struct inode_operations *op = nd.dentry->d_inode->i_op;
++ 
++              error = op->rmdir_raw(&nd);
++              /* the file system wants to use normal vfs path now */
++              if (error != -EOPNOTSUPP)
++                      goto exit1;
++      }
++ 
+       down(&nd.dentry->d_inode->i_sem);
+       dentry = lookup_hash(&nd.last, nd.dentry);
+       error = PTR_ERR(dentry);
+@@ -1769,6 +1800,7 @@
+       struct dentry *dentry;
+       struct nameidata nd;
+       struct inode *inode = NULL;
++        intent_init(&nd.intent, IT_LOOKUP);
+       name = getname(pathname);
+       if(IS_ERR(name))
+@@ -1780,6 +1812,13 @@
+       error = -EISDIR;
+       if (nd.last_type != LAST_NORM)
+               goto exit1;
++      if (nd.dentry->d_inode->i_op->unlink_raw) {
++              struct inode_operations *op = nd.dentry->d_inode->i_op;
++              error = op->unlink_raw(&nd);
++              /* the file system wants to use normal vfs path now */
++              if (error != -EOPNOTSUPP)
++                      goto exit1;
++      }
+       down(&nd.dentry->d_inode->i_sem);
+       dentry = lookup_hash(&nd.last, nd.dentry);
+       error = PTR_ERR(dentry);
+@@ -1847,10 +1886,18 @@
+       if (!IS_ERR(to)) {
+               struct dentry *dentry;
+               struct nameidata nd;
++                intent_init(&nd.intent, IT_LOOKUP);
+               error = path_lookup(to, LOOKUP_PARENT, &nd);
+               if (error)
+                       goto out;
++              if (nd.dentry->d_inode->i_op->symlink_raw) {
++                      struct inode_operations *op = nd.dentry->d_inode->i_op;
++                      error = op->symlink_raw(&nd, from);
++                      /* the file system wants to use normal vfs path now */
++                      if (error != -EOPNOTSUPP)
++                              goto out2;
++              }
+               dentry = lookup_create(&nd, 0);
+               error = PTR_ERR(dentry);
+               if (!IS_ERR(dentry)) {
+@@ -1858,6 +1905,7 @@
+                       dput(dentry);
+               }
+               up(&nd.dentry->d_inode->i_sem);
++out2:
+               path_release(&nd);
+ out:
+               putname(to);
+@@ -1921,6 +1969,8 @@
+       struct nameidata nd, old_nd;
+       int error;
+       char * to;
++        intent_init(&nd.intent, IT_LOOKUP);
++        intent_init(&old_nd.intent, IT_LOOKUP);
+       to = getname(newname);
+       if (IS_ERR(to))
+@@ -1935,6 +1985,13 @@
+       error = -EXDEV;
+       if (old_nd.mnt != nd.mnt)
+               goto out_release;
++        if (nd.dentry->d_inode->i_op->link_raw) {
++                struct inode_operations *op = nd.dentry->d_inode->i_op;
++                error = op->link_raw(&old_nd, &nd);
++                /* the file system wants to use normal vfs path now */
++                if (error != -EOPNOTSUPP)
++                        goto out_release;
++        }
+       new_dentry = lookup_create(&nd, 0);
+       error = PTR_ERR(new_dentry);
+       if (!IS_ERR(new_dentry)) {
+@@ -1985,7 +2042,7 @@
+  *       locking].
+  */
+ int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
+-             struct inode *new_dir, struct dentry *new_dentry)
++                   struct inode *new_dir, struct dentry *new_dentry)
+ {
+       int error = 0;
+       struct inode *target;
+@@ -2030,7 +2087,7 @@
+ }
+ int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
+-             struct inode *new_dir, struct dentry *new_dentry)
++                     struct inode *new_dir, struct dentry *new_dentry)
+ {
+       struct inode *target;
+       int error;
+@@ -2107,6 +2164,8 @@
+       struct dentry * old_dentry, *new_dentry;
+       struct dentry * trap;
+       struct nameidata oldnd, newnd;
++        intent_init(&oldnd.intent, IT_LOOKUP);
++        intent_init(&newnd.intent, IT_LOOKUP);
+       error = path_lookup(oldname, LOOKUP_PARENT, &oldnd);
+       if (error)
+@@ -2129,6 +2188,13 @@
+       if (newnd.last_type != LAST_NORM)
+               goto exit2;
++      if (old_dir->d_inode->i_op->rename_raw) {
++              error = old_dir->d_inode->i_op->rename_raw(&oldnd, &newnd);
++              /* the file system wants to use normal vfs path now */
++              if (error != -EOPNOTSUPP)
++                      goto exit2;
++      }
++
+       trap = lock_rename(new_dir, old_dir);
+       old_dentry = lookup_hash(&oldnd.last, old_dir);
+@@ -2160,8 +2226,7 @@
+       if (new_dentry == trap)
+               goto exit5;
+-      error = vfs_rename(old_dir->d_inode, old_dentry,
+-                                 new_dir->d_inode, new_dentry);
++      error = vfs_rename(old_dir->d_inode, old_dentry, new_dir->d_inode, new_dentry);
+ exit5:
+       dput(new_dentry);
+ exit4:
+Index: linux-2.6.0-test6/fs/open.c
+===================================================================
+--- linux-2.6.0-test6.orig/fs/open.c   2003-10-07 15:33:15.000000000 +0800
++++ linux-2.6.0-test6/fs/open.c        2003-10-07 15:40:41.000000000 +0800
+@@ -178,9 +178,10 @@
+       return error;
+ }
+-int do_truncate(struct dentry *dentry, loff_t length)
++int do_truncate(struct dentry *dentry, loff_t length, int called_from_open)
+ {
+       int err;
++      struct inode_operations *op = dentry->d_inode->i_op;
+       struct iattr newattrs;
+       /* Not pretty: "inode->i_size" shouldn't really be signed. But it is. */
+@@ -191,7 +192,14 @@
+       newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
+       down(&dentry->d_inode->i_sem);
+       down_write(&dentry->d_inode->i_alloc_sem);
+-      err = notify_change(dentry, &newattrs);
++      if (called_from_open)
++              newattrs.ia_valid |= ATTR_FROM_OPEN;
++      if (op->setattr_raw) {
++              newattrs.ia_valid |= ATTR_RAW;
++              newattrs.ia_ctime = CURRENT_TIME;
++              err = op->setattr_raw(dentry->d_inode, &newattrs);
++      } else 
++                err = notify_change(dentry, &newattrs);
+       up_write(&dentry->d_inode->i_alloc_sem);
+       up(&dentry->d_inode->i_sem);
+       return err;
+@@ -247,7 +255,7 @@
+       error = locks_verify_truncate(inode, NULL, length);
+       if (!error) {
+               DQUOT_INIT(inode);
+-              error = do_truncate(nd.dentry, length);
++              error = do_truncate(nd.dentry, length, 0);
+       }
+       put_write_access(inode);
+@@ -299,7 +307,7 @@
+       error = locks_verify_truncate(inode, file, length);
+       if (!error)
+-              error = do_truncate(dentry, length);
++              error = do_truncate(dentry, length, 0);
+ out_putf:
+       fput(file);
+ out:
+@@ -378,9 +386,19 @@
+                   (error = permission(inode,MAY_WRITE,&nd)) != 0)
+                       goto dput_and_out;
+       }
+-      down(&inode->i_sem);
+-      error = notify_change(nd.dentry, &newattrs);
+-      up(&inode->i_sem);
++      if (inode->i_op->setattr_raw) {
++              struct inode_operations *op = nd.dentry->d_inode->i_op;
++
++              newattrs.ia_valid |= ATTR_RAW;
++              error = op->setattr_raw(inode, &newattrs);
++              /* the file system wants to use normal vfs path now */
++              if (error != -EOPNOTSUPP)
++                      goto dput_and_out;
++      } else {
++                down(&inode->i_sem);
++                error = notify_change(nd.dentry, &newattrs);
++                up(&inode->i_sem);
++        }
+ dput_and_out:
+       path_release(&nd);
+ out:
+@@ -431,9 +449,19 @@
+                   (error = permission(inode,MAY_WRITE,&nd)) != 0)
+                       goto dput_and_out;
+       }
+-      down(&inode->i_sem);
+-      error = notify_change(nd.dentry, &newattrs);
+-      up(&inode->i_sem);
++      if (inode->i_op->setattr_raw) {
++              struct inode_operations *op = nd.dentry->d_inode->i_op;
++
++              newattrs.ia_valid |= ATTR_RAW;
++              error = op->setattr_raw(inode, &newattrs);
++              /* the file system wants to use normal vfs path now */
++              if (error != -EOPNOTSUPP)
++                      goto dput_and_out;
++      } else {
++                down(&inode->i_sem);
++                error = notify_change(nd.dentry, &newattrs);
++                up(&inode->i_sem);
++        }
+ dput_and_out:
+       path_release(&nd);
+ out:
+@@ -634,6 +662,18 @@
+       if (IS_RDONLY(inode))
+               goto dput_and_out;
+       
++      if (inode->i_op->setattr_raw) {
++              struct inode_operations *op = nd.dentry->d_inode->i_op;
++
++              newattrs.ia_mode = mode;
++              newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
++              newattrs.ia_valid |= ATTR_RAW;
++              error = op->setattr_raw(inode, &newattrs);
++              /* the file system wants to use normal vfs path now */
++              if (error != -EOPNOTSUPP)
++                      goto dput_and_out;
++      }
++
+       error = -EPERM;
+       if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+               goto dput_and_out;
+@@ -667,6 +707,18 @@
+       if (IS_RDONLY(inode))
+               goto out;
+       error = -EPERM;
++      if (inode->i_op->setattr_raw) {
++              struct inode_operations *op = dentry->d_inode->i_op;
++
++              newattrs.ia_uid = user;
++              newattrs.ia_gid = group;
++              newattrs.ia_valid = ATTR_UID | ATTR_GID;
++              newattrs.ia_valid |= ATTR_RAW;
++              error = op->setattr_raw(inode, &newattrs);
++              /* the file system wants to use normal vfs path now */
++              if (error != -EOPNOTSUPP)
++                      return error;
++      }
+       if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+               goto out;
+       newattrs.ia_valid =  ATTR_CTIME;
+@@ -680,6 +732,7 @@
+       }
+       if (!S_ISDIR(inode->i_mode))
+               newattrs.ia_valid |= ATTR_KILL_SUID|ATTR_KILL_SGID;
++
+       down(&inode->i_sem);
+       error = notify_change(dentry, &newattrs);
+       up(&inode->i_sem);
+Index: linux-2.6.0-test6/include/linux/fs.h
+===================================================================
+--- linux-2.6.0-test6.orig/include/linux/fs.h  2003-10-07 15:34:10.000000000 +0800
++++ linux-2.6.0-test6/include/linux/fs.h       2003-10-07 15:39:17.000000000 +0800
+@@ -831,13 +831,20 @@
+       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 (*link_raw) (struct nameidata *,struct nameidata *);
+       int (*unlink) (struct inode *,struct dentry *);
++      int (*unlink_raw) (struct nameidata *);
+       int (*symlink) (struct inode *,struct dentry *,const char *);
++      int (*symlink_raw) (struct nameidata *,const char *);
+       int (*mkdir) (struct inode *,struct dentry *,int);
++      int (*mkdir_raw) (struct nameidata *,int);
+       int (*rmdir) (struct inode *,struct dentry *);
++      int (*rmdir_raw) (struct nameidata *);
+       int (*mknod) (struct inode *,struct dentry *,int,dev_t);
++      int (*mknod_raw) (struct nameidata *,int,dev_t);
+       int (*rename) (struct inode *, struct dentry *,
+                       struct inode *, struct dentry *);
++      int (*rename_raw) (struct nameidata *, struct nameidata *);
+       int (*readlink) (struct dentry *, char __user *,int);
+       int (*follow_link) (struct dentry *, struct nameidata *);
+       void (*truncate) (struct inode *);
+@@ -1122,7 +1129,7 @@
+ asmlinkage long sys_open(const char __user *, int, int);
+ asmlinkage long sys_close(unsigned int);      /* yes, it's really unsigned */
+-extern int do_truncate(struct dentry *, loff_t start);
++extern int do_truncate(struct dentry *, loff_t start, int called_from_open);
+ extern struct file *filp_open(const char *, int, int);
+ extern struct file * dentry_open(struct dentry *, struct vfsmount *, int);
+Index: linux-2.6.0-test6/fs/exec.c
+===================================================================
+--- linux-2.6.0-test6.orig/fs/exec.c   2003-10-07 15:33:15.000000000 +0800
++++ linux-2.6.0-test6/fs/exec.c        2003-10-07 15:39:17.000000000 +0800
+@@ -1390,7 +1390,7 @@
+               goto close_fail;
+       if (!file->f_op->write)
+               goto close_fail;
+-      if (do_truncate(file->f_dentry, 0) != 0)
++      if (do_truncate(file->f_dentry, 0, 0) != 0)
+               goto close_fail;
+       retval = binfmt->core_dump(signr, regs, file);
diff --git a/lustre/kernel_patches/pc/ext3-ea-in-inode-2.4.22-rh.pc b/lustre/kernel_patches/pc/ext3-ea-in-inode-2.4.22-rh.pc
new file mode 100644 (file)
index 0000000..56f6fdf
--- /dev/null
@@ -0,0 +1,6 @@
+fs/ext3/ialloc.c
+fs/ext3/inode.c
+fs/ext3/super.c
+fs/ext3/xattr.c
+include/linux/ext3_fs.h
+include/linux/ext3_fs_i.h
diff --git a/lustre/kernel_patches/pc/nfs_export_kernel-2.4.20-hp.pc b/lustre/kernel_patches/pc/nfs_export_kernel-2.4.20-hp.pc
new file mode 100644 (file)
index 0000000..e70ab4d
--- /dev/null
@@ -0,0 +1,9 @@
+fs/file_table.c
+fs/inode.c
+fs/Makefile
+fs/namei.c
+fs/nfsd/export.c
+fs/nfsd/nfsfh.c
+fs/nfsd/vfs.c
+include/linux/fs.h
+kernel/ksyms.c
diff --git a/lustre/kernel_patches/pc/nfs_export_kernel-2.4.20-rh.pc b/lustre/kernel_patches/pc/nfs_export_kernel-2.4.20-rh.pc
new file mode 100644 (file)
index 0000000..e70ab4d
--- /dev/null
@@ -0,0 +1,9 @@
+fs/file_table.c
+fs/inode.c
+fs/Makefile
+fs/namei.c
+fs/nfsd/export.c
+fs/nfsd/nfsfh.c
+fs/nfsd/vfs.c
+include/linux/fs.h
+kernel/ksyms.c
diff --git a/lustre/kernel_patches/pc/nfs_export_kernel-2.4.22-rh.pc b/lustre/kernel_patches/pc/nfs_export_kernel-2.4.22-rh.pc
new file mode 100644 (file)
index 0000000..e70ab4d
--- /dev/null
@@ -0,0 +1,9 @@
+fs/file_table.c
+fs/inode.c
+fs/Makefile
+fs/namei.c
+fs/nfsd/export.c
+fs/nfsd/nfsfh.c
+fs/nfsd/vfs.c
+include/linux/fs.h
+kernel/ksyms.c
index 0c364b5..38a0e3a 100644 (file)
@@ -21,3 +21,4 @@ jbd-dont-account-blocks-twice.patch
 jbd-commit-tricks.patch
 add_page_private.patch
 socket-exports-2.4.22-rh.patch
+nfs_export_kernel-2.4.22-rh
diff --git a/lustre/lvfs/Makefile.mk b/lustre/lvfs/Makefile.mk
new file mode 100644 (file)
index 0000000..c866ba9
--- /dev/null
@@ -0,0 +1,4 @@
+include $(src)/../portals/Kernelenv
+
+obj-y += lvfs.o fsfilt_ext3.o 
+lvfs-objs := fsfilt.o  fsfilt_ext3.o lvfs_common.o  lvfs_linux.o 
index 0696bd7..9e9261f 100644 (file)
@@ -7,5 +7,5 @@ include $(src)/../portals/Kernelenv
 
 obj-y += mds.o
 mds-objs := mds_lov.o handler.o mds_reint.o mds_fs.o lproc_mds.o mds_open.o \
-               mds_lib.o
+               mds_lib.o mds_unlink_open.o
        
diff --git a/lustre/obdclass/llog_internal.h b/lustre/obdclass/llog_internal.h
new file mode 100644 (file)
index 0000000..c364f3f
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __LLOG_INTERNAL_H__
+#define __LLOG_INTERNAL_H__
+
+int llog_get_cat_list(struct obd_device *obd, struct obd_device *disk_obd, 
+                      char *name, int count, struct llog_logid *idarray);
+int llog_put_cat_list(struct obd_device *obd, struct obd_device *disk_obd, 
+                      char *name, int count, struct llog_logid *);
+#endif
index 69ae296..cea5a32 100644 (file)
@@ -58,7 +58,7 @@ extern unsigned int portal_cerror;
 #define D_IOCTL     (1 << 7) /* ioctl related information */
 #define D_BLOCKS    (1 << 8) /* ext2 block allocation */
 #define D_NET       (1 << 9) /* network communications */
-#define D_WARNING   (1 << 10)
+#define D_WARNING   (1 << 10) /* CWARN(...) == CDEBUG (D_WARNING, ...) */
 #define D_BUFFS     (1 << 11)
 #define D_OTHER     (1 << 12)
 #define D_DENTRY    (1 << 13)
@@ -757,6 +757,39 @@ do {                                                                    \
  * USER LEVEL STUFF BELOW
  */
 
+#define PORTALS_CFG_VERSION 0x00010001;
+
+struct portals_cfg {
+        __u32 pcfg_version;
+        __u32 pcfg_command;
+
+        __u32 pcfg_nal;
+        __u32 pcfg_flags;
+
+        __u64 pcfg_nid;
+        __u64 pcfg_nid2;
+        __u64 pcfg_nid3;
+        __u32 pcfg_id;
+        __u32 pcfg_misc;
+        __u32 pcfg_fd;
+        __u32 pcfg_count;
+        __u32 pcfg_size;
+        __u32 pcfg_wait;
+
+        __u32 pcfg_plen1; /* buffers in userspace */
+        char *pcfg_pbuf1;
+        __u32 pcfg_plen2; /* buffers in userspace */
+        char *pcfg_pbuf2;
+};
+
+#define PCFG_INIT(pcfg, cmd)                            \
+do {                                                    \
+        memset(&pcfg, 0, sizeof(pcfg));                 \
+        pcfg.pcfg_version = PORTALS_CFG_VERSION;        \
+        pcfg.pcfg_command = (cmd);                      \
+                                                        \
+} while (0)
+
 #define PORTAL_IOCTL_VERSION 0x00010007
 #define PING_SYNC       0
 #define PING_ASYNC      1
@@ -1034,11 +1067,20 @@ struct lustre_peer {
         ptl_handle_ni_t peer_ni;
 };
 
+
 /* module.c */
-typedef int (*nal_cmd_handler_t)(struct portal_ioctl_data *, void * private);
+typedef int (*nal_cmd_handler_t)(struct portals_cfg *, void * private);
 int kportal_nal_register(int nal, nal_cmd_handler_t handler, void * private);
 int kportal_nal_unregister(int nal);
 
+enum cfg_record_type {
+        PORTALS_CFG_TYPE = 1,
+        LUSTRE_CFG_TYPE = 123,
+};
+
+typedef int (*cfg_record_cb_t)(enum cfg_record_type, int len, void *data);
+int kportal_nal_cmd(struct portals_cfg *);
+
 ptl_handle_ni_t *kportal_get_ni (int nal);
 void kportal_put_ni (int nal);
 
index a528a80..14d60c6 100644 (file)
@@ -42,6 +42,11 @@ static inline int size_round (int val)
         return (val + 7) & (~0x7);
 }
 
+static inline int size_round16(int val)
+{
+        return (val + 0xf) & (~0xf);
+}
+
 static inline int size_round0(int val)
 {
         if (!val)
index d389aab..5f266e2 100644 (file)
@@ -18,8 +18,8 @@
 #include <unistd.h>
 #include <sys/time.h>
 #include <portals/types.h>
-#include <portals/ptlctl.h>
 #include <linux/kp30.h>
+#include <portals/ptlctl.h>
 #include <linux/limits.h>
 #include <asm/page.h>
 #include <linux/version.h>
index 7763f1b..0466494 100644 (file)
@@ -71,6 +71,8 @@ int jt_dbg_mark_debug_buf(int argc, char **argv);
 int jt_dbg_modules(int argc, char **argv);
 int jt_dbg_panic(int argc, char **argv);
 
+int ptl_set_cfg_record_cb(cfg_record_cb_t cb);
+
 /* l_ioctl.c */
 int register_ioc_dev(int dev_id, const char * dev_name);
 void unregister_ioc_dev(int dev_id);
index fdde839..2db6c9b 100644 (file)
@@ -159,7 +159,11 @@ typedef struct     _gmnal_msghdr {
  *     transmit descriptors on the free list)
  */
 typedef struct _gmnal_rxtwe {
-       gm_recv_event_t *rx;
+       void                    *buffer;
+       unsigned                snode;
+       unsigned                sport;
+       unsigned                type;
+       unsigned                length;
        struct _gmnal_rxtwe     *next;
 } gmnal_rxtwe_t;
 
@@ -408,10 +412,10 @@ int               gmnal_start_kernel_threads(gmnal_data_t *);
  */
 int            gmnal_ct_thread(void *); /* caretaker thread */
 int            gmnal_rx_thread(void *); /* receive thread */
-int            gmnal_pre_receive(gmnal_data_t*, gm_recv_t*, int);
-int            gmnal_rx_bad(gmnal_data_t *, gm_recv_t *, gmnal_srxd_t *);
+int            gmnal_pre_receive(gmnal_data_t*, gmnal_rxtwe_t*, int);
+int            gmnal_rx_bad(gmnal_data_t *, gmnal_rxtwe_t *, gmnal_srxd_t*);
 int            gmnal_rx_requeue_buffer(gmnal_data_t *, gmnal_srxd_t *);
-int            gmnal_add_rxtwe(gmnal_data_t *, gm_recv_event_t *);
+int            gmnal_add_rxtwe(gmnal_data_t *, gm_recv_t *);
 gmnal_rxtwe_t * gmnal_get_rxtwe(gmnal_data_t *);
 void           gmnal_remove_rxtwe(gmnal_data_t *);
 
index cdafba9..4472e30 100644 (file)
@@ -113,12 +113,12 @@ kqswnal_init(int interface, ptl_pt_index_t ptl_size, ptl_ac_index_t ac_size,
 }
 
 int
-kqswnal_get_tx_desc (struct portal_ioctl_data *data)
+kqswnal_get_tx_desc (struct portals_cfg *pcfg)
 {
        unsigned long      flags;
        struct list_head  *tmp;
        kqswnal_tx_t      *ktx;
-       int                index = data->ioc_count;
+       int                index = pcfg->pcfg_count;
        int                rc = -ENOENT;
 
        spin_lock_irqsave (&kqswnal_data.kqn_idletxd_lock, flags);
@@ -129,13 +129,13 @@ kqswnal_get_tx_desc (struct portal_ioctl_data *data)
 
                ktx = list_entry (tmp, kqswnal_tx_t, ktx_list);
 
-               data->ioc_pbuf1 = (char *)ktx;
-               data->ioc_count = NTOH__u32(ktx->ktx_wire_hdr->type);
-               data->ioc_size  = NTOH__u32(PTL_HDR_LENGTH(ktx->ktx_wire_hdr));
-               data->ioc_nid   = NTOH__u64(ktx->ktx_wire_hdr->dest_nid);
-               data->ioc_nid2  = ktx->ktx_nid;
-               data->ioc_misc  = ktx->ktx_launcher;
-               data->ioc_flags = (list_empty (&ktx->ktx_delayed_list) ? 0 : 1) |
+               pcfg->pcfg_pbuf1 = (char *)ktx;
+               pcfg->pcfg_count = NTOH__u32(ktx->ktx_wire_hdr->type);
+               pcfg->pcfg_size  = NTOH__u32(PTL_HDR_LENGTH(ktx->ktx_wire_hdr));
+               pcfg->pcfg_nid   = NTOH__u64(ktx->ktx_wire_hdr->dest_nid);
+               pcfg->pcfg_nid2  = ktx->ktx_nid;
+               pcfg->pcfg_misc  = ktx->ktx_launcher;
+               pcfg->pcfg_flags = (list_empty (&ktx->ktx_delayed_list) ? 0 : 1) |
                                  (!ktx->ktx_isnblk                    ? 0 : 2) |
                                  (ktx->ktx_state << 2);
                rc = 0;
@@ -147,21 +147,21 @@ kqswnal_get_tx_desc (struct portal_ioctl_data *data)
 }
 
 int
-kqswnal_cmd (struct portal_ioctl_data *data, void *private)
+kqswnal_cmd (struct portals_cfg *pcfg, void *private)
 {
-       LASSERT (data != NULL);
+       LASSERT (pcfg != NULL);
        
-       switch (data->ioc_nal_cmd) {
+       switch (pcfg->pcfg_command) {
        case NAL_CMD_GET_TXDESC:
-               return (kqswnal_get_tx_desc (data));
+               return (kqswnal_get_tx_desc (pcfg));
 
        case NAL_CMD_REGISTER_MYNID:
                CDEBUG (D_IOCTL, "setting NID offset to "LPX64" (was "LPX64")\n",
-                       data->ioc_nid - kqswnal_data.kqn_elanid,
+                       pcfg->pcfg_nid - kqswnal_data.kqn_elanid,
                        kqswnal_data.kqn_nid_offset);
                kqswnal_data.kqn_nid_offset =
-                       data->ioc_nid - kqswnal_data.kqn_elanid;
-               kqswnal_lib.ni.nid = data->ioc_nid;
+                       pcfg->pcfg_nid - kqswnal_data.kqn_elanid;
+               kqswnal_lib.ni.nid = pcfg->pcfg_nid;
                return (0);
                
        default:
index 33f950e..c72717d 100644 (file)
@@ -1219,27 +1219,27 @@ ksocknal_push (ptl_nid_t nid)
 }
 
 int
-ksocknal_cmd(struct portal_ioctl_data * data, void * private)
+ksocknal_cmd(struct portals_cfg *pcfg, void * private)
 {
         int rc = -EINVAL;
 
-        LASSERT (data != NULL);
+        LASSERT (pcfg != NULL);
 
-        switch(data->ioc_nal_cmd) {
+        switch(pcfg->pcfg_command) {
         case NAL_CMD_GET_AUTOCONN: {
-                ksock_route_t *route = ksocknal_get_route_by_idx (data->ioc_count);
+                ksock_route_t *route = ksocknal_get_route_by_idx (pcfg->pcfg_count);
 
                 if (route == NULL)
                         rc = -ENOENT;
                 else {
                         rc = 0;
-                        data->ioc_nid   = route->ksnr_peer->ksnp_nid;
-                        data->ioc_id    = route->ksnr_ipaddr;
-                        data->ioc_misc  = route->ksnr_port;
-                        data->ioc_count = route->ksnr_generation;
-                        data->ioc_size  = route->ksnr_buffer_size;
-                        data->ioc_wait  = route->ksnr_sharecount;
-                        data->ioc_flags = (route->ksnr_nonagel      ? 1 : 0) |
+                        pcfg->pcfg_nid   = route->ksnr_peer->ksnp_nid;
+                        pcfg->pcfg_id    = route->ksnr_ipaddr;
+                        pcfg->pcfg_misc  = route->ksnr_port;
+                        pcfg->pcfg_count = route->ksnr_generation;
+                        pcfg->pcfg_size  = route->ksnr_buffer_size;
+                        pcfg->pcfg_wait  = route->ksnr_sharecount;
+                        pcfg->pcfg_flags = (route->ksnr_nonagel      ? 1 : 0) |
                                           (route->ksnr_xchange_nids ? 2 : 0) |
                                           (route->ksnr_irq_affinity ? 4 : 0) |
                                           (route->ksnr_eager        ? 8 : 0);
@@ -1248,56 +1248,56 @@ ksocknal_cmd(struct portal_ioctl_data * data, void * private)
                 break;
         }
         case NAL_CMD_ADD_AUTOCONN: {
-                rc = ksocknal_add_route (data->ioc_nid, data->ioc_id,
-                                         data->ioc_misc, data->ioc_size,
-                                         (data->ioc_flags & 0x01) != 0,
-                                         (data->ioc_flags & 0x02) != 0,
-                                         (data->ioc_flags & 0x04) != 0,
-                                         (data->ioc_flags & 0x08) != 0,
-                                         (data->ioc_flags & 0x10) != 0);
+                rc = ksocknal_add_route (pcfg->pcfg_nid, pcfg->pcfg_id,
+                                         pcfg->pcfg_misc, pcfg->pcfg_size,
+                                         (pcfg->pcfg_flags & 0x01) != 0,
+                                         (pcfg->pcfg_flags & 0x02) != 0,
+                                         (pcfg->pcfg_flags & 0x04) != 0,
+                                         (pcfg->pcfg_flags & 0x08) != 0,
+                                         (pcfg->pcfg_flags & 0x10) != 0);
                 break;
         }
         case NAL_CMD_DEL_AUTOCONN: {
-                rc = ksocknal_del_route (data->ioc_nid, data->ioc_id, 
-                                         (data->ioc_flags & 1) != 0,
-                                         (data->ioc_flags & 2) != 0);
+                rc = ksocknal_del_route (pcfg->pcfg_nid, pcfg->pcfg_id, 
+                                         (pcfg->pcfg_flags & 1) != 0,
+                                         (pcfg->pcfg_flags & 2) != 0);
                 break;
         }
         case NAL_CMD_GET_CONN: {
-                ksock_conn_t *conn = ksocknal_get_conn_by_idx (data->ioc_count);
+                ksock_conn_t *conn = ksocknal_get_conn_by_idx (pcfg->pcfg_count);
 
                 if (conn == NULL)
                         rc = -ENOENT;
                 else {
                         rc = 0;
-                        data->ioc_nid  = conn->ksnc_peer->ksnp_nid;
-                        data->ioc_id   = conn->ksnc_ipaddr;
-                        data->ioc_misc = conn->ksnc_port;
+                        pcfg->pcfg_nid  = conn->ksnc_peer->ksnp_nid;
+                        pcfg->pcfg_id   = conn->ksnc_ipaddr;
+                        pcfg->pcfg_misc = conn->ksnc_port;
                         ksocknal_put_conn (conn);
                 }
                 break;
         }
         case NAL_CMD_REGISTER_PEER_FD: {
-                struct socket *sock = sockfd_lookup (data->ioc_fd, &rc);
+                struct socket *sock = sockfd_lookup (pcfg->pcfg_fd, &rc);
 
                 if (sock != NULL) {
-                        rc = ksocknal_create_conn (data->ioc_nid, NULL,
-                                                   sock, data->ioc_flags);
+                        rc = ksocknal_create_conn (pcfg->pcfg_nid, NULL,
+                                                   sock, pcfg->pcfg_flags);
                         if (rc != 0)
                                 fput (sock->file);
                 }
                 break;
         }
         case NAL_CMD_CLOSE_CONNECTION: {
-                rc = ksocknal_close_conn (data->ioc_nid, data->ioc_id);
+                rc = ksocknal_close_conn (pcfg->pcfg_nid, pcfg->pcfg_id);
                 break;
         }
         case NAL_CMD_REGISTER_MYNID: {
-                rc = ksocknal_set_mynid (data->ioc_nid);
+                rc = ksocknal_set_mynid (pcfg->pcfg_nid);
                 break;
         }
         case NAL_CMD_PUSH_CONNECTION: {
-                rc = ksocknal_push (data->ioc_nid);
+                rc = ksocknal_push (pcfg->pcfg_nid);
                 break;
         }
         }
index dc7e447..a85b281 100644 (file)
@@ -354,23 +354,23 @@ ktoenal_free_buffers (void)
 }
 
 int
-ktoenal_cmd(struct portal_ioctl_data * data, void * private)
+ktoenal_cmd(struct portals_cfg *pcfg, void * private)
 {
         int rc = -EINVAL;
 
-        LASSERT (data != NULL);
+        LASSERT (pcfg != NULL);
 
-        switch(data->ioc_nal_cmd) {
+        switch(pcfg->pcfg_command) {
         case NAL_CMD_REGISTER_PEER_FD: {
-                rc = ktoenal_add_sock(data->ioc_nid, data->ioc_fd);
+                rc = ktoenal_add_sock(pcfg->pcfg_nid, pcfg->pcfg_fd);
                 break;
         }
         case NAL_CMD_CLOSE_CONNECTION: {
-                rc = ktoenal_close_sock(data->ioc_nid);
+                rc = ktoenal_close_sock(pcfg->pcfg_nid);
                 break;
         }
         case NAL_CMD_REGISTER_MYNID: {
-                rc = ktoenal_set_mynid (data->ioc_nid);
+                rc = ktoenal_set_mynid (pcfg->pcfg_nid);
                 break;
         }
         }
index 8282141..f92511a 100644 (file)
@@ -300,7 +300,7 @@ ktoenal_process_transmit (ksock_conn_t *conn, long *irq_flags)
                         rc = 0;                 /* nothing sent */
                 else
                 {
-                        /* FIXME: handle socket errors properly */
+                        //warning FIXME: handle socket errors properly
                         CERROR ("Error socknal send(%d) %p: %d\n", tx->tx_nob, conn, rc);
                         rc = tx->tx_nob;        /* kid on for now whole packet went */
                 }
@@ -862,7 +862,7 @@ ktoenal_process_receive (ksock_conn_t *conn, long *irq_flags)
                 if (len != -EAGAIN &&           /* ! nothing to read now */
                     len != 0)                   /* ! nothing to read ever */
                 {
-                        /* FIXME: handle socket errors properly */
+                        // warning FIXME: handle socket errors properly
                         CERROR ("Error socknal read(%d) %p: %d\n",
                                 conn->ksnc_rx_nob_wanted, conn, len);
                 }
index 9aa838f..c201429 100644 (file)
@@ -6,4 +6,4 @@
 include fs/lustre/portals/Kernelenv
 
 obj-y += libcfs.o
-libcfs-objs    := module.o proc.o debug.o
+libcfs-objs    := module.o proc.o debug.o lwt.o
index 308158b..6beae25 100644 (file)
@@ -207,17 +207,19 @@ kportal_get_route(int index, __u32 *gateway_nalidp, ptl_nid_t *gateway_nidp,
         return (rc);
 }
 
-static int
-kportal_nal_cmd(int nal, struct portal_ioctl_data *data)
+int
+kportal_nal_cmd(struct portals_cfg *pcfg)
 {
+        __u32 nal = pcfg->pcfg_nal;
         int rc = -EINVAL;
 
         ENTRY;
 
         down(&nal_cmd_sem);
         if (nal > 0 && nal <= NAL_MAX_NR && nal_cmd[nal].nch_handler) {
-                CDEBUG(D_IOCTL, "calling handler nal: %d, cmd: %d\n", nal, data->ioc_nal_cmd);
-                rc = nal_cmd[nal].nch_handler(data, nal_cmd[nal].nch_private);
+                CDEBUG(D_IOCTL, "calling handler nal: %d, cmd: %d\n", nal, 
+                       pcfg->pcfg_command);
+                rc = nal_cmd[nal].nch_handler(pcfg, nal_cmd[nal].nch_private);
         }
         up(&nal_cmd_sem);
         RETURN(rc);
@@ -445,15 +447,25 @@ static int kportal_ioctl(struct inode *inode, struct file *file,
                 break;
         }
 
-        case IOC_PORTAL_NAL_CMD:
-                CDEBUG (D_IOCTL, "nal command nal %d cmd %d\n", data->ioc_nal,
-                        data->ioc_nal_cmd);
-                err = kportal_nal_cmd(data->ioc_nal, data);
+        case IOC_PORTAL_NAL_CMD: {
+                struct portals_cfg pcfg;
+
+                LASSERT (data->ioc_plen1 == sizeof(pcfg));
+                err = copy_from_user(&pcfg, (void *)data->ioc_pbuf1, 
+                                     sizeof(pcfg));
+                if ( err ) {
+                        EXIT;
+                        return err;
+                }
+
+                CDEBUG (D_IOCTL, "nal command nal %d cmd %d\n", pcfg.pcfg_nal,
+                        pcfg.pcfg_command);
+                err = kportal_nal_cmd(&pcfg);
                 if (err == 0)
                         if (copy_to_user((char *)arg, data, sizeof (*data)))
                                 err = -EFAULT;
                 break;
-
+        }
         case IOC_PORTAL_FAIL_NID: {
                 const ptl_handle_ni_t *nip;
 
@@ -643,6 +655,7 @@ EXPORT_SYMBOL(kportal_assertion_failed);
 EXPORT_SYMBOL(dispatch_name);
 EXPORT_SYMBOL(kportal_get_ni);
 EXPORT_SYMBOL(kportal_put_ni);
+EXPORT_SYMBOL(kportal_nal_cmd);
 
 module_init(init_kportals_module);
 module_exit (exit_kportals_module);
index 415eda6..be6949c 100644 (file)
@@ -396,8 +396,7 @@ int do_PtlMDUpdate_internal(nal_cb_t * nal, void *private, void *v_args,
             test_eq->sequence == args->sequence_in) {
                 lib_me_t *me = md->me;
 
-                /* XXX this does not track eq refcounts properly */
-
+                // #warning this does not track eq refcounts properly 
                 ret->rc = lib_md_build(nal, md, private,
                                        new, &new->eventq, md->unlink);
 
index dc9e4ed..4ace247 100644 (file)
@@ -71,7 +71,11 @@ typedef struct
 
 typedef struct
 {
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+        struct work_struct        kpru_tq;
+#else
         struct tq_struct        kpru_tq;
+#endif
         int                     kpru_nal_id;
         ptl_nid_t               kpru_nid;
         int                     kpru_alive;
index c6590db..9fb2759 100644 (file)
@@ -409,6 +409,7 @@ int main(int argc, char **argv)
                 int len = sizeof(clntaddr);
                 int cfd;
                 struct portal_ioctl_data data;
+                struct portals_cfg pcfg;
                 ptl_nid_t peer_nid;
                 
                 cfd = accept(fd, (struct sockaddr *)&clntaddr, &len);
@@ -441,13 +442,16 @@ int main(int argc, char **argv)
                 }
 
                 show_connection (cfd, clntaddr.sin_addr.s_addr, peer_nid);
-                
+
+                PCFG_INIT(pcfg, NAL_CMD_REGISTER_PEER_FD);
+                pcfg.pcfg_nal = nal;
+                pcfg.pcfg_fd = cfd;
+                pcfg.pcfg_nid = peer_nid;
+                pcfg.pcfg_flags = bind_irq;
+
                 PORTAL_IOC_INIT(data);
-                data.ioc_fd = cfd;
-                data.ioc_nal = nal;
-                data.ioc_nal_cmd = NAL_CMD_REGISTER_PEER_FD;
-                data.ioc_nid = peer_nid;
-                data.ioc_flags = bind_irq;
+                data.ioc_pbuf1 = (char*)&pcfg;
+                data.ioc_plen1 = sizeof(pcfg);
                 
                 if (ioctl(pfd, IOC_PORTAL_NAL_CMD, &data) < 0) {
                         perror("ioctl failed");
index c5e374f..94ac0f1 100644 (file)
@@ -84,6 +84,38 @@ static name2num_t nalnames[] = {
         {NULL,         -1}
 };
 
+static cfg_record_cb_t g_record_cb;
+
+int 
+ptl_set_cfg_record_cb(cfg_record_cb_t cb)
+{
+        g_record_cb = cb;
+        return 0;
+}
+
+int 
+pcfg_ioctl(struct portals_cfg *pcfg) 
+{
+        int rc;
+
+        pcfg->pcfg_nal    = g_nal;
+
+        if (g_record_cb) {
+                rc = g_record_cb(PORTALS_CFG_TYPE, sizeof(*pcfg), pcfg);
+        } else {
+                struct portal_ioctl_data data;
+                PORTAL_IOC_INIT (data);
+                data.ioc_pbuf1   = (char*)pcfg;
+                data.ioc_plen1   = sizeof(*pcfg);
+
+                rc = l_ioctl (PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
+        }
+
+        return (rc);
+}
+
+
+
 static name2num_t *
 name2num_lookup_name (name2num_t *table, char *str)
 {
@@ -402,7 +434,7 @@ int jt_ptl_network(int argc, char **argv)
 int 
 jt_ptl_print_autoconnects (int argc, char **argv)
 {
-        struct portal_ioctl_data data;
+        struct portals_cfg        pcfg;
         char                     buffer[64];
         int                      index;
         int                      rc;
@@ -411,24 +443,22 @@ jt_ptl_print_autoconnects (int argc, char **argv)
                 return -1;
 
         for (index = 0;;index++) {
-                PORTAL_IOC_INIT (data);
-                data.ioc_nal     = g_nal;
-                data.ioc_nal_cmd = NAL_CMD_GET_AUTOCONN;
-                data.ioc_count   = index;
-                
-                rc = l_ioctl (PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
+                PCFG_INIT (pcfg, NAL_CMD_GET_AUTOCONN);
+                pcfg.pcfg_count   = index;
+
+                rc = pcfg_ioctl (&pcfg);
                 if (rc != 0)
                         break;
 
                 printf (LPX64"@%s:%d #%d buffer %d nonagle %s xchg %s "
                         "affinity %s eager %s share %d\n",
-                        data.ioc_nid, ptl_ipaddr_2_str (data.ioc_id, buffer),
-                        data.ioc_misc, data.ioc_count, data.ioc_size, 
-                        (data.ioc_flags & 1) ? "on" : "off",
-                        (data.ioc_flags & 2) ? "on" : "off",
-                        (data.ioc_flags & 4) ? "on" : "off",
-                        (data.ioc_flags & 8) ? "on" : "off",
-                        data.ioc_wait);
+                        pcfg.pcfg_nid, ptl_ipaddr_2_str (pcfg.pcfg_id, buffer),
+                        pcfg.pcfg_misc, pcfg.pcfg_count, pcfg.pcfg_size, 
+                        (pcfg.pcfg_flags & 1) ? "on" : "off",
+                        (pcfg.pcfg_flags & 2) ? "on" : "off",
+                        (pcfg.pcfg_flags & 4) ? "on" : "off",
+                        (pcfg.pcfg_flags & 8) ? "on" : "off",
+                        pcfg.pcfg_wait);
         }
 
         if (index == 0)
@@ -439,7 +469,7 @@ jt_ptl_print_autoconnects (int argc, char **argv)
 int 
 jt_ptl_add_autoconnect (int argc, char **argv)
 {
-        struct portal_ioctl_data data;
+        struct portals_cfg        pcfg;
         ptl_nid_t                nid;
         __u32                    ip;
         int                      port;
@@ -497,21 +527,19 @@ jt_ptl_add_autoconnect (int argc, char **argv)
                         }
         }
 
-        PORTAL_IOC_INIT (data);
-        data.ioc_nal     = g_nal;
-        data.ioc_nal_cmd = NAL_CMD_ADD_AUTOCONN;
-        data.ioc_nid     = nid;
-        data.ioc_id      = ip;
-        data.ioc_misc    = port;
+        PCFG_INIT(pcfg, NAL_CMD_ADD_AUTOCONN);
+        pcfg.pcfg_nid     = nid;
+        pcfg.pcfg_id      = ip;
+        pcfg.pcfg_misc    = port;
         /* only passing one buffer size! */
-        data.ioc_size    = MAX (g_socket_rxmem, g_socket_txmem);
-        data.ioc_flags   = (g_socket_nonagle ? 0x01 : 0) |
+        pcfg.pcfg_size    = MAX (g_socket_rxmem, g_socket_txmem);
+        pcfg.pcfg_flags   = (g_socket_nonagle ? 0x01 : 0) |
                            (xchange_nids     ? 0x02 : 0) |
                            (irq_affinity     ? 0x04 : 0) |
                            (share            ? 0x08 : 0) |
                            (eager            ? 0x10 : 0);
 
-        rc = l_ioctl (PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
+        rc = pcfg_ioctl (&pcfg);
         if (rc != 0) {
                 fprintf (stderr, "failed to enable autoconnect: %s\n",
                          strerror (errno));
@@ -524,7 +552,7 @@ jt_ptl_add_autoconnect (int argc, char **argv)
 int 
 jt_ptl_del_autoconnect (int argc, char **argv)
 {
-        struct portal_ioctl_data data;
+        struct portals_cfg       pcfg;
         ptl_nid_t                nid = PTL_NID_ANY;
         __u32                    ip  = 0;
         int                      share = 0;
@@ -570,15 +598,13 @@ jt_ptl_del_autoconnect (int argc, char **argv)
                         }
         }
 
-        PORTAL_IOC_INIT (data);
-        data.ioc_nal     = g_nal;
-        data.ioc_nal_cmd = NAL_CMD_DEL_AUTOCONN;
-        data.ioc_nid     = nid;
-        data.ioc_id      = ip;
-        data.ioc_flags   = (share     ? 1 : 0) |
+        PCFG_INIT(pcfg, NAL_CMD_DEL_AUTOCONN);
+        pcfg.pcfg_nid     = nid;
+        pcfg.pcfg_id      = ip;
+        pcfg.pcfg_flags   = (share     ? 1 : 0) |
                            (keep_conn ? 2 : 0);
-        
-        rc = l_ioctl (PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
+
+        rc = pcfg_ioctl (&pcfg);
         if (rc != 0) {
                 fprintf (stderr, "failed to remove autoconnect route: %s\n",
                          strerror (errno));
@@ -591,7 +617,7 @@ jt_ptl_del_autoconnect (int argc, char **argv)
 int 
 jt_ptl_print_connections (int argc, char **argv)
 {
-        struct portal_ioctl_data data;
+        struct portals_cfg       pcfg;
         char                     buffer[64];
         int                      index;
         int                      rc;
@@ -600,19 +626,17 @@ jt_ptl_print_connections (int argc, char **argv)
                 return -1;
 
         for (index = 0;;index++) {
-                PORTAL_IOC_INIT (data);
-                data.ioc_nal     = g_nal;
-                data.ioc_nal_cmd = NAL_CMD_GET_CONN;
-                data.ioc_count   = index;
+                PCFG_INIT (pcfg,  NAL_CMD_GET_CONN);
+                pcfg.pcfg_count   = index;
                 
-                rc = l_ioctl (PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
+                rc = pcfg_ioctl (&pcfg);
                 if (rc != 0)
                         break;
 
                 printf (LPX64"@%s:%d\n",
-                        data.ioc_nid, 
-                        ptl_ipaddr_2_str (data.ioc_id, buffer),
-                        data.ioc_misc);
+                        pcfg.pcfg_nid, 
+                        ptl_ipaddr_2_str (pcfg.pcfg_id, buffer),
+                        pcfg.pcfg_misc);
         }
 
         if (index == 0)
@@ -696,6 +720,7 @@ int jt_ptl_connect(int argc, char **argv)
 {
         ptl_nid_t peer_nid;
         struct portal_ioctl_data data;
+        struct portals_cfg pcfg;
         struct sockaddr_in srvaddr;
         __u32 ipaddr;
         char *flag;
@@ -820,14 +845,12 @@ int jt_ptl_connect(int argc, char **argv)
         printf("Connected host: %s NID "LPX64" snd: %d rcv: %d nagle: %s\n", argv[1],
                peer_nid, txmem, rxmem, nonagle ? "Disabled" : "Enabled");
 
-        PORTAL_IOC_INIT(data);
-        data.ioc_fd = fd;
-        data.ioc_nal = g_nal;
-        data.ioc_nal_cmd = NAL_CMD_REGISTER_PEER_FD;
-        data.ioc_nid = peer_nid;
-        data.ioc_flags = bind_irq;
+        PCFG_INIT(pcfg, NAL_CMD_REGISTER_PEER_FD);
+        pcfg.pcfg_fd = fd;
+        pcfg.pcfg_nid = peer_nid;
+        pcfg.pcfg_flags = bind_irq;
 
-        rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
+        rc = pcfg_ioctl(&pcfg);
         if (rc) {
                 fprintf(stderr, "failed to register fd with portals: %s\n", 
                         strerror(errno));
@@ -846,7 +869,7 @@ int jt_ptl_connect(int argc, char **argv)
 
 int jt_ptl_disconnect(int argc, char **argv)
 {
-        struct portal_ioctl_data data;
+        struct portals_cfg        pcfg;
         ptl_nid_t                nid = PTL_NID_ANY;
         __u32                    ipaddr = 0;
         int                      rc;
@@ -871,13 +894,11 @@ int jt_ptl_disconnect(int argc, char **argv)
                 return -1;
         }
 
-        PORTAL_IOC_INIT(data);
-        data.ioc_nal     = g_nal;
-        data.ioc_nal_cmd = NAL_CMD_CLOSE_CONNECTION;
-        data.ioc_nid     = nid;
-        data.ioc_id      = ipaddr;
+        PCFG_INIT(pcfg, NAL_CMD_CLOSE_CONNECTION);
+        pcfg.pcfg_nid     = nid;
+        pcfg.pcfg_id      = ipaddr;
         
-        rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
+        rc = pcfg_ioctl(&pcfg);
         if (rc) {
                 fprintf(stderr, "failed to remove connection: %s\n",
                         strerror(errno));
@@ -889,7 +910,7 @@ int jt_ptl_disconnect(int argc, char **argv)
 
 int jt_ptl_push_connection (int argc, char **argv)
 {
-        struct portal_ioctl_data data;
+        struct portals_cfg        pcfg;
         int                      rc;
         ptl_nid_t                nid = PTL_NID_ANY;
         __u32                    ipaddr = 0;
@@ -913,13 +934,11 @@ int jt_ptl_push_connection (int argc, char **argv)
                 fprintf(stderr, "Can't parse ipaddr: %s\n", argv[2]);
         }
 
-        PORTAL_IOC_INIT(data);
-        data.ioc_nal     = g_nal;
-        data.ioc_nal_cmd = NAL_CMD_PUSH_CONNECTION;
-        data.ioc_nid     = nid;
-        data.ioc_id      = ipaddr;
-
-        rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
+        PCFG_INIT(pcfg, NAL_CMD_PUSH_CONNECTION);
+        pcfg.pcfg_nid     = nid;
+        pcfg.pcfg_id      = ipaddr;
+        
+        rc = pcfg_ioctl(&pcfg);
         if (rc) {
                 fprintf(stderr, "failed to push connection: %s\n",
                         strerror(errno));
@@ -932,7 +951,7 @@ int jt_ptl_push_connection (int argc, char **argv)
 int 
 jt_ptl_print_active_txs (int argc, char **argv)
 {
-        struct portal_ioctl_data data;
+        struct portals_cfg        pcfg;
         int                      index;
         int                      rc;
 
@@ -940,28 +959,26 @@ jt_ptl_print_active_txs (int argc, char **argv)
                 return -1;
 
         for (index = 0;;index++) {
-                PORTAL_IOC_INIT (data);
-                data.ioc_nal     = g_nal;
-                data.ioc_nal_cmd = NAL_CMD_GET_TXDESC;
-                data.ioc_count   = index;
-                
-                rc = l_ioctl (PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
+                PCFG_INIT(pcfg, NAL_CMD_GET_TXDESC);
+                pcfg.pcfg_count   = index;
+        
+                rc = pcfg_ioctl(&pcfg);
                 if (rc != 0)
                         break;
 
                 printf ("%p: %5s payload %6d bytes to "LPX64" via "LPX64" by pid %6d: %s, %s, state %d\n",
-                        data.ioc_pbuf1,
-                        data.ioc_count == PTL_MSG_ACK ? "ACK" :
-                        data.ioc_count == PTL_MSG_PUT ? "PUT" :
-                        data.ioc_count == PTL_MSG_GET ? "GET" :
-                        data.ioc_count == PTL_MSG_REPLY ? "REPLY" : "<wierd message>",
-                        data.ioc_size,
-                        data.ioc_nid,
-                        data.ioc_nid2,
-                        data.ioc_misc,
-                        (data.ioc_flags & 1) ? "delayed" : "immediate",
-                        (data.ioc_flags & 2) ? "nblk"    : "normal",
-                        data.ioc_flags >> 2);
+                        pcfg.pcfg_pbuf1,
+                        pcfg.pcfg_count == PTL_MSG_ACK ? "ACK" :
+                        pcfg.pcfg_count == PTL_MSG_PUT ? "PUT" :
+                        pcfg.pcfg_count == PTL_MSG_GET ? "GET" :
+                        pcfg.pcfg_count == PTL_MSG_REPLY ? "REPLY" : "<wierd message>",
+                        pcfg.pcfg_size,
+                        pcfg.pcfg_nid,
+                        pcfg.pcfg_nid2,
+                        pcfg.pcfg_misc,
+                        (pcfg.pcfg_flags & 1) ? "delayed" : "immediate",
+                        (pcfg.pcfg_flags & 2) ? "nblk"    : "normal",
+                        pcfg.pcfg_flags >> 2);
         }
 
         if (index == 0)
@@ -1054,7 +1071,7 @@ int jt_ptl_mynid(int argc, char **argv)
         int rc;
         char hostname[1024];
         char *nidstr;
-        struct portal_ioctl_data data;
+        struct portals_cfg pcfg;
         ptl_nid_t mynid;
         
         if (argc > 2) {
@@ -1082,12 +1099,10 @@ int jt_ptl_mynid(int argc, char **argv)
                 return -1;
         }
         
-        PORTAL_IOC_INIT(data);
-        data.ioc_nid = mynid;
-        data.ioc_nal = g_nal;
-        data.ioc_nal_cmd = NAL_CMD_REGISTER_MYNID;
+        PCFG_INIT(pcfg, NAL_CMD_REGISTER_MYNID);
+        pcfg.pcfg_nid = mynid;
 
-        rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
+        rc = pcfg_ioctl(&pcfg);
         if (rc < 0)
                 fprintf(stderr, "setting my NID failed: %s\n",
                        strerror(errno));
diff --git a/lustre/tests/cmknod.c b/lustre/tests/cmknod.c
new file mode 100644 (file)
index 0000000..fa42e2b
--- /dev/null
@@ -0,0 +1,94 @@
+/* Simple test to check that device nodes are correctly created and visible */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#define TEST_MINOR 120
+#define TEST_MAJOR 25
+
+void usage(char *prog)
+{
+       fprintf(stderr, "usage: %s <filename>\n", prog);
+       exit(1);
+}
+
+int main( int argc, char **argv)
+{
+       char *prog = argv[0];
+       char *filename = argv[1];
+       int rc;
+       struct stat st;
+       dev_t device = makedev(TEST_MAJOR, TEST_MINOR);
+
+       if (argc != 2) 
+               usage(prog);
+
+       unlink(filename);
+       /* First try block devices */
+       rc = mknod(filename, 0700 | S_IFBLK, device);
+       if ( rc < 0 ) {
+               fprintf(stderr, "%s: mknod(%s) failed: rc %d: %s\n",
+                       prog, filename, errno, strerror(errno));
+               return 2;
+       }
+
+       rc = stat(filename, &st);
+       if ( rc < 0 ) {
+               fprintf(stderr, "%s: stat(%s) failed: rc %d: %s\n",
+                       prog, filename, errno, strerror(errno));
+               return 3;
+       }
+       if ( st.st_rdev != device) {
+               fprintf(stderr, "%s: created device other than requested: (%d,%d) instead of (%d,%d)\n", prog, major(st.st_rdev),minor(st.st_rdev),major(device),minor(device));
+               return 4;
+       }
+       if ( ! (st.st_mode | S_IFBLK) ) {
+               fprintf(stderr, "%s: created device of different type. Requested block device, got mode %o\n", prog, st.st_mode);
+               return 5;
+       }
+
+       rc = unlink(filename);
+       if ( rc < 0 ) {
+               fprintf(stderr, "%s: Cannot unlink created device %s, rc %d: %s\n",
+                       prog, filename, errno, strerror(errno));
+               return 6;
+       }
+
+       /* Second try char devices */
+       rc = mknod(filename, 0700 | S_IFCHR, device);
+       if ( rc < 0 ) {
+               fprintf(stderr, "%s: mknod(%s) failed: rc %d: %s\n",
+                       prog, filename, errno, strerror(errno));
+               return 7;
+       }
+
+       rc = stat(filename, &st);
+       if ( rc < 0 ) {
+               fprintf(stderr, "%s: stat(%s) failed: rc %d: %s\n",
+                       prog, filename, errno, strerror(errno));
+               return 8;
+       }
+       if ( st.st_rdev != device) {
+               fprintf(stderr, "%s: created device other than requested: (%d,%d) instead of (%d,%d)\n", prog, major(st.st_rdev),minor(st.st_rdev),major(device),minor(device));
+               return 9;
+       }
+       if ( ! (st.st_mode | S_IFCHR) ) {
+               fprintf(stderr, "%s: created device of different type. Requested char device, got mode %o\n", prog, st.st_mode);
+               return 10;
+       }
+
+       rc = unlink(filename);
+       if ( rc < 0 ) {
+               fprintf(stderr, "%s: Cannot unlink created device %s, rc %d: %s\n",
+                       prog, filename, errno, strerror(errno));
+               return 11;
+       }
+
+       printf("%s: device nodes created correctly\n", prog);
+
+       return 0;
+}