/*
* linux/fs/char_dev.c
*
* (C) 1991 Linus Torvalds
*/

#include <errno.h>		// ͷļϵͳиֳš(Linus minix )
#include <sys/types.h>		// ͷļ˻ϵͳ͡

#include <linux/sched.h>	// ȳͷļṹtask_structʼ0 ݣ
// һЩйúͻȡǶʽຯ䡣
#include <linux/kernel.h>	// ںͷļһЩں˳úԭζ塣

#include <asm/segment.h>	// βͷļйضμĴǶʽຯ
#include <asm/io.h>		// io ͷļӲ˿/䡣

extern int tty_read (unsigned minor, char *buf, int count);	// ն˶
extern int tty_write (unsigned minor, char *buf, int count);	// նд

// ַ豸дָ͡
typedef (*crw_ptr) (int rw, unsigned minor, char *buf, int count,
		    off_t * pos);

//// ն˶д
// rw - дminor - ն豸ţbuf - cout - дֽ
// pos - дǰָ룬ն˲ָá
// أʵʶдֽ
static int
rw_ttyx (int rw, unsigned minor, char *buf, int count, off_t * pos)
{
  return ((rw == READ) ? tty_read (minor, buf, count) :
	  tty_write (minor, buf, count));
}

//// ն˶д
// ͬrw_ttyx()ֻ˶ԽǷпն˵ļ⡣
static int
rw_tty (int rw, unsigned minor, char *buf, int count, off_t * pos)
{
// ûжӦĿնˣ򷵻سš
  if (current->tty < 0)
    return -EPERM;
// ն˶дrw_ttyx()ʵʶдֽ
  return rw_ttyx (rw, current->tty, buf, count, pos);
}

//// ڴݶдδʵ֡
static int
rw_ram (int rw, char *buf, int count, off_t * pos)
{
  return -EIO;
}

//// ڴݶдδʵ֡
static int
rw_mem (int rw, char *buf, int count, off_t * pos)
{
  return -EIO;
}

//// ںдδʵ֡
static int
rw_kmem (int rw, char *buf, int count, off_t * pos)
{
  return -EIO;
}

// ˿ڶд
// rw - дbuf - cout - дֽpos - ˿ڵַ
// أʵʶдֽ
static int
rw_port (int rw, char *buf, int count, off_t * pos)
{
  int i = *pos;

// ҪдֽҶ˿ڵַС64k ʱѭִеֽڵĶд
  while (count-- > 0 && i < 65536)
    {
// ǶӶ˿i жȡһֽݲŵûС
      if (rw == READ)
	put_fs_byte (inb (i), buf++);
// дûݻȡһֽ˿i
      else
	outb (get_fs_byte (buf++), i);
// ǰһ˿ڡ[??]
      i++;
    }
// /дֽӦдָ롣
  i -= *pos;
  *pos += i;
// ض/дֽ
  return i;
}

//// ڴд
static int
rw_memory (int rw, unsigned minor, char *buf, int count, off_t * pos)
{
// ڴ豸豸ţֱòͬڴд
  switch (minor)
    {
    case 0:
      return rw_ram (rw, buf, count, pos);
    case 1:
      return rw_mem (rw, buf, count, pos);
    case 2:
      return rw_kmem (rw, buf, count, pos);
    case 3:
      return (rw == READ) ? 0 : count;	/* rw_null */
    case 4:
      return rw_port (rw, buf, count, pos);
    default:
      return -EIO;
    }
}

// ϵͳ豸
#define NRDEVS ((sizeof (crw_table))/(sizeof (crw_ptr)))

// ַ豸дָ
static crw_ptr crw_table[] = {
  NULL,				/* nodev *//* 豸(豸) */
  rw_memory,			/* /dev/mem etc *//* /dev/mem  */
  NULL,				/* /dev/fd *//* /dev/fd  */
  NULL,				/* /dev/hd *//* /dev/hd Ӳ */
  rw_ttyx,			/* /dev/ttyx *//* /dev/ttyx ն */
  rw_tty,			/* /dev/tty *//* /dev/tty ն */
  NULL,				/* /dev/lp *//* /dev/lp ӡ */
  NULL
};				/* unnamed pipes *//* δܵ */

//// ַ豸д
// rw - дdev - 豸ţbuf - count - дֽpos -дָ롣
// أʵʶ/дֽ
int
rw_char (int rw, int dev, char *buf, int count, off_t * pos)
{
  crw_ptr call_addr;

// 豸ųϵͳ豸򷵻س롣
  if (MAJOR (dev) >= NRDEVS)
    return -ENODEV;
// 豸ûжӦĶ/д򷵻س롣
  if (!(call_addr = crw_table[MAJOR (dev)]))
    return -ENODEV;
// öӦ豸Ķдʵʶ/дֽ
  return call_addr (rw, MINOR (dev), buf, count, pos);
}
