Skip to the content.

tty driver

Notes

  1. 内核启动 arch/x86/kernel/setup.c 中间存在对于 IO 端口的硬编码来确定到底给谁使用。
  2. 即使是已经端口被注册了,但是还是可以使用为该端口注册 irq。
  3. 一共申请的资源为 :
    1. 设备号 : …
    2. 中断号 : register_irq
    3. io 端口 : request_region
  4. file->private 的作用

https://en.wikipedia.org/wiki/COM_(hardware_interface)

device address port is hard coded !

During the initialization function (init_module()), or in the function that opens the device, interrupts must be activated for the device. This operation is dependent on the device, but most often involves setting a bit from the control register.

Because the interrupt handlers run in interrupt context the actions that can be performed are limited: unable to access user space memory, can’t call blocking functions. Also synchronization using spinlocks is tricky and can lead to deadlocks if the spinlock used is already acquired by a process that has been interrupted by the running handler.

IFF you know that the spinlocks are never used in interrupt handlers, you can use the non-irq versions.

If we want to disable interrupts at the interrupt controller level (not recommended because disabling a particular interrupt is slower, we can not disable shared interrupts) we can do this with disable_irq(), disable_irq_nosync(), and enable_irq(). Using these functions will disable the interrupts on all processors.

https://stackoverflow.com/questions/5934402/can-an-interrupt-handler-be-preempted All irqs are not disabled by default only the same irq is disabled on all processors. but with flags in request_irq, you can disable all other interrupts on local processor while serving the interrupt.

The KeyBoard driver is really intesting :

  1. Keyboard initialization function i8042_setup_kbd()
  2. The AT or PS/2 keyboard interrupt function atkbd_interrupt()
static int __init i8042_setup_kbd(void)
{
    int error;

    error = i8042_create_kbd_port();
    if (error)
        return error;

    error = request_irq(I8042_KBD_IRQ, i8042_interrupt, IRQF_SHARED,
                "i8042", i8042_platform_device);
    if (error)
        goto err_free_port;

    error = i8042_enable_kbd_port(); // tell the device, everything is ok, start working now !
    if (error)
        goto err_free_irq;

    i8042_kbd_irq_registered = true;
    return 0;

 err_free_irq:
    free_irq(I8042_KBD_IRQ, i8042_platform_device);
 err_free_port:
    i8042_free_kbd_port();
    return error;
}


/*
 * i8042_interrupt() is the most important function in this driver -
 * it handles the interrupts from the i8042, and sends incoming bytes
 * to the upper layers.
 */

static irqreturn_t i8042_interrupt(int irq, void *dev_id)
// /home/shen/Core/linux/drivers/input/serio/i8042.c
// XXX although very important, but it's fairly simple
// read data by i8042_read_data

static inline int i8042_read_data(void)
{
    return inb(I8042_DATA_REG);
}
struct serio_driver { // todo so, what's the relation between serio_driver and keyboard ?
    const char *description;

    const struct serio_device_id *id_table;
    bool manual_bind;

    void (*write_wakeup)(struct serio *);
    irqreturn_t (*interrupt)(struct serio *, unsigned char, unsigned int);
    int  (*connect)(struct serio *, struct serio_driver *drv);
    int  (*reconnect)(struct serio *);
    int  (*fast_reconnect)(struct serio *);
    void (*disconnect)(struct serio *);
    void (*cleanup)(struct serio *);

    struct device_driver driver;
};

Exercise

  1. https://wiki.osdev.org/%228042%22_PS/2_Controller#Initialising_the_PS.2F2_Controller

Let us do more thinking before fulfill the simple task :

  1. register_chrdev_region
  2. cdev_init
  3. cdev_add

why we have to register char device,

本站所有文章转发 CSDN 将按侵权追究法律责任,其它情况随意。