diff -ruN linux.ORIG/drivers/char/Config.in linux.PATCHED/drivers/char/Config.in
--- linux.ORIG/drivers/char/Config.in	Wed Jun  7 15:26:42 2000
+++ linux.PATCHED/drivers/char/Config.in	Thu Aug 31 06:49:15 2000
@@ -8,6 +8,14 @@
 if [ "$CONFIG_VT" = "y" ]; then
   bool 'Support for console on virtual terminal' CONFIG_VT_CONSOLE
 fi
+#PPC
+if [ "$CONFIG_VT_CONSOLE" = "y" ]; then
+  bool 'Support for :Cue:Cat barcode reader' CONFIG_CUECAT
+  if [ "$CONFIG_CUECAT" = "y" ]; then
+    bool '  :Cue:Cat driver enabled by default' CONFIG_CUECAT_ENABLED_BY_DEFAULT
+  fi
+fi
+#\PPC
 tristate 'Standard/generic (dumb) serial support' CONFIG_SERIAL
 if [ "$CONFIG_SERIAL" = "y" ]; then
    bool '   Support for console on serial port' CONFIG_SERIAL_CONSOLE
diff -ruN linux.ORIG/drivers/char/Makefile linux.PATCHED/drivers/char/Makefile
--- linux.ORIG/drivers/char/Makefile	Wed Jun  7 15:26:42 2000
+++ linux.PATCHED/drivers/char/Makefile	Sun Aug 27 21:56:40 2000
@@ -57,6 +57,12 @@
 ifndef CONFIG_SUN_KEYBOARD
 ifdef CONFIG_VT
 LX_OBJS += keyboard.o
+#PPC
+ifdef CONFIG_CUECAT
+LX_OBJS += cuecat.o
+LX_OBJS += cuecat_lib.o
+endif
+#/PPC
 endif
  ifneq ($(ARCH),m68k)
   ifneq ($(ARCH),s390)
diff -ruN linux.ORIG/drivers/char/cuecat.c linux.PATCHED/drivers/char/cuecat.c
--- linux.ORIG/drivers/char/cuecat.c	Wed Dec 31 17:00:00 1969
+++ linux.PATCHED/drivers/char/cuecat.c	Thu Aug 31 06:44:06 2000
@@ -0,0 +1,369 @@
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/kbd_ll.h>
+#include <linux/proc_fs.h>
+#include <linux/smp_lock.h>
+#include <asm/segment.h>
+#include <linux/cuecat.h>
+#include <linux/cuecat_lib.h>
+
+
+
+/* Definitions */
+#define CUECAT_REENTRANT 1
+#define SHUNT_SCANCODE 1
+#define SCANCODE_ALT 0x38
+#define SCANCODES_TIMEOUT HZ/30
+#ifdef CONFIG_CUECAT_ENABLED_BY_DEFAULT
+#define DEFAULT_DRIVER_STARTUP_ENABLED 1
+#else
+#define DEFAULT_DRIVER_STARTUP_ENABLED 0
+#endif
+
+
+
+/* Function prototypes */
+static int cuecat_open(struct inode *inode,
+                       struct file *filp);
+int cuecat_read(struct file *filp,
+                char *buf,
+                size_t count,
+                loff_t *ppos);
+static int cuecat_release(struct inode *inode,
+                          struct file *filp);
+int barcode_decoder_timeout(void *unused);
+void create_cuecat_proc_entry(void);
+static int cuecat_write_proc(struct file *file,
+                             const char *buffer,
+                             unsigned long count,
+                             void *data);
+
+
+
+/* Global vars */
+char driver_enabled;
+struct wait_queue *wq=NULL;
+struct file_operations cuecat_fops = {
+    NULL,
+    cuecat_read,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    cuecat_open,
+    NULL,
+    cuecat_release,
+    NULL,
+    NULL,
+};
+unsigned char scancode_buffer[CUECAT_MAX_SCANCODE_SEQUENCE];
+unsigned char down_buffer[CUECAT_MAX_SCANCODE_SEQUENCE];
+int nb_scancodes_in_buffer;
+char nb_opens=0;
+
+char cuecat_id[CUECAT_DEVICE_ID_LEN+1];			/* Cuecat device ID */
+char barcode_type[CUECAT_BARCODE_TYPE_LEN+1];
+char barcode[256];
+
+char barcode_frame[256];
+char barcode_available=0;
+
+unsigned long last_scancode_arrival_time;
+char last_barcode_decoder_state;
+
+
+/* Functions */
+int cuecat_init(void)
+{
+  int result;
+
+  printk("CueCat barcode reader driver\n");
+  
+  /* Try to register the driver */
+  result=register_chrdev(CUECAT_MAJOR,"cuecat",&cuecat_fops);
+  if(result<0)
+  {
+    printk(KERN_WARNING "cuecat : can get major %d\n",CUECAT_MAJOR);
+    return(result);
+  }
+
+  /* Make sure the scancode buffer starts empty */
+  nb_scancodes_in_buffer=0;
+
+  /* Initialize the scancode arrival time marker */
+  last_scancode_arrival_time=jiffies;
+
+  /* Initialize the last barcode decoder state */
+  last_barcode_decoder_state=NO_BARCODE_DECODING_IN_PROGRESS;
+
+  /* Create a /proc filesystem entry */
+  create_cuecat_proc_entry();
+
+  /* Start with the driver disabled */
+  driver_enabled=DEFAULT_DRIVER_STARTUP_ENABLED;
+
+  /* No /dev/cuecat open yet */
+  nb_opens=0;
+
+  /* Start the timeout thread */
+  kernel_thread(barcode_decoder_timeout,NULL,0);
+  return(0);
+}
+
+
+
+/* Open the device */
+int cuecat_open(struct inode *inode,struct file *filp)
+{
+  int minor=MINOR(inode->i_rdev);
+
+  if(minor!=0)		/* We only have one device */
+    return(-ENODEV);
+
+  /* We don't allow more than one process to open the device file */
+  if(nb_opens)
+    return(-EBUSY);
+
+  nb_opens++;
+  MOD_INC_USE_COUNT;
+
+  return(0);
+}
+
+
+
+/* Close the device */
+int cuecat_release(struct inode *inode,struct file *filp)
+{
+  int minor=MINOR(inode->i_rdev);
+
+  if(minor!=0)		/* We only have one device */
+    return(-ENODEV);
+
+  nb_opens--;
+  MOD_DEC_USE_COUNT;
+
+  return(0);
+}
+
+
+
+/* Read from the device */
+int cuecat_read(struct file *file,char *buf,size_t count,loff_t *ppos)
+{
+  /* Can't seek (pread) on this device */
+  if (ppos != &file->f_pos)
+    return -ESPIPE;
+
+  /* Put the calling process to sleep if a barcode is not available yet */
+  if(!barcode_available)
+    interruptible_sleep_on(&wq);
+
+  /* The process is awake, let's send it the barcode */
+  memcpy(buf,barcode_frame,strlen(barcode_frame));
+  barcode_available=0;
+  return(strlen(barcode_frame));
+}
+
+
+
+int cuecat_process_scancode(unsigned char scancode,int down)
+{
+  int i;
+
+  /* If the driver is disabled, simply exit */
+  if(!driver_enabled)
+    return(0);
+
+  /* Note the time of arrival of the new scancode */
+  last_scancode_arrival_time=jiffies;
+
+  /* Purge the scancode buffer if we're out of space (it obviously can't be
+     a barcode because it'd be already too long */
+  if(nb_scancodes_in_buffer==CUECAT_MAX_SCANCODE_SEQUENCE)
+  {
+    for(i=0;i<CUECAT_MAX_SCANCODE_SEQUENCE;i++)
+      handle_scancode(scancode_buffer[i],down_buffer[i],CUECAT_REENTRANT);
+    nb_scancodes_in_buffer=0;
+
+    /* Reset the barcode decoder, just to make sure */
+    cuecat_reset_barcode_decoder();
+  }
+
+  /* Store the new scancode and the down flag in the buffer */
+  scancode_buffer[nb_scancodes_in_buffer]=scancode;
+  down_buffer[nb_scancodes_in_buffer]=down;
+  nb_scancodes_in_buffer++;
+
+  /* Feed the new scancode to the barcode converter */
+  switch(last_barcode_decoder_state=
+         cuecat_decode_barcode(scancode,cuecat_id,barcode_type,barcode))
+  {
+  case NO_BARCODE_DECODING_IN_PROGRESS:
+    /* Purge the scancode buffer, minus the new scancode */
+    i=1;
+    while(i<nb_scancodes_in_buffer)
+    {
+      handle_scancode(scancode_buffer[i],down_buffer[i],CUECAT_REENTRANT);
+      i++;
+    }
+    
+    nb_scancodes_in_buffer=0;
+    break;
+
+  case POSSIBLE_BARCODE_DECODING_IN_PROGRESS:
+    /* Do not let the scancode continue its voyage up the kernel */
+    return(SHUNT_SCANCODE);
+    break;
+
+    break;
+
+  case BARCODE_DECODED:
+    /* We have a barcode : store the information and mark it as available */
+    sprintf(barcode_frame,"BARCODE:%s,%s,%s\n",cuecat_id,barcode_type,barcode);
+    barcode_available=1;
+
+    /* We have consumed the scancode buffer */
+    nb_scancodes_in_buffer=0;
+
+    /* Send an ALT up to account for the ALT-down that triggered the buffering
+       in the first place */
+    handle_scancode(SCANCODE_ALT,0,CUECAT_REENTRANT);
+
+
+    /* Wake up a sleeping process */
+    wake_up_interruptible(&wq);
+
+    /* Do not let the scancode continue its voyage up the kernel */
+    return(SHUNT_SCANCODE);
+    break;
+  }
+
+  return(0);
+}
+
+
+
+/* Thread attached to task 0 that takes care of making sure a slow keyboard
+   input times the barcode decoder out */
+int barcode_decoder_timeout(void *unused)
+{
+  int i;
+
+  /* Initialize thread */
+  siginitsetinv(&current->blocked,0);
+  lock_kernel();
+  /* The thread doesn't need any user-level access, so get rid of all our 
+     resources */
+  exit_mm(current);
+  exit_files(current);
+  exit_fs(current);
+  /* Set a name for the thread */
+  strcpy(current->comm,"kcctod");
+  unlock_kernel();
+
+  while(1)
+  {
+    /* If the driver is disabled, simply skip the scancdde checking */
+    if(driver_enabled)
+    {
+      /* If there is a possible barcode decoding in progress and the delay
+         between the last scancode and now is greater than the timeout value,
+         flush the scancode buffer and reset the barcode decoder */
+      if(last_barcode_decoder_state==POSSIBLE_BARCODE_DECODING_IN_PROGRESS &&
+         jiffies-last_scancode_arrival_time>=SCANCODES_TIMEOUT)
+      {
+        /* Flush the scancode buffer */
+        i=0;
+        while(i<nb_scancodes_in_buffer)
+        {
+          handle_scancode(scancode_buffer[i],down_buffer[i],CUECAT_REENTRANT);
+          i++;
+        }
+
+        /* Reset the barcode decoder */
+        cuecat_reset_barcode_decoder();
+        last_barcode_decoder_state=NO_BARCODE_DECODING_IN_PROGRESS;
+      }
+    }
+
+    /* Sleep for SCANCODES_TIMEOUT jiffies */
+    current->state=TASK_INTERRUPTIBLE;
+    schedule_timeout(SCANCODES_TIMEOUT);
+  }
+
+  return(0);
+}
+
+
+
+/* Proc filesystem init */
+void create_cuecat_proc_entry(void)
+{
+  struct proc_dir_entry *cuecat_proc_entry;
+
+  /* Create the proc filesystem entry */
+  if(!(cuecat_proc_entry=create_proc_entry("cuecat",0,0)))
+    return;
+
+  /* Configure the proc entry */
+  cuecat_proc_entry->write_proc=cuecat_write_proc;
+}
+
+
+
+/* Recover data written to the proc cuecat entry */
+static int cuecat_write_proc(struct file *file,
+                             const char *buffer,
+                             unsigned long count,
+                             void *data)
+{
+  int i;
+
+  /* We must have at least 4 chars */
+  if(count<4)
+    return(count);
+
+  /* Look for "CC=" or "cc" or "Cc" or "cC" */
+  for(i=0;i<count-4;i++)
+  {
+    if((buffer[i]=='C' || buffer[i]=='c') &&
+       (buffer[i+1]=='C' || buffer[i+1]=='c') &&
+        buffer[i+2]=='=')
+      switch(buffer[i+3])
+      {
+      case('0'):
+        /* Was the driver enabled before ? */
+        if(driver_enabled)
+        {
+          /* Disable the driver */
+          driver_enabled=0;
+
+          /* Flush the scancode buffer */
+          i=0;
+          while(i<nb_scancodes_in_buffer)
+          {
+            handle_scancode(scancode_buffer[i],down_buffer[i],CUECAT_REENTRANT);
+            i++;
+          }
+
+          /* Reset the barcode decoder */
+          cuecat_reset_barcode_decoder();
+          last_barcode_decoder_state=NO_BARCODE_DECODING_IN_PROGRESS;
+        }
+        break;
+      case('1'):
+        driver_enabled=1;
+        break;
+      }
+  }
+
+  return(count);
+}
diff -ruN linux.ORIG/drivers/char/cuecat_lib.c linux.PATCHED/drivers/char/cuecat_lib.c
--- linux.ORIG/drivers/char/cuecat_lib.c	Wed Dec 31 17:00:00 1969
+++ linux.PATCHED/drivers/char/cuecat_lib.c	Thu Aug 31 14:25:01 2000
@@ -0,0 +1,604 @@
+#ifdef __KERNEL__
+#include <linux/string.h>
+#include <linux/cuecat_lib.h>
+#include <linux/cuecat_scancode2ascii.h>
+#else
+#include <string.h>
+#include "cuecat_lib.h"
+#include "cuecat_scancode2ascii.h"
+#endif
+
+
+
+/* Definitions */
+#define KEY_RELEASE    0x80
+#define CHARACTER_DECODING_ERROR  -1
+#define GOT_CHARACTER             -2
+#define GOT_ALT_F10               -3
+
+
+
+/* Global variables */
+/* Scancodes to ascii table */
+unsigned char scancode2ascii[128]=SCANCODE2ASCII_VALS;
+
+/* States and var for the barcode decoder */
+char global_barcode_decoder_state=NO_BARCODE_DECODING_IN_PROGRESS;
+char nb_dots_read=0;
+int nb_codes_read=0;
+char triplet_encoded_char_counter=0;
+char current_coded_triplet_chars;
+char coded_triplet_chars[4];
+char ALT_F10_early_notice;
+
+/* States and vars for the scancode decoder */
+char got_shift_press=0;
+char got_alt_press=0;
+char got_letter_press=0;
+char got_letter_release=0;
+char temp_read_char;
+char prev_read_char;
+char read_char;
+
+
+
+/* Function prototypes */
+char cuecat_decode_scancode(unsigned char scancode);
+char cuecat_decode_triplet(char *coded_triplet,char *decoded_triplet);
+void cuecat_reset_barcode_decoder(void);
+void cuecat_reset_scancode_decoder(void);
+void cuecat_reset_triplet_char_decoder(void);
+void do_barcode_special_cases(char *cuecat_id,
+                              char *barcode_type,
+                              char *barcode);
+
+
+
+/* Functions */
+/* Read a scancode, update the decoder's state machine and determine the barcode
+   values, completion state ... */
+char cuecat_decode_barcode(unsigned char scancode,
+                           char *cuecat_id,
+                           char *barcode_type,
+                           char *barcode)
+{
+  int i;
+  char decoded_triplet[3];
+
+  switch(cuecat_decode_scancode(scancode))	/* Feed scancode to decoder */
+  {
+  case 0:
+    if(ALT_F10_early_notice)			/* Special ALT-F10 half-baked
+						   scancode sequence makes us
+						   lie to the calling function*/
+      return(POSSIBLE_BARCODE_DECODING_IN_PROGRESS);
+    return(global_barcode_decoder_state);	/* The scancode decoder reported
+						   nothing special yet. Exit
+						   exit quietly. */
+    break;
+
+  case CHARACTER_DECODING_ERROR:		/* That scancode can't belong to
+						   a CueCat character stream */
+    cuecat_reset_barcode_decoder();
+    return(global_barcode_decoder_state);
+    break;
+
+  case GOT_CHARACTER:				/* Decoder got a valid char */
+    switch(read_char)
+    {
+    case '.':					/* We got a dot */
+      if(global_barcode_decoder_state==NO_BARCODE_DECODING_IN_PROGRESS)
+      {
+        cuecat_reset_barcode_decoder();		/* We haven't received */
+        return(global_barcode_decoder_state);	/* ALT-F10 yet */
+      }
+
+      switch(nb_dots_read)			/* How many dots have we got */
+      {						/* already ? */
+      case 0:					/* No dot read yet */
+        if(nb_codes_read!=0)
+        {
+          cuecat_reset_barcode_decoder();
+          return(global_barcode_decoder_state);	/* We're not supposed to have
+						   got codes yet */
+        }
+
+        nb_dots_read++;
+        global_barcode_decoder_state=POSSIBLE_BARCODE_DECODING_IN_PROGRESS;
+        return(global_barcode_decoder_state);
+        break;
+
+      case 1:					/* We have 1 dot already, so
+						   this one should end the
+						   CueCat device ID */
+        if(nb_codes_read!=CUECAT_DEVICE_ID_LEN)
+        {
+          cuecat_reset_barcode_decoder();
+          return(global_barcode_decoder_state);
+        }
+
+        /* We got the CueCat device ID okay and the dot is at the right place */
+	cuecat_id[CUECAT_DEVICE_ID_LEN]=0;	/* Terminate the string */
+
+        nb_codes_read=0;
+        nb_dots_read++;
+        return(global_barcode_decoder_state);
+        break;
+
+      case 2:					/* We have 2 dots already, so
+						   this one should end the
+						   barcode type code */
+        if(nb_codes_read!=CUECAT_BARCODE_TYPE_LEN)
+        {
+          cuecat_reset_barcode_decoder();
+          return(global_barcode_decoder_state);
+        }
+
+        /* We got the barcode type code okay and the dot is at the right place*/
+	barcode_type[CUECAT_BARCODE_TYPE_LEN]=0;/* Terminate the string */
+
+        nb_codes_read=0;
+        nb_dots_read++;
+        return(global_barcode_decoder_state);
+        break;
+
+      case 3:					/* We have 3 dots already, so
+						   this one should end the
+						   barcode data */
+        if(!nb_codes_read)			/* A barcode's length cannot be
+						   null */
+        {
+          cuecat_reset_barcode_decoder();
+          return(global_barcode_decoder_state);
+        }
+
+        /* Convert any remaining coded characters */
+        if(current_coded_triplet_chars)
+        {
+          /* Pad the unfinished coded triplet sequence with zeros */
+          for(i=current_coded_triplet_chars;i<4;i++)
+            coded_triplet_chars[i]='a';		/* 'a'==0 */
+
+          /* Convert this last coded triplet */
+          if(cuecat_decode_triplet(coded_triplet_chars,decoded_triplet)==
+             CHARACTER_DECODING_ERROR)
+          {
+            cuecat_reset_barcode_decoder();
+            return(global_barcode_decoder_state);/* This is not a CueCat
+  						    triplet */
+          }
+
+          /* Store this last decoded triplet */
+          for(i=0;i<3;i++)
+            barcode[nb_codes_read+i]=decoded_triplet[i];
+          nb_codes_read+=3;
+        }
+
+        /* We got the barcode */
+	  /* Terminate the string */
+        switch(current_coded_triplet_chars)
+        {
+        case 0:					/* Last code is complete */
+        case 1:					/* Last code only has 1 char :
+						   this case shouldn't exist.
+						   If it happens, it's wrong! */
+	  barcode[nb_codes_read]=0;
+          break;
+        case 2:					/* Last code only has 2 chars */
+	  barcode[nb_codes_read-2]=0;
+          break;
+        case 3:					/* Last code only has 3 chars */
+	  barcode[nb_codes_read-1]=0;
+          break;
+        default:				/* We don't know about this :
+						   this one cannot come from
+						   a CueCat */
+          cuecat_reset_barcode_decoder();
+          return(global_barcode_decoder_state);
+          break;
+        }
+
+        nb_codes_read=0;
+        nb_dots_read++;
+        return(global_barcode_decoder_state);
+        break;
+
+      case 4:					/* We have 4 dots already, so
+						   this one cannot come from
+						   a CueCat */
+        cuecat_reset_barcode_decoder();
+        return(global_barcode_decoder_state);
+        break;
+
+      default:					/* This state is not possible,
+						   this is abnormal (?) */
+        cuecat_reset_barcode_decoder();
+        return(BARCODE_DECODER_ERROR);
+        break;
+      }
+      break;
+
+    case '\r':					/* We got a carriage-return */
+      if(global_barcode_decoder_state==POSSIBLE_BARCODE_DECODING_IN_PROGRESS &&
+         nb_dots_read==4 &&
+         nb_codes_read==0 &&
+         prev_read_char=='.')
+      {
+        /* Do special treatment on some barcodes */
+        do_barcode_special_cases(cuecat_id,barcode_type,barcode);
+
+        cuecat_reset_barcode_decoder();
+        return(BARCODE_DECODED);
+      }
+      else
+      {
+        cuecat_reset_barcode_decoder();
+        return(global_barcode_decoder_state);
+      }
+      break;
+  
+    default:					/* Any other valid character */
+      if(global_barcode_decoder_state!=POSSIBLE_BARCODE_DECODING_IN_PROGRESS ||
+         nb_dots_read==0 ||
+         nb_dots_read==4 ||
+         (nb_dots_read==1 && nb_codes_read>=CUECAT_DEVICE_ID_LEN) ||
+         (nb_dots_read==2 && nb_codes_read>=1))
+      {
+        cuecat_reset_barcode_decoder();
+        return(global_barcode_decoder_state);	/* We aren't decoding anything
+  						   yet, or we shouldn't be
+  						   decoding anything, or we
+  						   shouldn't decode anymore */
+      }
+  
+      /* Read and store encoded triplet chars */
+      coded_triplet_chars[(int)current_coded_triplet_chars]=read_char;
+      current_coded_triplet_chars=(current_coded_triplet_chars+1) % 4;
+      if(!current_coded_triplet_chars)
+      {
+        /* Try to decode the triplet */
+        if(cuecat_decode_triplet(coded_triplet_chars,decoded_triplet)==
+           CHARACTER_DECODING_ERROR)
+        {
+          cuecat_reset_barcode_decoder();
+          return(global_barcode_decoder_state);/* This is not a CueCat
+  						    triplet */
+        }
+
+        switch(nb_dots_read)
+        {
+        case 1:					/* We're decoding the cuecat
+						   device ID */
+          if(nb_codes_read>CUECAT_DEVICE_ID_LEN-3)
+          {
+            cuecat_reset_barcode_decoder();
+            return(global_barcode_decoder_state);/* Too many triplets to come
+  						    from the CueCat */
+          }
+
+          /* Store the decoded triplet */
+          for(i=0;i<3;i++)
+            cuecat_id[nb_codes_read+i]=decoded_triplet[i];
+          nb_codes_read+=3;
+          break;
+
+        case 2:					/* We're decoding the barcode
+						   type */
+          if(nb_codes_read>CUECAT_BARCODE_TYPE_LEN-3)
+          {
+            cuecat_reset_barcode_decoder();
+            return(global_barcode_decoder_state);/* Too many triplets to come
+  						    from the CueCat */
+          }
+
+          /* Store the decoded triplet */
+          for(i=0;i<3;i++)
+            barcode_type[nb_codes_read+i]=decoded_triplet[i];
+          nb_codes_read+=3;
+          break;
+
+        case 3:					/* We're decoding the barcode */
+          /* Store the decoded triplet */
+          for(i=0;i<3;i++)
+            barcode[nb_codes_read+i]=decoded_triplet[i];
+          nb_codes_read+=3;
+          break;
+        }
+      }
+      return(global_barcode_decoder_state);
+      break;
+    }
+    break;
+  
+  case GOT_ALT_F10:				/* We got ALT-F10 */
+    if(global_barcode_decoder_state!=NO_BARCODE_DECODING_IN_PROGRESS)
+      cuecat_reset_barcode_decoder();
+    else
+    {
+      cuecat_reset_barcode_decoder();
+      global_barcode_decoder_state=POSSIBLE_BARCODE_DECODING_IN_PROGRESS;
+    }
+  
+    return(global_barcode_decoder_state);
+    break;
+
+  default:					/* This state is not possible,
+						   this is abnormal (?) */
+    cuecat_reset_barcode_decoder();
+    return(BARCODE_DECODER_ERROR);
+    break;
+  }
+}
+
+
+
+/* Decode a 4-character encoded triplet. A million thanks to Colin Cross for the
+   the original algorith, and to Michael for the once-only table initialization
+   that I had missed */
+char cuecat_decode_triplet(char *coded_triplet,char *decoded_triplet)
+{
+  unsigned long int n=0;
+  int i;
+  int c;
+
+  /* First convert all 4 chars in coded_triplet into their index in
+     following sequence (c), and then use the first 6 bits of each as a 24
+     bit number (n)
+     abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+- */
+  for (i=0;i<4;i++) 
+  {
+    if (coded_triplet[i] >= 'a' && coded_triplet[i] <= 'z')
+      c = coded_triplet[i] - 'a';
+    else if (coded_triplet[i] >= 'A' && coded_triplet[i] <= 'Z')
+        c = coded_triplet[i] - 'A' + 26;
+    else if (coded_triplet[i] >= '0' && coded_triplet[i] <= '9')
+      c = coded_triplet[i] - '0' + 52;
+    else if (coded_triplet[i] == '+')
+      c = 62;
+    else if (coded_triplet[i] == '-')
+      c = 63;
+    else
+      return(CHARACTER_DECODING_ERROR);
+    n = n << 6 | c;
+  }
+
+  /* Then shift and XOR to get the correct ASCII code */
+  decoded_triplet[0] = (n >> 16) ^ 67;
+  decoded_triplet[1] = (n >> 8 & 255) ^ 67;
+  decoded_triplet[2] = (n & 255) ^ 67;
+
+  return(0);
+}
+
+
+
+/* Read a scancode and try to get a character out of it.
+   NOTE : as soon as we get ALT-press + F10-press, we warn the calling function
+          so that it has the earliest chance of filtering garbage out */
+char cuecat_decode_scancode(unsigned char scancode)
+{
+  unsigned char key;
+  char keypress;
+
+  keypress=!(scancode & KEY_RELEASE);
+  key=scancode2ascii[scancode & ~KEY_RELEASE];
+
+  switch(key)
+  {
+  case 0:					/* Unknown key ? */
+    cuecat_reset_scancode_decoder();
+    return(CHARACTER_DECODING_ERROR);		/* The CueCat only sends a
+						   limited number of keys */
+    break;
+    
+  case KEY_ALT:					/* Key is ALT ? */
+    if(keypress)				/* The key was depressed */
+    {
+      if(got_shift_press ||
+         got_alt_press ||
+         got_letter_press ||
+         got_letter_release)
+      {
+        cuecat_reset_scancode_decoder();
+        return(CHARACTER_DECODING_ERROR);	/* ALT press has to be first */
+      }
+      got_alt_press=1;
+      return(0);				/* Nothing special to report */
+    }
+    else					/* The key was released */
+    {
+      if(got_shift_press ||
+         !got_alt_press ||
+         !got_letter_press ||
+         !got_letter_release)
+      {
+        cuecat_reset_scancode_decoder();
+        return(CHARACTER_DECODING_ERROR);	/* ALT release has to be last*/
+      }
+      cuecat_reset_scancode_decoder();
+      if(temp_read_char==KEY_F10)
+        return(GOT_ALT_F10);			/* We have ALT-F10 */
+      else
+        return(CHARACTER_DECODING_ERROR);	/* The CueCat doesn't send
+						   ALT-anything-else-but-F10 */
+    }
+    break;
+
+  case KEY_SHIFT:				/* Key is SHIFT ? */
+    if(keypress)				/* The key was depressed */
+    {
+      if(got_shift_press ||
+         got_alt_press ||
+         got_letter_press ||
+         got_letter_release)
+      {
+        cuecat_reset_scancode_decoder();
+        return(CHARACTER_DECODING_ERROR);	/* SHIFT press has to be first*/
+      }
+      got_shift_press=1;
+      return(0);				/* Nothing special to report */
+    }
+    else					/* The key was released */
+    {
+      if(got_alt_press ||
+         !got_shift_press ||
+         !got_letter_press ||
+         !got_letter_release)
+      {
+        cuecat_reset_scancode_decoder();
+        return(CHARACTER_DECODING_ERROR);	/*SHIFT release has to be last*/
+      }
+      cuecat_reset_scancode_decoder();
+      if(temp_read_char>='a' && temp_read_char<='z')
+      {
+	prev_read_char=read_char;
+        read_char=temp_read_char-'a'+'A';	/* Turn read char uppercase */
+        return(GOT_CHARACTER);			/* We have a valid character */
+      }
+      else
+        return(CHARACTER_DECODING_ERROR);	/* The CueCat doesn't send
+						   SHIFT-anything-else-but-a-
+						   letter */
+    }
+    break;
+
+  case '.':					/* Key is a dot */
+  case '\r':					/* or a carriage-return */
+    if((key=='.' || key=='\r') &&
+       got_shift_press)				/* shifted '.' or CR ? */
+    {
+      cuecat_reset_scancode_decoder();
+      return(CHARACTER_DECODING_ERROR);		/* The CueCat doesn't send
+                                          	   shifted '.'s or CRs */
+    }
+  default:					/* Any other key */
+    if((got_alt_press && key!=KEY_F10) ||
+       (!got_alt_press && key==KEY_F10))
+    {
+      cuecat_reset_scancode_decoder();
+      return(CHARACTER_DECODING_ERROR);		/* The CueCat doesn't send
+                                          	   ALTed-anything-but-F10 and
+						   doesn't send F10 alone */
+    }
+
+    if((keypress && got_letter_press) ||
+       (!keypress && got_letter_release))
+    {
+      cuecat_reset_scancode_decoder();
+      return(CHARACTER_DECODING_ERROR);		/* The CueCat doesn't press a
+                                          	   key without releasing the
+                                                   previous one and doesn't
+                                                   release a key without
+                                                   pressing one first */
+    }
+
+    if(keypress)				/* The key was depressed */
+    {
+      temp_read_char=key;			/* Store the key for later */
+      got_letter_press=1;
+
+      if(key==KEY_F10 &&
+         got_alt_press &&
+         !got_shift_press)
+        ALT_F10_early_notice=1;			/* Special ALT-F10 half-baked
+						   scancode sequence */
+        return(0);				/* Nothing special to report */
+    }
+    else					/* The key was released */
+    {
+      if(key!=temp_read_char)
+      {
+        cuecat_reset_scancode_decoder();
+        return(CHARACTER_DECODING_ERROR);	/* The CueCat doesn't release
+                                          	   a key it hasn't pressed
+                                                   right before */
+      }
+
+      if(got_shift_press || got_alt_press)
+      {
+        got_letter_release=1;
+        return(0);				/* Nothing special to report */
+      }
+      else
+      {
+        cuecat_reset_scancode_decoder();
+	prev_read_char=read_char;
+        read_char=temp_read_char;
+        return(GOT_CHARACTER);			/* We have a valid character */
+      }
+    }
+
+    break;
+  }
+}
+
+
+
+/* Reset the barcode decoder */
+void cuecat_reset_barcode_decoder(void)
+{
+  ALT_F10_early_notice=nb_dots_read=nb_codes_read=current_coded_triplet_chars=0;
+  global_barcode_decoder_state=NO_BARCODE_DECODING_IN_PROGRESS;
+  cuecat_reset_scancode_decoder();
+}
+
+
+
+/* Reset the scancode decoder */
+void cuecat_reset_scancode_decoder(void)
+{
+  got_shift_press=got_alt_press=got_letter_press=got_letter_release=0;
+}
+
+
+
+/* Do special treatment on some barcodes */
+void do_barcode_special_cases(char *cuecat_id,
+                              char *barcode_type,
+                              char *barcode)
+{
+  /* If the barcode is a UPC-E, it seems that the CueCat has a bug and doesn't
+     finish the barcode by the check digit */
+  if(!strcmp(barcode_type,"UPE") && strlen(barcode)==7)
+  {
+    /* Reconstruct the check digit and append it to the barcode to simulate
+       a proper operation from the CueCat */
+    char result[16];
+    int esum = 0, osum = 0, i;
+    int even=1;					/* last char is even */
+
+    /* Generate a UPC-A out of the UPC-E */
+    strcpy(result, "00000000000"); /* 11 0's */
+
+    switch(barcode[5])				/* last char */
+    {
+    case '0': case '1': case '2':
+      memcpy(result+1,barcode,2);
+      result[3]=barcode[5];			/* Manufacturer */
+      memcpy(result+8,barcode+2,3);		/* Product */
+    case '3':
+      memcpy(result+1,barcode,3);		/* Manufacturer */
+      memcpy(result+9,barcode+3,2);		/* Product */
+    case '4':
+      memcpy(result+1,barcode,4);		/* Manufacturer */
+      memcpy(result+10,barcode+4,1);		/* Product */
+    default:
+      memcpy(result+1,barcode,5);		/* Manufacturer */
+      memcpy(result+10,barcode+5,1);		/* Product */
+    }
+    
+    /* Calculate the check digit */
+    i=strlen(result);				/* end of all */
+    while (i--)
+    {
+      if (even)
+        esum+=result[i]-'0';
+      else
+        osum+=result[i]-'0';
+      even=!even;
+    }
+    i=(3*esum+osum)%10;
+    barcode[7]='0'+((10-i)%10);				/* complement to 10 */
+    barcode[8]=0;
+  }
+}
diff -ruN linux.ORIG/drivers/char/keyboard.c linux.PATCHED/drivers/char/keyboard.c
--- linux.ORIG/drivers/char/keyboard.c	Mon Aug  9 13:05:01 1999
+++ linux.PATCHED/drivers/char/keyboard.c	Sun Aug 27 21:56:40 2000
@@ -43,6 +43,12 @@
 #include <linux/kbd_ll.h>
 #include <linux/sysrq.h>
 
+/*PPC*/
+#ifdef CONFIG_CUECAT
+#include <linux/cuecat.h>
+#endif
+/*\PPC*/
+
 #define SIZE(x) (sizeof(x)/sizeof((x)[0]))
 
 #ifndef KBD_DEFMODE
@@ -194,11 +200,21 @@
     return kbd_getkeycode(scancode);
 }
 
-void handle_scancode(unsigned char scancode, int down)
+/*PPC void handle_scancode(unsigned char scancode, int down)*/
+void handle_scancode(unsigned char scancode, int down, int cuecat_reentrancy)
+/*\PPC*/
 {
 	unsigned char keycode;
 	char up_flag = down ? 0 : 0200;
 	char raw_mode;
+
+/*PPC*/
+#ifdef CONFIG_CUECAT
+        if(!cuecat_reentrancy)
+	  if(cuecat_process_scancode(scancode,down))
+	    return;	/* The decoder has asked us to junk this scancode */
+#endif
+/*\PPC*/
 
 	do_poke_blanked_console = 1;
 	mark_bh(CONSOLE_BH);
diff -ruN linux.ORIG/drivers/char/pc_keyb.c linux.PATCHED/drivers/char/pc_keyb.c
--- linux.ORIG/drivers/char/pc_keyb.c	Wed Jun  7 15:26:42 2000
+++ linux.PATCHED/drivers/char/pc_keyb.c	Sun Aug 27 21:56:40 2000
@@ -452,7 +452,9 @@
 			handle_mouse_event(scancode);
 		} else {
 			if (do_acknowledge(scancode))
-				handle_scancode(scancode, !(scancode & 0x80));
+/*PPC				handle_scancode(scancode, !(scancode & 0x80));*/
+				handle_scancode(scancode, !(scancode & 0x80),0);
+/*\PPC*/
 			mark_bh(KEYBOARD_BH);
 		}
 
