patch-2.1.67 linux/drivers/sound/midibuf.c
Next file: linux/drivers/sound/mpu401.c
Previous file: linux/drivers/sound/midi_synth.c
Back to the patch index
Back to the overall index
- Lines: 852
- Date:
Sat Nov 29 10:33:20 1997
- Orig file:
v2.1.66/linux/drivers/sound/midibuf.c
- Orig date:
Wed Nov 12 13:34:27 1997
diff -u --recursive --new-file v2.1.66/linux/drivers/sound/midibuf.c linux/drivers/sound/midibuf.c
@@ -28,24 +28,24 @@
{NULL};
static volatile struct snd_wait midi_sleep_flag[MAX_MIDI_DEV] =
{
- {0}};
+ {0}};
static struct wait_queue *input_sleeper[MAX_MIDI_DEV] =
{NULL};
static volatile struct snd_wait input_sleep_flag[MAX_MIDI_DEV] =
{
- {0}};
+ {0}};
struct midi_buf
{
- int len, head, tail;
- unsigned char queue[MAX_QUEUE_SIZE];
+ int len, head, tail;
+ unsigned char queue[MAX_QUEUE_SIZE];
};
struct midi_parms
{
- int prech_timeout; /*
- * Timeout before the first ch
- */
+ int prech_timeout; /*
+ * Timeout before the first ch
+ */
};
static struct midi_buf *midi_out_buf[MAX_MIDI_DEV] =
@@ -54,7 +54,7 @@
{NULL};
static struct midi_parms parms[MAX_MIDI_DEV];
-static void midi_poll (unsigned long dummy);
+static void midi_poll(unsigned long dummy);
static struct timer_list poll_timer =
@@ -85,458 +85,446 @@
}
static void
-drain_midi_queue (int dev)
+drain_midi_queue(int dev)
{
- /*
- * Give the Midi driver time to drain its output queues
- */
-
- if (midi_devs[dev]->buffer_status != NULL)
- while (!(current->signal & ~current->blocked) &&
- midi_devs[dev]->buffer_status (dev))
-
- {
- unsigned long tlimit;
-
- if (HZ / 10)
- current->timeout = tlimit = jiffies + (HZ / 10);
- else
- tlimit = (unsigned long) -1;
- midi_sleep_flag[dev].opts = WK_SLEEP;
- interruptible_sleep_on (&midi_sleeper[dev]);
- if (!(midi_sleep_flag[dev].opts & WK_WAKEUP))
- {
- if (jiffies >= tlimit)
- midi_sleep_flag[dev].opts |= WK_TIMEOUT;
- }
- midi_sleep_flag[dev].opts &= ~WK_SLEEP;
- };
+ /*
+ * Give the Midi driver time to drain its output queues
+ */
+
+ if (midi_devs[dev]->buffer_status != NULL)
+ while (!(current->signal & ~current->blocked) &&
+ midi_devs[dev]->buffer_status(dev))
+
+ {
+ unsigned long tlimit;
+
+ if (HZ / 10)
+ current->timeout = tlimit = jiffies + (HZ / 10);
+ else
+ tlimit = (unsigned long) -1;
+ midi_sleep_flag[dev].opts = WK_SLEEP;
+ interruptible_sleep_on(&midi_sleeper[dev]);
+ if (!(midi_sleep_flag[dev].opts & WK_WAKEUP))
+ {
+ if (jiffies >= tlimit)
+ midi_sleep_flag[dev].opts |= WK_TIMEOUT;
+ }
+ midi_sleep_flag[dev].opts &= ~WK_SLEEP;
+ };
}
static void
-midi_input_intr (int dev, unsigned char data)
+midi_input_intr(int dev, unsigned char data)
{
- if (midi_in_buf[dev] == NULL)
- return;
+ if (midi_in_buf[dev] == NULL)
+ return;
- if (data == 0xfe) /*
+ if (data == 0xfe) /*
* Active sensing
*/
- return; /*
+ return; /*
* Ignore
*/
- if (SPACE_AVAIL (midi_in_buf[dev]))
- {
- QUEUE_BYTE (midi_in_buf[dev], data);
- if ((input_sleep_flag[dev].opts & WK_SLEEP))
- {
- input_sleep_flag[dev].opts = WK_WAKEUP;
- wake_up (&input_sleeper[dev]);
- };
- }
-
+ if (SPACE_AVAIL(midi_in_buf[dev]))
+ {
+ QUEUE_BYTE(midi_in_buf[dev], data);
+ if ((input_sleep_flag[dev].opts & WK_SLEEP))
+ {
+ input_sleep_flag[dev].opts = WK_WAKEUP;
+ wake_up(&input_sleeper[dev]);
+ };
+ }
}
static void
-midi_output_intr (int dev)
+midi_output_intr(int dev)
{
- /*
- * Currently NOP
- */
+ /*
+ * Currently NOP
+ */
}
static void
-midi_poll (unsigned long dummy)
+midi_poll(unsigned long dummy)
{
- unsigned long flags;
- int dev;
+ unsigned long flags;
+ int dev;
- save_flags (flags);
- cli ();
- if (open_devs)
- {
- for (dev = 0; dev < num_midis; dev++)
- if (midi_out_buf[dev] != NULL)
- {
- int ok = 1;
-
- while (DATA_AVAIL (midi_out_buf[dev]) && ok)
- {
- int c = midi_out_buf[dev]->queue[midi_out_buf[dev]->head];
-
- restore_flags (flags); /* Give some time to others */
- ok = midi_devs[dev]->outputc (dev, c);
- save_flags (flags);
- cli ();
- midi_out_buf[dev]->head = (midi_out_buf[dev]->head + 1) % MAX_QUEUE_SIZE;
- midi_out_buf[dev]->len--;
- }
-
- if (DATA_AVAIL (midi_out_buf[dev]) < 100 &&
- (midi_sleep_flag[dev].opts & WK_SLEEP))
- {
- midi_sleep_flag[dev].opts = WK_WAKEUP;
- wake_up (&midi_sleeper[dev]);
- };
- }
-
- {
- poll_timer.expires = (1) + jiffies;
- add_timer (&poll_timer);
- }; /*
+ save_flags(flags);
+ cli();
+ if (open_devs)
+ {
+ for (dev = 0; dev < num_midis; dev++)
+ if (midi_devs[dev] != NULL && midi_out_buf[dev] != NULL)
+ {
+ int ok = 1;
+
+ while (DATA_AVAIL(midi_out_buf[dev]) && ok)
+ {
+ int c = midi_out_buf[dev]->queue[midi_out_buf[dev]->head];
+
+ restore_flags(flags); /* Give some time to others */
+ ok = midi_devs[dev]->outputc(dev, c);
+ save_flags(flags);
+ cli();
+ midi_out_buf[dev]->head = (midi_out_buf[dev]->head + 1) % MAX_QUEUE_SIZE;
+ midi_out_buf[dev]->len--;
+ }
+
+ if (DATA_AVAIL(midi_out_buf[dev]) < 100 &&
+ (midi_sleep_flag[dev].opts & WK_SLEEP))
+ {
+ midi_sleep_flag[dev].opts = WK_WAKEUP;
+ wake_up(&midi_sleeper[dev]);
+ };
+ }
+ {
+ poll_timer.expires = (1) + jiffies;
+ add_timer(&poll_timer);
+ }; /*
* Come back later
*/
- }
- restore_flags (flags);
+ }
+ restore_flags(flags);
}
int
-MIDIbuf_open (int dev, struct fileinfo *file)
+MIDIbuf_open(int dev, struct fileinfo *file)
{
- int mode, err;
+ int mode, err;
- dev = dev >> 4;
- mode = file->mode & O_ACCMODE;
+ dev = dev >> 4;
+ mode = file->mode & O_ACCMODE;
- if (num_midis > MAX_MIDI_DEV)
- {
- printk ("Sound: FATAL ERROR: Too many midi interfaces\n");
- num_midis = MAX_MIDI_DEV;
- }
-
- if (dev < 0 || dev >= num_midis)
- {
- printk ("Sound: Nonexistent MIDI interface %d\n", dev);
- return -ENXIO;
- }
-
- /*
- * Interrupts disabled. Be careful
- */
-
- if ((err = midi_devs[dev]->open (dev, mode,
- midi_input_intr, midi_output_intr)) < 0)
- {
- return err;
- }
-
- parms[dev].prech_timeout = 0;
-
- midi_in_buf[dev] = (struct midi_buf *) vmalloc (sizeof (struct midi_buf));
-
- if (midi_in_buf[dev] == NULL)
- {
- printk ("midi: Can't allocate buffer\n");
- midi_devs[dev]->close (dev);
- return -EIO;
- }
- midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0;
-
- midi_out_buf[dev] = (struct midi_buf *) vmalloc (sizeof (struct midi_buf));
-
- if (midi_out_buf[dev] == NULL)
- {
- printk ("midi: Can't allocate buffer\n");
- midi_devs[dev]->close (dev);
- vfree (midi_in_buf[dev]);
- midi_in_buf[dev] = NULL;
- return -EIO;
- }
- midi_out_buf[dev]->len = midi_out_buf[dev]->head = midi_out_buf[dev]->tail = 0;
- open_devs++;
-
- midi_sleep_flag[dev].opts = WK_NONE;
- input_sleep_flag[dev].opts = WK_NONE;
-
- if (open_devs < 2) /* This was first open */
- {
- ;
-
- {
- poll_timer.expires = (1) + jiffies;
- add_timer (&poll_timer);
- }; /* Start polling */
- }
+ if (num_midis > MAX_MIDI_DEV)
+ {
+ printk("Sound: FATAL ERROR: Too many midi interfaces\n");
+ num_midis = MAX_MIDI_DEV;
+ }
+ if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL)
+ {
+ printk("Sound: Nonexistent MIDI interface %d\n", dev);
+ return -ENXIO;
+ }
+ /*
+ * Interrupts disabled. Be careful
+ */
- return err;
-}
+ if ((err = midi_devs[dev]->open(dev, mode,
+ midi_input_intr, midi_output_intr)) < 0)
+ {
+ return err;
+ }
+ parms[dev].prech_timeout = 0;
-void
-MIDIbuf_release (int dev, struct fileinfo *file)
-{
- int mode;
- unsigned long flags;
+ midi_in_buf[dev] = (struct midi_buf *) vmalloc(sizeof(struct midi_buf));
- dev = dev >> 4;
- mode = file->mode & O_ACCMODE;
+ if (midi_in_buf[dev] == NULL)
+ {
+ printk("midi: Can't allocate buffer\n");
+ midi_devs[dev]->close(dev);
+ return -EIO;
+ }
+ midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0;
- if (dev < 0 || dev >= num_midis)
- return;
+ midi_out_buf[dev] = (struct midi_buf *) vmalloc(sizeof(struct midi_buf));
- save_flags (flags);
- cli ();
+ if (midi_out_buf[dev] == NULL)
+ {
+ printk("midi: Can't allocate buffer\n");
+ midi_devs[dev]->close(dev);
+ vfree(midi_in_buf[dev]);
+ midi_in_buf[dev] = NULL;
+ return -EIO;
+ }
+ midi_out_buf[dev]->len = midi_out_buf[dev]->head = midi_out_buf[dev]->tail = 0;
+ open_devs++;
- /*
- * Wait until the queue is empty
- */
+ midi_sleep_flag[dev].opts = WK_NONE;
+ input_sleep_flag[dev].opts = WK_NONE;
- if (mode != OPEN_READ)
- {
- midi_devs[dev]->outputc (dev, 0xfe); /*
- * Active sensing to shut the
- * devices
- */
+ if (open_devs < 2) /* This was first open */
+ {
+ ;
- while (!(current->signal & ~current->blocked) &&
- DATA_AVAIL (midi_out_buf[dev]))
+ {
+ poll_timer.expires = (1) + jiffies;
+ add_timer(&poll_timer);
+ }; /* Start polling */
+ }
+ return err;
+}
- {
- unsigned long tlimit;
+void
+MIDIbuf_release(int dev, struct fileinfo *file)
+{
+ int mode;
+ unsigned long flags;
- if (0)
- current->timeout = tlimit = jiffies + (0);
- else
- tlimit = (unsigned long) -1;
- midi_sleep_flag[dev].opts = WK_SLEEP;
- interruptible_sleep_on (&midi_sleeper[dev]);
- if (!(midi_sleep_flag[dev].opts & WK_WAKEUP))
- {
- if (jiffies >= tlimit)
- midi_sleep_flag[dev].opts |= WK_TIMEOUT;
- }
- midi_sleep_flag[dev].opts &= ~WK_SLEEP;
- }; /*
- * Sync
- */
+ dev = dev >> 4;
+ mode = file->mode & O_ACCMODE;
- drain_midi_queue (dev); /*
- * Ensure the output queues are empty
+ if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL)
+ return;
+
+ save_flags(flags);
+ cli();
+
+ /*
+ * Wait until the queue is empty
+ */
+
+ if (mode != OPEN_READ)
+ {
+ midi_devs[dev]->outputc(dev, 0xfe); /*
+ * Active sensing to shut the
+ * devices
+ */
+
+ while (!(current->signal & ~current->blocked) &&
+ DATA_AVAIL(midi_out_buf[dev]))
+
+ {
+ unsigned long tlimit;
+
+ if (0)
+ current->timeout = tlimit = jiffies + (0);
+ else
+ tlimit = (unsigned long) -1;
+ midi_sleep_flag[dev].opts = WK_SLEEP;
+ interruptible_sleep_on(&midi_sleeper[dev]);
+ if (!(midi_sleep_flag[dev].opts & WK_WAKEUP))
+ {
+ if (jiffies >= tlimit)
+ midi_sleep_flag[dev].opts |= WK_TIMEOUT;
+ }
+ midi_sleep_flag[dev].opts &= ~WK_SLEEP;
+ }; /*
+ * Sync
*/
- }
- restore_flags (flags);
+ drain_midi_queue(dev); /*
+ * Ensure the output queues are empty
+ */
+ }
+ restore_flags(flags);
- midi_devs[dev]->close (dev);
+ midi_devs[dev]->close(dev);
- vfree (midi_in_buf[dev]);
- vfree (midi_out_buf[dev]);
- midi_in_buf[dev] = NULL;
- midi_out_buf[dev] = NULL;
- if (open_devs < 2)
- del_timer (&poll_timer);;
- open_devs--;
+ vfree(midi_in_buf[dev]);
+ vfree(midi_out_buf[dev]);
+ midi_in_buf[dev] = NULL;
+ midi_out_buf[dev] = NULL;
+ if (open_devs < 2)
+ del_timer(&poll_timer);;
+ open_devs--;
}
int
-MIDIbuf_write (int dev, struct fileinfo *file, const char *buf, int count)
+MIDIbuf_write(int dev, struct fileinfo *file, const char *buf, int count)
{
- unsigned long flags;
- int c, n, i;
- unsigned char tmp_data;
+ unsigned long flags;
+ int c, n, i;
+ unsigned char tmp_data;
- dev = dev >> 4;
+ dev = dev >> 4;
- if (!count)
- return 0;
+ if (!count)
+ return 0;
- save_flags (flags);
- cli ();
+ save_flags(flags);
+ cli();
- c = 0;
+ c = 0;
- while (c < count)
- {
- n = SPACE_AVAIL (midi_out_buf[dev]);
+ while (c < count)
+ {
+ n = SPACE_AVAIL(midi_out_buf[dev]);
- if (n == 0) /*
+ if (n == 0) /*
* No space just now. We have to sleep
*/
- {
+ {
- {
- unsigned long tlimit;
+ {
+ unsigned long tlimit;
- if (0)
- current->timeout = tlimit = jiffies + (0);
- else
- tlimit = (unsigned long) -1;
- midi_sleep_flag[dev].opts = WK_SLEEP;
- interruptible_sleep_on (&midi_sleeper[dev]);
- if (!(midi_sleep_flag[dev].opts & WK_WAKEUP))
- {
- if (jiffies >= tlimit)
- midi_sleep_flag[dev].opts |= WK_TIMEOUT;
- }
- midi_sleep_flag[dev].opts &= ~WK_SLEEP;
- };
- if ((current->signal & ~current->blocked))
- {
- restore_flags (flags);
- return -EINTR;
- }
-
- n = SPACE_AVAIL (midi_out_buf[dev]);
- }
-
- if (n > (count - c))
- n = count - c;
-
- for (i = 0; i < n; i++)
- {
- copy_from_user ((char *) &tmp_data, &(buf)[c], 1);
- QUEUE_BYTE (midi_out_buf[dev], tmp_data);
- c++;
- }
- }
+ if (0)
+ current->timeout = tlimit = jiffies + (0);
+ else
+ tlimit = (unsigned long) -1;
+ midi_sleep_flag[dev].opts = WK_SLEEP;
+ interruptible_sleep_on(&midi_sleeper[dev]);
+ if (!(midi_sleep_flag[dev].opts & WK_WAKEUP))
+ {
+ if (jiffies >= tlimit)
+ midi_sleep_flag[dev].opts |= WK_TIMEOUT;
+ }
+ midi_sleep_flag[dev].opts &= ~WK_SLEEP;
+ };
+ if ((current->signal & ~current->blocked))
+ {
+ restore_flags(flags);
+ return -EINTR;
+ }
+ n = SPACE_AVAIL(midi_out_buf[dev]);
+ }
+ if (n > (count - c))
+ n = count - c;
+
+ for (i = 0; i < n; i++)
+ {
+ copy_from_user((char *) &tmp_data, &(buf)[c], 1);
+ QUEUE_BYTE(midi_out_buf[dev], tmp_data);
+ c++;
+ }
+ }
- restore_flags (flags);
+ restore_flags(flags);
- return c;
+ return c;
}
int
-MIDIbuf_read (int dev, struct fileinfo *file, char *buf, int count)
+MIDIbuf_read(int dev, struct fileinfo *file, char *buf, int count)
{
- int n, c = 0;
- unsigned long flags;
- unsigned char tmp_data;
+ int n, c = 0;
+ unsigned long flags;
+ unsigned char tmp_data;
- dev = dev >> 4;
+ dev = dev >> 4;
- save_flags (flags);
- cli ();
-
- if (!DATA_AVAIL (midi_in_buf[dev])) /*
- * No data yet, wait
- */
- {
+ save_flags(flags);
+ cli();
- {
- unsigned long tlimit;
-
- if (parms[dev].prech_timeout)
- current->timeout = tlimit = jiffies + (parms[dev].prech_timeout);
- else
- tlimit = (unsigned long) -1;
- input_sleep_flag[dev].opts = WK_SLEEP;
- interruptible_sleep_on (&input_sleeper[dev]);
- if (!(input_sleep_flag[dev].opts & WK_WAKEUP))
- {
- if (jiffies >= tlimit)
- input_sleep_flag[dev].opts |= WK_TIMEOUT;
- }
- input_sleep_flag[dev].opts &= ~WK_SLEEP;
- };
- if ((current->signal & ~current->blocked))
- c = -EINTR; /*
- * The user is getting restless
- */
- }
-
- if (c == 0 && DATA_AVAIL (midi_in_buf[dev])) /*
- * Got some bytes
+ if (!DATA_AVAIL(midi_in_buf[dev])) /*
+ * No data yet, wait
*/
- {
- n = DATA_AVAIL (midi_in_buf[dev]);
- if (n > count)
- n = count;
- c = 0;
-
- while (c < n)
- {
- REMOVE_BYTE (midi_in_buf[dev], tmp_data);
- {
- char *fixit = (char *) &tmp_data;
-
- copy_to_user (&(buf)[c], fixit, 1);
- };
- c++;
- }
- }
+ {
+
+ {
+ unsigned long tlimit;
- restore_flags (flags);
+ if (parms[dev].prech_timeout)
+ current->timeout = tlimit = jiffies + (parms[dev].prech_timeout);
+ else
+ tlimit = (unsigned long) -1;
+ input_sleep_flag[dev].opts = WK_SLEEP;
+ interruptible_sleep_on(&input_sleeper[dev]);
+ if (!(input_sleep_flag[dev].opts & WK_WAKEUP))
+ {
+ if (jiffies >= tlimit)
+ input_sleep_flag[dev].opts |= WK_TIMEOUT;
+ }
+ input_sleep_flag[dev].opts &= ~WK_SLEEP;
+ };
+ if ((current->signal & ~current->blocked))
+ c = -EINTR; /*
+ * The user is getting restless
+ */
+ }
+ if (c == 0 && DATA_AVAIL(midi_in_buf[dev])) /*
+ * Got some bytes
+ */
+ {
+ n = DATA_AVAIL(midi_in_buf[dev]);
+ if (n > count)
+ n = count;
+ c = 0;
+
+ while (c < n)
+ {
+ REMOVE_BYTE(midi_in_buf[dev], tmp_data);
+ {
+ char *fixit = (char *) &tmp_data;
+
+ copy_to_user(&(buf)[c], fixit, 1);
+ };
+ c++;
+ }
+ }
+ restore_flags(flags);
- return c;
+ return c;
}
int
-MIDIbuf_ioctl (int dev, struct fileinfo *file,
- unsigned int cmd, caddr_t arg)
+MIDIbuf_ioctl(int dev, struct fileinfo *file,
+ unsigned int cmd, caddr_t arg)
{
- int val;
+ int val;
- dev = dev >> 4;
+ dev = dev >> 4;
- if (((cmd >> 8) & 0xff) == 'C')
- {
- if (midi_devs[dev]->coproc) /* Coprocessor ioctl */
- return midi_devs[dev]->coproc->ioctl (midi_devs[dev]->coproc->devc, cmd, arg, 0);
- else
- printk ("/dev/midi%d: No coprocessor for this device\n", dev);
-
- return -ENXIO;
- }
- else
- switch (cmd)
- {
-
- case SNDCTL_MIDI_PRETIME:
- val = *(int *) arg;
- if (val < 0)
- val = 0;
-
- val = (HZ * val) / 10;
- parms[dev].prech_timeout = val;
- return (*(int *) arg = val);
- break;
-
- default:
- return midi_devs[dev]->ioctl (dev, cmd, arg);
- }
+ if (((cmd >> 8) & 0xff) == 'C')
+ {
+ if (midi_devs[dev]->coproc) /* Coprocessor ioctl */
+ return midi_devs[dev]->coproc->ioctl(midi_devs[dev]->coproc->devc, cmd, arg, 0);
+ else
+ printk("/dev/midi%d: No coprocessor for this device\n", dev);
+
+ return -ENXIO;
+ } else
+ switch (cmd)
+ {
+
+ case SNDCTL_MIDI_PRETIME:
+ val = *(int *) arg;
+ if (val < 0)
+ val = 0;
+
+ val = (HZ * val) / 10;
+ parms[dev].prech_timeout = val;
+ return (*(int *) arg = val);
+ break;
+
+ default:
+ return midi_devs[dev]->ioctl(dev, cmd, arg);
+ }
}
int
-MIDIbuf_select (int dev, struct fileinfo *file, int sel_type, poll_table * wait)
+MIDIbuf_select(int dev, struct fileinfo *file, int sel_type, poll_table * wait)
{
- dev = dev >> 4;
-
- switch (sel_type)
- {
- case SEL_IN:
- if (!DATA_AVAIL (midi_in_buf[dev]))
- {
-
- input_sleep_flag[dev].opts = WK_SLEEP;
- poll_wait (&input_sleeper[dev], wait);
- return 0;
- }
- return 1;
- break;
+ dev = dev >> 4;
- case SEL_OUT:
- if (SPACE_AVAIL (midi_out_buf[dev]))
- {
-
- midi_sleep_flag[dev].opts = WK_SLEEP;
- poll_wait (&midi_sleeper[dev], wait);
- return 0;
- }
- return 1;
- break;
+ switch (sel_type)
+ {
+ case SEL_IN:
+ if (!DATA_AVAIL(midi_in_buf[dev]))
+ {
+
+ input_sleep_flag[dev].opts = WK_SLEEP;
+ poll_wait(&input_sleeper[dev], wait);
+ return 0;
+ }
+ return 1;
+ break;
+
+ case SEL_OUT:
+ if (SPACE_AVAIL(midi_out_buf[dev]))
+ {
+
+ midi_sleep_flag[dev].opts = WK_SLEEP;
+ poll_wait(&midi_sleeper[dev], wait);
+ return 0;
+ }
+ return 1;
+ break;
- case SEL_EX:
- return 0;
- }
+ case SEL_EX:
+ return 0;
+ }
- return 0;
+ return 0;
}
void
-MIDIbuf_init (void)
+MIDIbuf_init(void)
{
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov