顯示具有 Linux conception 標籤的文章。 顯示所有文章
顯示具有 Linux conception 標籤的文章。 顯示所有文章

2023年8月4日 星期五

USB conception

/sys/bus/usb/devices
1-0:1.0  3-0:1.0  3-10:1.0  3-11      3-11:1.1  3-4      3-4.2      3-4.4      3-4.4:1.1  3-4.4:1.3  3-4.4:1.5  3-4.4:1.7  3-4.4:1.9  3-8:1.0  3-9:1.0  4-0:1.0  usb2  usb4
2-0:1.0  3-10     3-10:1.1  3-11:1.0  3-11:1.2  3-4:1.0  3-4.2:1.0  3-4.4:1.0  3-4.4:1.2  3-4.4:1.4  3-4.4:1.6  3-4.4:1.8  3-8        3-9      3-9:1.1  usb1     usb3

解析:
<bus>-<port[.port[.port]]>:<config>.<interface>
For more info:
1. 【USB笔记】接口描述符Interface Descriptor
2. Understand USB (in Linux)
3. superuser.com/

dmesg
[13363.344895] cdc_acm 3-4.4:1.0: ttyACM0: USB ACM device
[13363.345308] cdc_acm 3-4.4:1.2: ttyACM1: USB ACM device
[13363.346187] cdc_acm 3-4.4:1.4: ttyACM2: USB ACM device
[13363.346989] cdc_acm 3-4.4:1.6: ttyACM3: USB ACM device
4G/5G 模組會有數個 multi interface (MI)
Windows:
    裝罝管理員裡, com port(右鍵,內容)
    詳細資料,屬性,硬體識別碼
    USB\VID_1E2D&PID_0069&REV_0000&MI_02

Linux:
    $ cat /sys/devices/pci0000:00/0000:00:14.0/usb3/3-4/3-4.4/3-4.4:1.6/bInterfaceNumber
    $ ls /sys/devices/pci0000:00/0000:00:14.0/usb3/3-4/3-4.4/3-4.4:1.6/tty





好用tool: lsusb.py
lsusb.py
Output:
$ ./lsusb.py -i
 WARNING: Failure to read usb.ids
usb1              1d6b:0002 09 1IF  [USB 2.00,   480 Mbps,   0mA] (xhci-hcd 0000:00:0d.0) hub
usb2              1d6b:0003 09 1IF  [USB 3.10, 10000 Mbps,   0mA] (xhci-hcd 0000:00:0d.0) hub
usb3              1d6b:0002 09 1IF  [USB 2.00,   480 Mbps,   0mA] (xhci-hcd 0000:00:14.0) hub
  3-4               1a40:0101 09 1IF  [USB 2.00,   480 Mbps, 100mA] () hub
    3-4.2             047d:2048 00 1IF  [USB 2.00,   1.5 Mbps, 100mA] (Primax Kensington Eagle Trackball)
      3-4.2:1.0         (IF) 03:01:02 1EP  () usbhid hidraw0 (hid-generic) input15 (hid-generic)
    3-4.4             1e2d:0069 ef 10IFs [USB 2.00,   480 Mbps, 500mA] (Cinterion Wireless Modules PLSx3 f7b292b4)
      3-4.4:1.0         (IF) 02:02:01 1EP  () cdc_acm tty/ttyACM0
      3-4.4:1.1         (IF) 0a:00:00 2EPs () cdc_acm
      3-4.4:1.2         (IF) 02:02:01 1EP  () cdc_acm tty/ttyACM1
      3-4.4:1.3         (IF) 0a:00:00 2EPs () cdc_acm
      3-4.4:1.4         (IF) 02:02:01 1EP  () cdc_acm tty/ttyACM2
      3-4.4:1.5         (IF) 0a:00:00 2EPs () cdc_acm
      3-4.4:1.6         (IF) 02:02:01 1EP  () cdc_acm tty/ttyACM3
      3-4.4:1.7         (IF) 0a:00:00 2EPs () cdc_acm
      3-4.4:1.8         (IF) 02:06:00 1EP  () cdc_ether net/wwx00a0c6292b40
      3-4.4:1.9         (IF) 0a:00:00 2EPs () cdc_ether
  3-8               04f3:0c11 00 1IF  [USB 2.00,    12 Mbps, 100mA] (ELAN ELAN:Fingerprint)
    3-8:1.0           (IF) ff:00:00 5EPs ()
  3-9               13d3:56a2 ef 2IFs [USB 2.00,   480 Mbps, 500mA] (Azurewave USB2.0 HD UVC WebCam 0x0001)
    3-9:1.0           (IF) 0e:01:00 1EP  () uvcvideo video4linux/video1 video4linux/video0 input/input19
    3-9:1.1           (IF) 0e:02:00 0EPs () uvcvideo
  3-10              8087:0029 e0 2IFs [USB 2.01,    12 Mbps, 100mA] ()
    3-10:1.0          (IF) e0:01:01 3EPs () btusb bluetooth/hci0
    3-10:1.1          (IF) e0:01:01 2EPs () btusb
  3-11              1044:7a3c 00 3IFs [USB 2.00,    12 Mbps, 500mA] (GIGABYTE Fusion RGB KB)
    3-11:1.0          (IF) 03:01:01 1EP  () usbhid hidraw1 (hid-generic) input16 (hid-generic)
    3-11:1.1          (IF) 03:01:01 1EP  () usbhid hidraw2 (hid-generic) input32 (hid-generic)
    3-11:1.2          (IF) 03:01:00 1EP  () usbhid hidraw3 (hid-generic) input34 input39 input35 input33 input36 (hid-generic)
usb4              1d6b:0003 09 1IF  [USB 3.10, 20000 Mbps,   0mA] (xhci-hcd 0000:00:14.0) hub



#!/bin/bash

# Function to check if the VID and PID match
function check_vid_pid {
    local vid_pid_dir="$1"
    local vid="$2"
    local pid="$3"

    local device_vid=$(cat "$vid_pid_dir/idVendor" 2>/dev/null)
    local device_pid=$(cat "$vid_pid_dir/idProduct" 2>/dev/null)

    if [[ "$device_vid" == "$vid" && "$device_pid" == "$pid" ]]; then
        echo "$vid_pid_dir"
        return 0 # Indicate a match was found
    else
        return 1 # Indicate no match was found
    fi
}

# Search for USB devices with matching VID and PID
function search_usb_devices {
    local vid="$1"
    local pid="$2"
    local -a paths=()

    for device in /sys/bus/usb/devices/*; do
        if [[ -d "$device" ]]; then
            if check_vid_pid "$device" "$vid" "$pid"; then
                paths+=("$device")
            fi
        fi
    done
}

function find_ttyUSB_ACM {
    local path="$1"
    local bInterface="04"
    local tty_devices=()

    cd $path
    # Find directories that contain bInterfaceNumber files, limiting depth to 2
    find ./ -maxdepth 2 -type f -name "bInterfaceNumber" -print0 | while IFS= read -r -d $'\0' bInterface_file; do
        # Extract the directory containing the bInterfaceNumber file
        interface_dir=$(dirname "$bInterface_file")

        # Read the bInterfaceNumber
        interface_number=$(cat "$bInterface_file")

        # Check if the interface number matches the desired value
        if [[ "$interface_number" == "$bInterface" ]]; then
            #echo "Found matching bInterface in: $interface_dir"

            # Search for ttyUSB* device nodes within the interface directory
            find "$interface_dir" -maxdepth 1 -type d -name "ttyUSB*" -print0 | while IFS= read -r -d $'\0' ttyname; do
                echo "/dev/$(basename "$ttyname")"
                #tty_devices+=("/dev/$(basename "$ttyname")")
            done
        fi
    done

    #echo "${tty_devices[*]}"
}

# Usage: ./find_usb_device.sh VID PID
if [[ $# -ne 2 ]]; then
    echo "Usage: $0 VID PID"
    exit 1
fi

if systemctl is-enabled ModemManager.service; then
    echo "ModemManager is enabled."

    systemctl stop ModemManager.service
    sleep 3
    systemctl disable ModemManager.service
    sleep 3
    echo "ModemManager has been stopped and disabled."
else
    echo "ModemManager is not enabled."
fi

paths=$(search_usb_devices "$1" "$2")

# Iterate over the paths and find ttyUSB/ACM devices
for path in $paths; do
    echo "Searching for ttyUSB/ACM devices in: $path"
    # Capture the tty devices returned by find_ttyUSB_ACM
    tty_devices=$(find_ttyUSB_ACM "$path")

    #echo "bbb-$tty_devices"
done

output:
./find_usb_device.sh 1e2d 0069
/sys/bus/usb/devices/3-2/, 480Mbits, 500mA, USB 2.00
/sys/bus/usb/devices/3-2/3-2:1.6/tty/ttyACM3
/sys/bus/usb/devices/3-2/3-2:1.4/tty/ttyACM2
/sys/bus/usb/devices/3-2/3-2:1.2/tty/ttyACM1
/sys/bus/usb/devices/3-2/3-2:1.0/tty/ttyACM0

ludev library
#include <libudev.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
  if (argc != 4) {
    fprintf(stderr, "Usage: %s <VID> <PID> <bInterfaceNumber>\n", argv[0]);
    return 1;
  }

  const char *target_vid = argv[1];
  const char *target_pid = argv[2];
  const char *target_bInterfaceNumber = argv[3];

  struct udev *udev = udev_new();
  if (!udev) {
    fprintf(stderr, "Failed to create udev object\n");
    return 1;
  }

  struct udev_enumerate *enumerate = udev_enumerate_new(udev);
  udev_enumerate_add_match_subsystem(enumerate, "tty");
  udev_enumerate_add_match_property(enumerate, "ID_VENDOR_ID", target_vid);
  udev_enumerate_add_match_property(enumerate, "ID_MODEL_ID", target_pid);

  udev_enumerate_scan_devices(enumerate);

  struct udev_list_entry *devices = udev_enumerate_get_list_entry(enumerate);
  struct udev_list_entry *entry;

  udev_list_entry_foreach(entry, devices) {
    const char *path = udev_list_entry_get_name(entry);
    struct udev_device *dev = udev_device_new_from_syspath(udev, path);

    const char *devnode = udev_device_get_devnode(dev);
    const char *bInterface =
        udev_device_get_property_value(dev, "ID_USB_INTERFACE_NUM");

    // printf("devnode=%s, bInterface=%s\n", devnode, bInterface);

    if (devnode && bInterface &&
        strcmp(bInterface, target_bInterfaceNumber) == 0) {
      printf("Found device: %s\n", devnode);
    }

    udev_device_unref(dev);
  }

  udev_enumerate_unref(enumerate);
  udev_unref(udev);

  return 0;
}

output:
$ gcc find_usb_device.c -o find_usb_device -ludev

./find_usb_device 1bc7 1060 04
Found device: /dev/ttyUSB2
Found device: /dev/ttyUSB7
Found device: /dev/ttyUSB12

./find_usb_device 1e2d 0069 04
Found device: /dev/ttyACM2

udevadm
$ udevadm info --query=all --name=/dev/ttyUSB2
P: /devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2:1.2/ttyUSB2/tty/ttyUSB2
N: ttyUSB2
L: 0
S: serial/by-id/usb-Telit_LE910C1-WWX_6db09e-if02-port0
S: serial/by-path/pci-0000:00:14.0-usb-0:2:1.2-port0
E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2:1.2/ttyUSB2/tty/ttyUSB2
E: DEVNAME=/dev/ttyUSB2
E: MAJOR=188
E: MINOR=2
E: SUBSYSTEM=tty
E: ID_VENDOR_ID=1bc7
E: ID_MODEL_ID=1031
...
...
E: ID_USB_INTERFACE_NUM=02
E: ID_USB_DRIVER=option
E: ID_PATH=pci-0000:00:14.0-usb-0:2:1.2
E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_2_1_2

2022年7月8日 星期五

recognize USB 2.0 / 3.0 with Linux

$ lsusb -t
$ lsusb -t
/:  Bus 04.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/8p, 20000M  //USB3.2
/:  Bus 03.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/16p, 480M
    |__ Port 4: Dev 12, If 0, Class=Hub, Driver=hub/4p, 480M
        |__ Port 2: Dev 13, If 0, Class=Human Interface Device, Driver=usbhid, 1.5M
    |__ Port 8: Dev 3, If 0, Class=Vendor Specific Class, Driver=, 12M
    |__ Port 9: Dev 5, If 1, Class=Video, Driver=uvcvideo, 480M
    |__ Port 9: Dev 5, If 0, Class=Video, Driver=uvcvideo, 480M
    |__ Port 10: Dev 6, If 0, Class=Wireless, Driver=btusb, 12M
    |__ Port 10: Dev 6, If 1, Class=Wireless, Driver=btusb, 12M
    |__ Port 11: Dev 7, If 1, Class=Human Interface Device, Driver=usbhid, 12M
    |__ Port 11: Dev 7, If 2, Class=Human Interface Device, Driver=usbhid, 12M
    |__ Port 11: Dev 7, If 0, Class=Human Interface Device, Driver=usbhid, 12M
/:  Bus 02.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/4p, 10000M  //USB 3.1
/:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/1p, 480M

2011年12月12日 星期一

inode 基本概念@@

2011年9月8日 星期四

Linux Input Device

Linux Input Device
【轉貼】 Jollen 的 Blog

input.c是Linux的”input”驅動程式,主要支援鍵盤與滑鼠的輸入;input.c介面有趣的地方是採用了事件(event)的方式來處理輸入,
.......
.......
.......
Linux 的input機制可用來實作「虛擬鍵盤」或「虛擬滑鼠」,只要呼叫input_event()將輸入資料發佈給input handler即可。
.......
.......
.......
定義按鍵

我們可以設定struct input_dev裡的evbit欄位,來定義所要接受的輸入類型,目前共有8種輸入類型如下:

* EV_KEY:Keys and buttons(按鍵與按鈕)。
* EV_REL:Relative axes(相對座標)。
* EV_ABS:Absolute axes(絕對座標)。
* EV_MSC:Misc events(其它事件)。
* EV_LED:LEDs。
* EV_SND:Sounds(聲音輸入)。
* EV_REP:Autorepeat values(自動重覆數值)。
* EV_FF:Force feedback事件。

以下是一個範例,我們指定dev可接受EV_KEY事件:

dev.evbit[0] = BIT(EV_KEY);

evbit是一個陣列,每個元素可以索引一種輸入類型。每種輸入類型均可指定特定的輸入資料,例如:TAB鍵。指定方式是使用set_bit()或BIT巨集來設定每種輸入類型的陣列。以下是各輸入類型的欄位名稱:
定義按鍵

我們可以設定struct input_dev裡的evbit欄位,來定義所要接受的輸入類型,目前共有8種輸入類型如下:(include\linux\input.h)

* EV_KEY:Keys and buttons(按鍵與按鈕)。
* EV_REL:Relative axes(相對座標)。
* EV_ABS:Absolute axes(絕對座標)。
* EV_MSC:Misc events(其它事件)。
* EV_LED:LEDs。
* EV_SND:Sounds(聲音輸入)。
* EV_REP:Autorepeat values(自動重覆數值)。
* EV_FF:Force feedback事件。

以下是一個範例,我們指定dev可接受EV_KEY事件:

dev.evbit[0] = BIT(EV_KEY);

evbit是一個陣列,每個元素可以索引一種輸入類型。每種輸入類型均可指定特定的輸入資料,例如:TAB鍵。指定方式是使用set_bit()或BIT巨集來設定每種輸入類型的陣列。以下是各輸入類型的欄位名稱:
......
......
......

ref: Jollen 的 Blog

我的ACPI筆記

ACPI(Advanced Configuration and Power Interface)
  • Types of ACPI Events
    At the direct ACPI hardware level, two types of events can be signaled by an SCI interrupt:
    • Fixed ACPI events:
    ex:Power button signal, Sleep button signal 

    • General-purpose events:
    When OSPM receives a general-purpose event, it either passes control to an ACPI-aware driver, or uses an OEM-supplied control method to handle the event. An OEM can implement up to 128 general-purpose event inputs in hardware per GPE block, each as either a level or edge event. It is also possible to implement a single 256-pin block as long as it’s the only block defined in the system.  (指的是Qevent 00~FF嗎?!)
     ref:ACPI Spec 3.0b
    • ACPI和其他的電源管理方式一樣,要想享受到上面這些功能,必須要有軟件和硬件的支援。硬件方面比較麻煩,除了要求主板、顯卡和網卡等外設要支援 ACPI外,還需要機箱電源的配合。電源在提供5伏電壓給主板的同時,還必須使電流穩定在720毫安以上才可以,這樣它才能夠實現電腦的「睡眠」和「喚醒」。
      ref: 初心者之家 (ACPI VS APIC)
      • (1) Button Devices
             • PNP0C0C — Power Button Device
             • PNP0C0D — Lid Device
             • PNP0C0E — Sleep Button Device
        (2) PCI Bus Wakeup Event Reporting (PME)
             • PNP0A03 — PCI Host Bridge 

      2009年7月8日 星期三

      proc - 進程信息偽檔案系統

      proc - 進程信息偽檔案系統

      [轉貼]
      /proc 是一個偽檔案系統, 被用作核心數據結構的接口, 而不僅僅 是解釋說明 /dev/kmem. /proc裏的大多數檔案都是只讀的, 但也可 以通過寫一些檔案來改變核心變量.

      下面對整個 /proc 目錄作一個大略的介紹.
      [內容詳文]

      2009年6月17日 星期三

      靜態 / 動態 函式庫

      靜態 / 動態 函式庫

      [轉貼] 函式庫管理

      函式庫:目標檔庫

      靜態函式庫:
      附檔名:通常為 libxxx.a 的類型;
      編譯行為:整個函式庫的資料被整合到執行檔中,所以利用編譯成的檔案會比較大。
      獨立執行的狀態:編譯成功的可執行檔可以獨立執行,而不需要再向外部要求讀取函式庫的內容。
      升級難易度:函式庫升級後,連執行檔也需要重新編譯過一次,將新的函式庫整合到執行檔當中。


      動態函式庫:
      附檔名:通常為 libxxx.so 的類型;
      編譯行為:編譯時執行檔中僅具有指向動態函式庫所在的指標而已,並不包含函式庫的內容,所以檔案會比較小。
      獨立執行的狀態:不能被獨立執行,程式讀取函式庫時,函式庫『必須要存在』,且函式庫的『所在目錄也不能改變』。
      升級難易度:函式庫升級後,執行檔不需要進行重新編譯,故目前的 Linux distribution 比較傾向使用動態函式庫。

      [實作]

      產生 靜態函式庫:
      # ar crv libtest.a a.o b.o 產生libtest.a的靜態函式庫

      產生 動態函式庫:
      # gcc a.c b.c -shared -o libtest.so 編譯a.c及b.c成一個libtest.so動態函式
      給其它程式compile時用:
      # gcc sample.c -o sample -lm libxxx.so

      ref :
      1. 函式庫管理
      2. Makefile教學(一)

      2009年5月18日 星期一

      Linux電源管理研究筆記-acpid工作原理簡述

      Linux電源管理研究筆記-acpid工作原理述

      [轉貼] acpid工作原理

      在手持設備設計中,電源管理歷來為重要的研究課題之一。我們日常所說的省電就屬於電源管理的範疇,這也是我們最關心的一個部分。通過掛起不必要的設備、降低CPU的頻率或者其他方法,可以減少能量的消耗,達到省電的目的。電源管理實際上是一個系統工程,從應用程式到內核框架,再到設備驅動和硬體設備,都要參與進來,才能達到電源管理的最優化。本文介紹一下acpid的工作原理。

      ACPI是Advanced Configuration and Power Interface縮寫,acpid中的d則代表daemon。Acpid是一個用戶空間的服務進程,它充當linux kernel與應用程式之間通信的介面,負責將kernel中的電源管理事件轉發給應用程式。

         acpid與kernel的通信方式:acpid用poll函數掛在/proc/acpi/event檔上。內核在drivers/acpi/event.c 中實現了該檔的介面,一旦匯流排事件列表(acpi_bus_event_list)上有電源管理事件發生,kernel就會喚醒掛在 /proc/acpi/event上的acpid,acpid再從/proc/acpi/event中讀取相應的事件。

        acpid與應用程式的通信方式有兩種,其一是通過本地socket,其檔案名為/var/run/acpid.socket,應用程式只要連接到這個socket上,不用發送任何命令就可以接收到acpid轉發的電源管理事件。

        其二是通過配置檔。在acpid收到來自kernel的電源管理事件時,根據配置檔中的規則執行指定的命令。配置檔在/etc/acpi/events/目錄下,下面是一個示例:
      (要監聽到/var/run/acpid.socket為前提下,下面的方能work)

        event=button/power.*
        action=/sbin/shutdown -h now

        事件的格式為:device_class bus_id type data。device_class和bus_id是字串,type和data是十六制整數。在配置檔中可以使用通配符,來匹配指定的事件。

      [實作]:
      (1)
      # /etc/init.d/udev start
      # /usr/sbin/acpid -c /etc/acpi/events -s /var/run/acpid.socket
      # /usr/sbin/hald
      # ps ax | grep acpi

      /usr/sbin/acpid -c /etc/acpi/events -s /var/run/acpid.socket (@@?)
      hald-addon-acpi: listening on acpid socket /var/run/acpid.socket
      要看到這兩個才算開啟。

      (2)
      /var/run/acpid.socket 如果沒有此檔,
      啟動 /etc/init.d/acpid start 即可

      此時再 /usr/sbin/acpid -c /etc/acpi/events -s /var/run/acpid.socket
      可能會出現
      acpid: can't open /proc/acpi/event: Device or resource busy
      就先不要理它吧@@
      只要有下面的2個東東,acpi其實就能work了,前提是kernel有編入acpi

      # ps ax | grep acpi
      /usr/sbin/acpid
      hald-addon-acpi: listening on acpid socket /var/run/acpid.socket

      ref :
      acpid工作原理

      2009年5月12日 星期二

      ps aux 代表意思

      ps aux 代表意思

      [轉貼]

      USER:該 process 屬於的使用者帳號。
      PID :該 process 的號碼。
      %CPU:該 process 使用掉的 CPU 資源百分比;
      %MEM:該 process 所佔用的實體記憶體百分比;
      VSZ :該 process 使用掉的虛擬記憶體量 (Kbytes)
      RSS :該 process 佔用的固定的記憶體量 (Kbytes)
      TTY :該 process 是在那個終端機上面運作,若與終端機無關,則顯示 ?,另外,tty1~tty6 是本機上面的登入者程序,若為 pts/0 等等的,則表示為由網路連接進主機的程序。


      ps ax 的 stat 代表意思
      D 不可中斷 Uninterruptible sleep (usually IO)
      R 正在運行,或在隊列中的進程
      S 處於休眠狀態
      T 停止或被追踪
      Z 僵屍進程
      W 進入内存交换(從kernel 2.6開始無效)
      X 死掉的進程
      -------------------------------
      < 高優先级
      N 低優先级
      L 有些頁被鎖進内存
      s 包含子進程
      + 位于後台的進程组;
      l 多線程,克隆線程 multi-threaded (using CLONE_THREAD, like NPTL pthreads do)
      D Uninterruptible sleep (usually IO)
      R Running or runnable (on run queue)
      S Interruptible sleep (waiting for an event to complete)
      T Stopped, either by a job control signal or because it is being traced.
      W paging (not valid since the 2.6.xx kernel)
      X dead (should never be seen)
      Z Defunct ("zombie") process, terminated but not reaped by its parent.

      ref :
      程序管理
      Linux時代論譠

      2009年4月15日 星期三

      magic number

      magic number

      [轉貼]
      當 UNIX 的 kernel 開始要執行一隻程式(使用 exec() 中的任一 個),會先偷看檔案開頭的 16 個 bit。這 16 個 bit 稱為 'magic number'。 Magic number 有幾個重要的功能。首先,kernel 再執行一個檔案之前會先 看看它的 magic number,如果 kernel 不認得那個 magic number,就不會 去執行之並且會 return 回 ENOEXEC。.......

      ref
      為什麼有一些 script 是用 #! ... 做為檔案的開端?

      2009年4月14日 星期二

      區分/dev/tty、/dev/console、/dev/pts、/dev/ttyn

      區分/dev/tty、/dev/console、/dev/pts、/dev/ttyn

      [轉貼] Here

      通常我們在linux下看到的控制台(console)是由幾個設備完成的。
      分别是/dev/ttyN(其中tty0就是/dev/console、tty1,tty2就是不同的virtual console。
      通常使用熱鍵alt+Fn來在這些virtual console之間進行切换。
      所有的這些tty設備都是由linux/drivers/char/console.c和vt.c對應。

      /dev/pts是遠端登入(telnet,ssh等)後創建的控制台設備文件所在的目錄。
      由於可能有好幾千個user登入,所以/dev/pts其實是動態生成的,
      不像其他設備文件是構建系统時就已經產生的設備節點(如果未使用devfs)。

      第一個user登入,console的设备文件為/dev/pts/0,第二個為/dev/pts/1,以此類推。
      這裡的0、1、2、3不是具體的標準輸入或輸出,而是整個控制台。
      可以嘗試 echo "aaaaaa" > /dev/pts/0、1、2……。

      /dev/tty指的是當前所處的console输出到此的内容,只會顯示在當前工作的console螢幕上
      /dev/console就是tty0

      ref : Here
      /*nice*/