diff -ruN linux.ORIG/include/linux/cuecat.h linux.PATCHED/include/linux/cuecat.h
--- linux.ORIG/include/linux/cuecat.h	Wed Dec 31 17:00:00 1969
+++ linux.PATCHED/include/linux/cuecat.h	Sun Aug 27 21:56:40 2000
@@ -0,0 +1,4 @@
+#define CUECAT_MAJOR 66
+
+extern int cuecat_init(void);
+extern int cuecat_process_scancode(unsigned char scancode,int down);
diff -ruN linux.ORIG/include/linux/cuecat_lib.h linux.PATCHED/include/linux/cuecat_lib.h
--- linux.ORIG/include/linux/cuecat_lib.h	Wed Dec 31 17:00:00 1969
+++ linux.PATCHED/include/linux/cuecat_lib.h	Thu Aug 31 05:38:55 2000
@@ -0,0 +1,42 @@
+/* Definitions */
+/* Lengths of the different fixed-length codes */
+#define CUECAT_DEVICE_ID_LEN    18
+#define CUECAT_BARCODE_TYPE_LEN  3
+#define CUECAT_BARCODE_SUBTYPE_LEN  1
+
+/* Barcode decoder return codes */
+#define BARCODE_DECODER_ERROR                 -1	/* Internal error */
+#define NO_BARCODE_DECODING_IN_PROGRESS       0
+#define POSSIBLE_BARCODE_DECODING_IN_PROGRESS 1
+#define BARCODE_DECODED                       2 
+
+/* Maximum number of scancodes sent by the cuecat in one transmission :
+     ALT-F10 = 4 scancodes
+   + '.'     = 2 scancodes
+   + 6*4 capital letters (4 scancodes each)
+   + '.'     = 2 scancodes
+   + 4 capital letters (4 scancodes each)
+   + '.'     = 2 scancodes
+   + 12*4+3 capital letters (4 scancodes each)
+   + '.'     = 2 scancodes
+   + '\n'    = 2 scancodes
+   = 330 scancodes
+
+   NOTE : it has been measured that the longest barcode the CueCat can send is
+          a CODE128-B of 19 characters (that can all be uppercase) or a
+          CODE128-C of 38 digits. In the first case, 19 characters are coded on
+          26 coded triplet characters, i.e. 4*26=104 scancodes if all of them
+          are uppercase. In the second case, 38 digits are coded on 51 coded
+          triplet characters, i.e. 4*51=204 scancodes if all of them are upper-
+          case. So the longest barcode will be sent with 204 scancodes.
+*/ 
+#define CUECAT_MAX_SCANCODE_SEQUENCE 4+2+(6*4*4)+2+(4*4)+2+((12*4+3)*4)+2+2
+
+
+
+/* Function prototypes */
+void cuecat_reset_barcode_decoder(void);
+char cuecat_decode_barcode(unsigned char scancode,
+                           char *cuecat_id,
+                           char *barcode_type,
+                           char *barcode);
diff -ruN linux.ORIG/include/linux/cuecat_scancode2ascii.h linux.PATCHED/include/linux/cuecat_scancode2ascii.h
--- linux.ORIG/include/linux/cuecat_scancode2ascii.h	Wed Dec 31 17:00:00 1969
+++ linux.PATCHED/include/linux/cuecat_scancode2ascii.h	Sun Aug 27 21:56:40 2000
@@ -0,0 +1,134 @@
+/* This is a limited table that converts cuecat scancodes to ascii */
+/* NOTE : values above 0x1f represent SHIFT, ALT and F10. See #defines below. */
+#define KEY_ALT   0x20
+#define KEY_SHIFT 0x21
+#define KEY_F10   0x22
+#define SCANCODE2ASCII_VALS {	\
+0,	/* 0x00 */		\
+0,	/* 0x01 */		\
+'1',	/* 0x02 */		\
+'2',	/* 0x03 */		\
+'3',	/* 0x04 */		\
+'4',	/* 0x05 */		\
+'5',	/* 0x06 */		\
+'6',	/* 0x07 */		\
+'7',	/* 0x08 */		\
+'8',	/* 0x09 */		\
+'9',	/* 0x0a */		\
+'0',	/* 0x0b */		\
+'-',	/* 0x0c */		\
+'=',	/* 0x0d */		\
+0,	/* 0x0e */		\
+0,	/* 0x0f */		\
+'q',	/* 0x10 */		\
+'w',	/* 0x11 */		\
+'e',	/* 0x12 */		\
+'r',	/* 0x13 */		\
+'t',	/* 0x14 */		\
+'y',	/* 0x15 */		\
+'u',	/* 0x16 */		\
+'i',	/* 0x17 */		\
+'o',	/* 0x18 */		\
+'p',	/* 0x19 */		\
+0,	/* 0x1a */		\
+0,	/* 0x1b */		\
+'\r',	/* 0x1c */		\
+0,	/* 0x1d */		\
+'a',	/* 0x1e */		\
+'s',	/* 0x1f */		\
+'d',	/* 0x20 */		\
+'f',	/* 0x21 */		\
+'g',	/* 0x22 */		\
+'h',	/* 0x23 */		\
+'j',	/* 0x24 */		\
+'k',	/* 0x25 */		\
+'l',	/* 0x26 */		\
+0,	/* 0x27 */		\
+0,	/* 0x28 */		\
+0,	/* 0x29 */		\
+0x21,	/* 0x2a */		\
+0,	/* 0x2b */		\
+'z',	/* 0x2c */		\
+'x',	/* 0x2d */		\
+'c',	/* 0x2e */		\
+'v',	/* 0x2f */		\
+'b',	/* 0x30 */		\
+'n',	/* 0x31 */		\
+'m',	/* 0x32 */		\
+0,	/* 0x33 */		\
+'.',	/* 0x34 */		\
+0,	/* 0x35 */		\
+0,	/* 0x36 */		\
+0,	/* 0x37 */		\
+0x20,	/* 0x38 */		\
+0,	/* 0x39 */		\
+0,	/* 0x3a */		\
+0,	/* 0x3b */		\
+0,	/* 0x3c */		\
+0,	/* 0x3d */		\
+0,	/* 0x3e */		\
+0,	/* 0x3f */		\
+0,	/* 0x40 */		\
+0,	/* 0x41 */		\
+0,	/* 0x42 */		\
+0,	/* 0x43 */		\
+0x22,	/* 0x44 */		\
+0,	/* 0x45 */		\
+0,	/* 0x46 */		\
+0,	/* 0x47 */		\
+0,	/* 0x48 */		\
+0,	/* 0x49 */		\
+0,	/* 0x4a */		\
+0,	/* 0x4b */		\
+0,	/* 0x4c */		\
+0,	/* 0x4d */		\
+'+',	/* 0x4e */		\
+0,	/* 0x4f */		\
+0,	/* 0x50 */		\
+0,	/* 0x51 */		\
+0,	/* 0x52 */		\
+0,	/* 0x53 */		\
+0,	/* 0x54 */		\
+0,	/* 0x55 */		\
+0,	/* 0x56 */		\
+0,	/* 0x57 */		\
+0,	/* 0x58 */		\
+0,	/* 0x59 */		\
+0,	/* 0x5a */		\
+0,	/* 0x5b */		\
+0,	/* 0x5c */		\
+0,	/* 0x5d */		\
+0,	/* 0x5e */		\
+0,	/* 0x5f */		\
+0,	/* 0x60 */		\
+0,	/* 0x61 */		\
+0,	/* 0x62 */		\
+0,	/* 0x63 */		\
+0,	/* 0x64 */		\
+0,	/* 0x65 */		\
+0,	/* 0x66 */		\
+0,	/* 0x67 */		\
+0,	/* 0x68 */		\
+0,	/* 0x69 */		\
+0,	/* 0x6a */		\
+0,	/* 0x6b */		\
+0,	/* 0x6c */		\
+0,	/* 0x6d */		\
+0,	/* 0x6e */		\
+0,	/* 0x6f */		\
+0,	/* 0x70 */		\
+0,	/* 0x71 */		\
+0,	/* 0x72 */		\
+0,	/* 0x73 */		\
+0,	/* 0x74 */		\
+0,	/* 0x75 */		\
+0,	/* 0x76 */		\
+0,	/* 0x77 */		\
+0,	/* 0x78 */		\
+0,	/* 0x79 */		\
+0,	/* 0x7a */		\
+0,	/* 0x7b */		\
+0,	/* 0x7c */		\
+0,	/* 0x7d */		\
+0,	/* 0x7e */		\
+0	/* 0x7f */		}
diff -ruN linux.ORIG/include/linux/kbd_ll.h linux.PATCHED/include/linux/kbd_ll.h
--- linux.ORIG/include/linux/kbd_ll.h	Mon Apr 26 14:22:33 1999
+++ linux.PATCHED/include/linux/kbd_ll.h	Sun Aug 27 21:56:40 2000
@@ -7,6 +7,8 @@
 
 extern struct pt_regs *kbd_pt_regs;
 
-void handle_scancode(unsigned char scancode, int down);
+/*PPC void handle_scancode(unsigned char scancode, int down);*/
+void handle_scancode(unsigned char scancode, int down, int cuecat_reentrancy);
+/*\PPC*/
 
 #endif	/* _KBD_LL_H */
diff -ruN linux.ORIG/init/main.c linux.PATCHED/init/main.c
--- linux.ORIG/init/main.c	Wed Jun  7 15:26:44 2000
+++ linux.PATCHED/init/main.c	Mon Aug 28 06:55:14 2000
@@ -54,6 +54,12 @@
 #include "../drivers/s390/block/xpram.h"
 #endif
 
+/*PPC*/
+#ifdef CONFIG_CUECAT
+#include <linux/cuecat.h>
+#endif
+/*\PPC*/
+
 #ifdef CONFIG_MAC
 extern void nubus_init(void);
 #endif
@@ -1564,6 +1570,12 @@
 #ifdef CONFIG_IRDA
 	irda_device_init(); /* Must be done after protocol initialization */
 #endif
+
+/*PPC*/
+#ifdef CONFIG_CUECAT
+	cuecat_init();
+#endif
+/*\PPC*/
 
 	/* Mount the root filesystem.. */
 	mount_root();
