linux/drivers/char/tty_io.c
/* * linux/drivers/char/tty_io.c * * Copyright (C) 1991, 1992 Linus Torvalds */ /* * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles * or rs-channels. It also implements echoing, cooked mode etc. * * Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0. * * Modified by Theodore Ts'o, 9/14/92, to dynamically allocate the * tty_struct and tty_queue structures. Previously there was an array * of 256 tty_struct's which was statically allocated, and the * tty_queue structures were allocated at boot time. Both are now * dynamically allocated only when the tty is open. * * Also restructured routines so that there is more of a separation * between the high-level tty routines (tty_io.c and tty_ioctl.c) and * the low-level tty routines (serial.c, pty.c, console.c). This * makes for cleaner and more compact code. -TYT, 9/17/92 * * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines * which can be dynamically activated and de-activated by the line * discipline handling modules (like SLIP). * * NOTE: pay no attention to the line discipline code (yet); its * interface is still subject to change in this version... * -- TYT, 1/31/92 * * Added functionality to the OPOST tty handling. No delays, but all * other bits should be there. * -- Nick Holloway <alfie@dcs.warwick.ac.uk>, 27th May 1993. * * Rewrote canonical mode and added more termios flags. * -- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94 * * Reorganized FASYNC support so mouse code can share it. * -- ctm@ardi.com, 9Sep95 * * New TIOCLINUX variants added. * -- mj@k332.feld.cvut.cz, 19-Nov-95 * * Restrict vt switching via ioctl() * -- grif@cs.ucr.edu, 5-Dec-95 * * Rewrote init_dev and release_dev to eliminate races. * -- Bill Hawes <whawes@star.net>, June 97 */ #include <linux/config.h> #include <linux/types.h> #include <linux/major.h> #include <linux/errno.h> #include <linux/signal.h> #include <linux/fcntl.h> #include <linux/sched.h> #include <linux/interrupt.h> #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/timer.h> #include <linux/ctype.h> #include <linux/kd.h> #include <linux/mm.h> #include <linux/string.h> #include <linux/malloc.h> #include <asm/segment.h> #include <asm/system.h> #include <asm/bitops.h> #include <linux/scc.h> #include "kbd_kern.h" #include "vt_kern.h" #include "selection.h" #ifdef CONFIG_KERNELD #include <linux/kerneld.h> #endif /* Bieżąca konsola, urządzenie o numerze głównym TTY_MAJOR i numerze drugorzędnym 0 (reprezentowane przez plik /dev/tty0). */ #define CONSOLE_DEV MKDEV(TTY_MAJOR,0) /* Terminal sterujący dla procesu, urządzenie o numerze głównym TTYAUX_MAJOR i numerze drugorzędnym 0 (reprezentowane przez plik /dev/tty). */ #define TTY_DEV MKDEV(TTYAUX_MAJOR,0) #undef TTY_DEBUG_HANGUP #define TTY_PARANOIA_CHECK #define CHECK_TTY_COUNT extern void do_blank_screen(int nopowersave); extern void set_vesa_blanking(const unsigned long arg); /* Standardowa struktura termios dla sterowników. */ struct termios tty_std_termios; /* for the benefit of tty drivers */ /* Lista sterowników dla terminali. */ struct tty_driver *tty_drivers = NULL; /* linked list of tty drivers */ /* Tablica dyscyplin linii. */ struct tty_ldisc ldiscs[NR_LDISCS]; /* line disc dispatch table */ /* * fg_console is the current virtual console, * last_console is the last used one, * want_console is the console we want to switch to, * kmsg_redirect is the console for kernel messages, * redirect is the pseudo-tty that console output * is redirected to if asked by TIOCCONS. */ /* Bieżąca wirtualna konsola. */ int fg_console = 0; /* Konsola ostatnio używana. */ int last_console = 0; /* Konsola, na którą chcemy się przełączyć. */ int want_console = -1; /* Konsola dla komunikatów jądra. */ int kmsg_redirect = 0; /* Pseudoterminal, na który jest przekierowywane wyjście przez TIOCCONS. */ struct tty_struct * redirect = NULL; /* Kolejka czekających na naciśnięcie klawisza. */ struct wait_queue * keypress_wait = NULL; /* Znacznik informujący, czy możemy przełączać się pomiędzy konsolami. */ char vt_dont_switch = 0; static void initialize_tty_struct(struct tty_struct *tty); static int tty_read(struct inode *, struct file *, char *, int); static int tty_write(struct inode *, struct file *, const char *, int); static int tty_select(struct inode *, struct file *, int, select_table *); static int tty_open(struct inode *, struct file *); static void tty_release(struct inode *, struct file *); static int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg); static int tty_fasync(struct inode * inode, struct file * filp, int on); extern void reset_palette(int currcons) ; extern void set_palette(void) ; #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif
/* * These two routines return the name of tty. tty_name() should NOT * be used in interrupt drivers, since it's not re-entrant. Use * _tty_name() instead. */ /* Następne dwie funckje zwracają nazwę terminala. tty_name nie powinna być używana w sterownikach przerwaniowych, ponieważ nie jest wielowejściowa (używa bufora statycznego). Należy wtedy używać _tty_name. */ char *_tty_name(struct tty_struct *tty, char *buf) { if (tty) sprintf(buf, "%s%d", tty->driver.name, MINOR(tty->device) - tty->driver.minor_start + tty->driver.name_base); else strcpy(buf, "NULL tty"); return buf; }
char *tty_name(struct tty_struct *tty) { static char buf[64]; return(_tty_name(tty, buf)); }
/* tty_paranoia_check -sprawdza poprawność numeru magic oraz czy struktura opisująca terminal nie jest NULLem. Powrót: 0 :OK, 1 :wpp. */ inline int tty_paranoia_check(struct tty_struct *tty, kdev_t device, const char *routine) { #ifdef TTY_PARANOIA_CHECK static const char *badmagic = "Warning: bad magic number for tty struct (%s) in %s\n"; static const char *badtty = "Warning: null TTY for (%s) in %s\n"; if (!tty) { printk(badtty, kdevname(device), routine); return 1; } if (tty->magic != TTY_MAGIC) { printk(badmagic, kdevname(device), routine); return 1; } #endif return 0; }
/* check_tty_count -sprawdza, czy licznik count, oznaczający liczbę otworzonych plików specjalnych dla danego urządzenia, zawiera prawidłową wartość. Powrót: 0 :OK, poprawna wartość :wpp. */ static int check_tty_count(struct tty_struct *tty, const char *routine) { #ifdef CHECK_TTY_COUNT struct file *f; int i, count = 0; /* Przeglądamy listę plików zliczając te, które są używane (licznik f_count dowiązań z tablic deskryptorów użytkowników większy od 0) oraz wskazują na nasz terminal. */ for (f = first_file, i=0; i<nr_files; i++, f = f->f_next) { if (!f->f_count) continue; if (f->private_data == tty) { count++; } } /* Jeżeli struktura tty opisuje część podrzędną pseudoterminala zwiększamy jeszcze raz licznik. Licznik w części podrzędnej pseudoterminala jest większy o jeden od rzeczywistej liczby, aby część podrzędna nie została zamknięta przed częścią nadrzędną. */ if (tty->driver.type == TTY_DRIVER_TYPE_PTY && tty->driver.subtype == PTY_TYPE_SLAVE && tty->link && tty->link->count) count++; /* Jeżeli obliczona przez nas wartość nie zgadza się z licznikiem count w strukturze opisującej terminal zwracamy prawidłową wartość. */ if (tty->count != count) { printk("Warning: dev (%s) tty->count(%d) != #fd's(%d) in %s\n", kdevname(tty->device), tty->count, count, routine); return count; } #endif return 0; }
/* tty_register_ldisc -rejestracja dyscypliny linii. Jeżeli wskaźnik na strukturę dyscypliny linii jest NULLem rejestracja oznacza wyzerowanie dyscypliny linii o podanym numerze. Powrót: 0 :OK, kod błędu :wpp. */ int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc) { /* Sprawdzamy, czy numer dycypliny linii zawarty w zakresie. */ if (disc < N_TTY || disc >= NR_LDISCS) return -EINVAL; /* Ustawiamy odpowiednią dyscyplinę linii w tablicy dyscyplin linii ldiscs, aktualizujemy jej numer i znacznik informujący o zdefiniowaniu dyscypliny linii. Jeżeli nowa dyscyplina nie jest podana zerujemy element o numerze disc w tablicy ldiscs. */ if (new_ldisc) { ldiscs[disc] = *new_ldisc; ldiscs[disc].flags |= LDISC_FLAG_DEFINED; ldiscs[disc].num = disc; } else memset(&ldiscs[disc], 0, sizeof(struct tty_ldisc)); return 0; }
/* Set the discipline of a tty line. */ /* tty_set_ldisc -zmieniamy dyscyplinę linii. Powrót: 0 :OK, kod błędu :wpp. */ static int tty_set_ldisc(struct tty_struct *tty, int ldisc) { int retval = 0; struct tty_ldisc o_ldisc; /* Sprawdzamy poprawność numeru dyscypliny linii. */ if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS)) return -EINVAL; #ifdef CONFIG_KERNELD /* Eduardo Blanco <ejbs@cs.cs.com.uy> */ if (!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED)) { char modname [20]; sprintf(modname, "tty-ldisc-%d", ldisc); request_module (modname); } #endif /* Sprawdzamy, czy dyscyplina linii o podanym numerze została zdefiniowana. */ if (!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED)) return -EINVAL; /* Jeżeli już jesteśmy w żądanej dyscyplinie linii to powrót z sukcesem. */ if (tty->ldisc.num == ldisc) return 0; /* We are already in the desired discipline */ /* Zapamiętujemy bieżącą dyscyplinę linii. W przypadku niepowodzenia z nową spróbujemy przywrócić starą dyscyplinę linii. */ o_ldisc = tty->ldisc; /* Jeśli jest coś w buforze sterownika to próbujemy wysłać na terminal. */ tty_wait_until_sent(tty, 0); /* Zamykamy bieżącą duscyplinę linii. */ /* Shutdown the current discipline. */ if (tty->ldisc.close) (tty->ldisc.close)(tty); /* Ustawiamy nową dyscyplinę linii. */ /* Now set up the new line discipline. */ tty->ldisc = ldiscs[ldisc]; tty->termios->c_line = ldisc; /* Jeżeli istnieje to wywołujemy funkcję otworzenia specyficzną dla dyscypliny linii. */ if (tty->ldisc.open) retval = (tty->ldisc.open)(tty); /* Jeżeli nie powiodło się otworzenie żądanej dyscypliny linii ... */ if (retval < 0) { /* ... próbujemy przywrócić poprzednią. */ tty->ldisc = o_ldisc; tty->termios->c_line = tty->ldisc.num; /* Jeżeli nie udało nam się otworzyć poprzedniej dyscypliny linii ... */ if (tty->ldisc.open && (tty->ldisc.open(tty) < 0)) { /* ... przełączamy się do standardowej dyscypliny linii N_TTY. */ tty->ldisc = ldiscs[N_TTY]; tty->termios->c_line = N_TTY; if (tty->ldisc.open) { int r = tty->ldisc.open(tty); /* Jeżeli nie potrafiliśmy otworzyć podstawowej dyscpypliny linii to panikujemy! */ if (r < 0) panic("Couldn't open N_TTY ldisc for " "%s --- error %d.", tty_name(tty), r); } } } /* Jeżeli zmieniliśmy dyscpylinę linii (niekoniecznie na żądaną) wywołujemy funkcję zmiany dyscypliny linii ze sterownika (oczywiście o ile istnieje). */ if (tty->ldisc.num != o_ldisc.num && tty->driver.set_ldisc) tty->driver.set_ldisc(tty); return retval; }
/* * This routine returns a tty driver structure, given a device number */ /* get_tty_driver -zwraca strukturę opisującą sterownik dla danego urządzenia. Powrót: tty_driver :jeżeli istnieje, NULL :wpp. */ struct tty_driver *get_tty_driver(kdev_t device) { int major, minor; struct tty_driver *p; /* Pobieramy numer główny i drugorzędny urządzenia. */ minor = MINOR(device); major = MAJOR(device); /* Przeglądamy listę sterowników, aby znaleźć właściwy. Sterownik p obsługuje num urządzeń o kolejnych numerach drugorzędnych poczynając od p->minor_start i o numerze głównym p->major. Uwaga: minor_start tylko dla konsoli jest różny od 0 (wynosi 1). */ for (p = tty_drivers; p; p = p->next) { if (p->major != major) continue; if (minor < p->minor_start) continue; if (minor >= p->minor_start + p->num) continue; /* Zwracamy właściwy sterownik. (1) Sterownik jest dla urządzeń o podanym numerze głównym. (2) Numer drugorzędny urządzenia mieści się w zakresie obsługiwanym przez sterownik. */ return p; } /* Nie znaleźliśmy sterownika dla podanego urządzenia. */ return NULL; }
/* * If we try to write to, or set the state of, a terminal and we're * not in the foreground, send a SIGTTOU. If the signal is blocked or * ignored, go ahead and perform the operation. (POSIX 7.2) */ /* tty_check_change -dla procesu działającego w tle sprawdzamy czy może wykonać operację pisania lub zmiany stanu terminala. Powrót: 0 :OK, kod błędu :wpp. */ int tty_check_change(struct tty_struct * tty) { /* Jeżeli nie jest to nasz terminal sterujący :OK */ if (current->tty != tty) return 0; /* Ujemny numer grupy terminala :OK. */ if (tty->pgrp <= 0) { printk("tty_check_change: tty->pgrp <= 0!\n"); return 0; } /* Jeżeli należymy do grupy terminala :OK. */ if (current->pgrp == tty->pgrp) return 0; /* Jeżeli jest ignorowany sygnał SIGTTOU :OK. */ if (is_ignored(SIGTTOU)) return 0; /* Jeżeli grupa, do której należy nasz proces jest 'osierocona' :błąd. */ if (is_orphaned_pgrp(current->pgrp)) return -EIO; /* Wysyłamy sygnał SIGTTOU do grupy, do której należy proces. */ (void) kill_pg(current->pgrp,SIGTTOU,1); return -ERESTARTSYS; }
static int hung_up_tty_read(struct inode * inode, struct file * file, char * buf, int count) { return 0; }
static int hung_up_tty_write(struct inode * inode, struct file * file, const char * buf, int count) { return -EIO; }
static int hung_up_tty_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait) { return 1; }
static int hung_up_tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) { return cmd == TIOCSPGRP ? -ENOTTY : -EIO; }
static int tty_lseek(struct inode * inode, struct file * file, off_t offset, int orig) { return -ESPIPE; }
/* Opisuje operacje dla terminala. */ static struct file_operations tty_fops = { tty_lseek, tty_read, tty_write, NULL, /* tty_readdir */ tty_select, tty_ioctl, NULL, /* tty_mmap */ tty_open, tty_release, NULL, /* tty_fsync */ tty_fasync };
/* hung_up_tty_fops -operacje, które są ustawiane po zerwaniu łączności z terminalem. */ static struct file_operations hung_up_tty_fops = { tty_lseek, hung_up_tty_read, hung_up_tty_write, NULL, /* hung_up_tty_readdir */ hung_up_tty_select, hung_up_tty_ioctl, NULL, /* hung_up_tty_mmap */ NULL, /* hung_up_tty_open */ tty_release, /* hung_up_tty_release */ NULL, /* hung_up_tty_fsync */ NULL /* hung_up_tty_fasync */ };
/* do_tty_hangup -zerwanie łączności z terminalem. */ void do_tty_hangup(struct tty_struct * tty, struct file_operations *fops) { int i; struct file * filp; struct task_struct *p; if (!tty) return; /* Sprawdzamy licznik w strukturze terminala. */ check_tty_count(tty, "do_tty_hangup"); /* Przeglądamy listę plików wyszukukjąc te, które są używane, wskazują nasz terminal i wywołujemy dla nich funkcję fasync oraz ustawiamy f_op (file_operations) na fops przekazane jako argument do funkcji (są to hung_up_tty_fops). */ for (filp = first_file, i=0; i<nr_files; i++, filp = filp->f_next) { if (!filp->f_count) continue; if (filp->private_data != tty) continue; if (!filp->f_inode) continue; if (filp->f_inode->i_rdev == CONSOLE_DEV) continue; if (filp->f_op != &tty_fops) continue; tty_fasync(filp->f_inode, filp, 0); filp->f_op = fops; } /* Wywołujemy (jeżeli istnieje) funkcję opróżnienia buforów z dyscypliny linii. */ if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); /* Wywołujemy (jeżeli istnieje) funkcję opróżnienia buforów ze sterownika. */ if (tty->driver.flush_buffer) tty->driver.flush_buffer(tty); if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); /* Budzimy procesy czekające w kolejce do pisania na danym terminalu. */ wake_up_interruptible(&tty->write_wait); /* Budzimy procesy czekające w kolejce do czytania z danego terminala. */ wake_up_interruptible(&tty->read_wait); /* * Shutdown the current line discipline, and reset it to * N_TTY. */ /* Zamykamy bieżącą dyscyplinę linii. */ if (tty->ldisc.num != ldiscs[N_TTY].num) { if (tty->ldisc.close) (tty->ldisc.close)(tty); /* Przełączamy się do standardowej dyscypliny linii N_TTY. */ tty->ldisc = ldiscs[N_TTY]; tty->termios->c_line = N_TTY; if (tty->ldisc.open) { i = (tty->ldisc.open)(tty); if (i < 0) printk("do_tty_hangup: N_TTY open: error %d\n", -i); } } /* Przeglądamy wszystkie procesy. */ for_each_task(p) { /* Jeżeli proces jest liderem sesji terminala wysyłamy do niego sygnał SIGHUP (zerwania łączności) i SIGCONT (wznowienie wstrzymanego procesu) oraz zapamiętujemy identyfikator grupy terminalowej. */ if ((tty->session > 0) && (p->session == tty->session) && p->leader) { send_sig(SIGHUP,p,1); send_sig(SIGCONT,p,1); if (tty->pgrp > 0) p->tty_old_pgrp = tty->pgrp; } /* Dla wszystkich procesów, dla których terminal, z którym zrywamy łączność był terminalem sterującym, ustawiamy terminal steryjący na NULL. */ if (p->tty == tty) p->tty = NULL; } /* Resetujemy flagi, pole sesji, pole identyfikatora grupy terminala oraz pole stanu dla pseudoterminala. */ tty->flags = 0; tty->session = 0; tty->pgrp = -1; tty->ctrl_status = 0; /* Jeżeli w sterowniku jest ustawiona flaga resetowania struktury termios inicjujemy strukturę termios w terminalu. */ if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS) *tty->termios = tty->driver.init_termios; /* Wywołujemy funkcję zerwania łaczności z terminalem ze sterownika. */ if (tty->driver.hangup) (tty->driver.hangup)(tty); }
void tty_hangup(struct tty_struct * tty) { #ifdef TTY_DEBUG_HANGUP printk("%s hangup...\n", tty_name(tty)); #endif do_tty_hangup(tty, &hung_up_tty_fops); }
void tty_vhangup(struct tty_struct * tty) { #ifdef TTY_DEBUG_HANGUP printk("%s vhangup...\n", tty_name(tty)); #endif do_tty_hangup(tty, &hung_up_tty_fops); }
/* tty_hung_up_p -sprawdzenie, czy operacje są ustawione na hung_up_tty_fops. */ int tty_hung_up_p(struct file * filp) { return (filp->f_op == &hung_up_tty_fops); }
/* * This function is typically called only by the session leader, when * it wants to disassociate itself from its controlling tty. * * It performs the following functions: * (1) Sends a SIGHUP and SIGCONT to the foreground process group * (2) Clears the tty from being controlling the session * (3) Clears the controlling tty for all processes in the * session group. * * The argument on_exit is set to 1 if called when a process is * exiting; it is 0 if called by the ioctl TIOCNOTTY. */ /* disassociate_ctty -funkcja wołana zazwyczaj przez lidera sesji, kiedy chce on odłączyć się od swojego terminal sterującego. Wykonuje następujące operacje: (1) Wysyła SIGHUP i SIGCONT do grupy procesów pierwszoplanowych (2) Wymazuje znacznik kontrolowania sesji w terminalu (3) Wymazuje terminal sterujący dla wszystkich procesów w grupie sesji. Argument on_exit jest 1, jeżeli funkcja jest wołana przez proces kończący się,a jest równy 0, jeśli jest wołana przez ioctl z argumentem TIOCNOTTY. */ void disassociate_ctty(int on_exit) { struct tty_struct *tty = current->tty; struct task_struct *p; int tty_pgrp = -1; if (tty) { /* Jeżeli proces ma terminal sterujący to zapamiętujemy numer grupy terminalowej oraz ... */ tty_pgrp = tty->pgrp; /* ... jeśli nie mamy do czynienia z pseudoterminalem i lider sesji kończy się (on_exit==1) to wywołujemy funkcję zerwania łączności z terminalem. */ if (on_exit && tty->driver.type != TTY_DRIVER_TYPE_PTY) tty_vhangup(tty); } else { /* W przypadku gdy proces nie miał terminala sterującego. */ if (current->tty_old_pgrp) { /* Jeśli pole tty_old_pgrp zawiera coś oznacza to, iż wcześniej nastąpiło zerwanie łączności z terminalem i proces ten był liderem sesji. Wysyłamy sygnały SIGHUP (zerwania łączności) i SIGCONT (wznowienia wstrzymanego procesu) do grupy tty_old_pgrp (starej grupy terminalowej). */ kill_pg(current->tty_old_pgrp, SIGHUP, on_exit); kill_pg(current->tty_old_pgrp, SIGCONT, on_exit); } return; } /* Wysyłamy sygnały SIGHUP i SIGCONT do grupy terminalowej procesu. */ if (tty_pgrp > 0) { kill_pg(tty_pgrp, SIGHUP, on_exit); if (!on_exit) kill_pg(tty_pgrp, SIGCONT, on_exit); } /* Resetujemy pole tty_old_pgrp procesu. */ current->tty_old_pgrp = 0; /* Resetujemy pole sesji i grupy terminalowej w terminalu. */ tty->session = 0; tty->pgrp = -1; /* Wymazujemy terminal sterujący dla wszystkich procesów należących do sesji. */ for_each_task(p) if (p->session == current->session) p->tty = NULL; }
/* * Sometimes we want to wait until a particular VT has been activated. We * do it in a very simple manner. Everybody waits on a single queue and * get woken up at once. Those that are satisfied go on with their business, * while those not ready go back to sleep. Seems overkill to add a wait * to each vt just for this - usually this does nothing! */ /* Czasem chcemy poczekać na aktywację konkretnego terminala. Robimy to w bardzo prosty sposób. Wszyscy czekają na jednej kolejce i budzą się na raz. Ci, którzy są usatysfakcjonowani zaczynają przetwarzanie, natomiast reszta idzie z powrotem spać. */ static struct wait_queue *vt_activate_queue = NULL;
/* * Sleeps until a vt is activated, or the task is interrupted. Returns * 0 if activation, -1 if interrupted. */ /* vt_waitactive -sen, dopóki terminal nie zostanie uaktywniony lub nie nadejdzie przerwanie. Powrót: 0 :aktywacja, -1 :przerwanie. */ int vt_waitactive(void) { /* Zaśnij (przerwania dozwolone) na kolejce czekających na terminale. */ interruptible_sleep_on(&vt_activate_queue); /* Zwraca -1, jeżeli był sygnał i nie jest on blokowany, przypadek przeciwny oznacza aktywację. */ return (current->signal & ~current->blocked) ? -1 : 0; }
#define vt_wake_waitactive() wake_up(&vt_activate_queue)
/* reset_vc -resetujemy ustawienia dla danej konsoli. */ void reset_vc(unsigned int new_console) { vt_cons[new_console]->vc_mode = KD_TEXT; kbd_table[new_console].kbdmode = VC_XLATE; vt_cons[new_console]->vt_mode.mode = VT_AUTO; vt_cons[new_console]->vt_mode.waitv = 0; vt_cons[new_console]->vt_mode.relsig = 0; vt_cons[new_console]->vt_mode.acqsig = 0; vt_cons[new_console]->vt_mode.frsig = 0; vt_cons[new_console]->vt_pid = -1; vt_cons[new_console]->vt_newvt = -1; reset_palette (new_console) ; }
/* * Performs the back end of a vt switch */ /* complete_change_console -dokończenie przełączenia pomiędzy konsolami. */ void complete_change_console(unsigned int new_console) { unsigned char old_vc_mode; /* Jeżeli konsola, na którą chcemy się przełączyć jest naszą bieżącą konsolą lub jest zabronione przełączanie pomiędzy konsolami to powrót. */ if ((new_console == fg_console) || (vt_dont_switch)) return; /* Sprawdzamy czy konsola została zaalokowana. */ if (!vc_cons_allocated(new_console)) return; /* Zapamiętujemy bieżącą konsolę jako ostatnio używaną. */ last_console = fg_console; /* * If we're switching, we could be going from KD_GRAPHICS to * KD_TEXT mode or vice versa, which means we need to blank or * unblank the screen later. */ /* Jeżeli przełączamy się pomiędzy konsolami możemy przechodzić między trybem graficznym a tekstowym, co oznacza, że musimy później wygasić i odświeżyć ekran. Zapamiętujemy bieżąy tryb. */ old_vc_mode = vt_cons[fg_console]->vc_mode; /* Aktualizujemy informacje o ekranie. */ update_screen(new_console); /* * If this new console is under process control, send it a signal * telling it that it has acquired. Also check if it has died and * clean up (similar to logic employed in change_console()) */ /* Jeżeli nowa konsola ma proces sterujący (jest w trybie VT_PROCESS), wysyłamy do niego sygnał, że została zdobyta. Musimy również sprawdzić, czy nie umarł i posprzątać. */ if (vt_cons[new_console]->vt_mode.mode == VT_PROCESS) { /* * Send the signal as privileged - kill_proc() will * tell us if the process has gone or something else * is awry */ /* Wysyłamy sygnał jako uprzywilejowany (trzeci argument dla kill_proc jest 1), na pewno zostanie wysłany. kill_proc zwróci nam błąd, jeśli nie znajdzie tego procesu. */ if (kill_proc(vt_cons[new_console]->vt_pid, vt_cons[new_console]->vt_mode.acqsig, 1) != 0) { /* * The controlling process has died, so we revert back to * normal operation. In this case, we'll also change back * to KD_TEXT mode. I'm not sure if this is strictly correct * but it saves the agony when the X server dies and the screen * remains blanked due to KD_GRAPHICS! It would be nice to do * this outside of VT_PROCESS but there is no single process * to account for and tracking tty count may be undesirable. */ /* Proces sterujący zmarł, więc powrcamy do normy - resetujemy nową konsolę. Przełączamy się również do trybu tekstowego. Nie jest pewne czy to jest zupełnie poprawne, ale ratuje przed zawieszeniem jeżeli X serwer zmarł i ekran pozostaje wygaszony w trybie graficznym. */ reset_vc(new_console); } } /* * We do this here because the controlling process above may have * gone, and so there is now a new vc_mode */ /* Robimy to tutaj, ponieważ proces sterujący mógł się skończyć i mamy nowy tryb. */ if (old_vc_mode != vt_cons[new_console]->vc_mode) { if (vt_cons[new_console]->vc_mode == KD_TEXT) do_unblank_screen(); else do_blank_screen(1); } /* Set the colour palette for this VT */ /* Ustawiamy paletę dla tego wirtualnego terminala, jeżeli jest w trybie tekstowym. */ if (vt_cons[new_console]->vc_mode == KD_TEXT) set_palette() ; /* * Wake anyone waiting for their VT to activate */ /* Budzimy czekających na aktywację terminali. */ vt_wake_waitactive(); return; }
/* * Performs the front-end of a vt switch */ /* change_console -zmiana konsoli. */ void change_console(unsigned int new_console) { /* Jeżeli konsola, na którą chcemy się przełączyć jest naszą bieżącą konsolą lub jest zabronione przełączanie pomiędzy konsolami to powrót. */ if ((new_console == fg_console) || (vt_dont_switch)) return; if (!vc_cons_allocated(new_console)) return; /* * If this vt is in process mode, then we need to handshake with * that process before switching. Essentially, we store where that * vt wants to switch to and wait for it to tell us when it's done * (via VT_RELDISP ioctl). * * We also check to see if the controlling process still exists. * If it doesn't, we reset this vt to auto mode and continue. * This is a cheap way to track process control. The worst thing * that can happen is: we send a signal to a process, it dies, and * the switch gets "lost" waiting for a response; hopefully, the * user will try again, we'll detect the process is gone (unless * the user waits just the right amount of time :-) and revert the * vt to auto control. */ /* Jeżeli bieżący terminal ma proces sterujący, musimy się porozumieć z nim przed przełączeniem. Przechowujemy terminal, na który chcemy się przełączyć i czekamy na informacje o przełączneiu (przez VT_RELDISP). Sprawdzamy również czy proces sterujący wciąż istnieje. Jeżeli nie istnieje to przełączamy wirtualny terminal do trybu automatycznego i kontynuujemy. Jest to prosty sposób na śledzenie procesu sterującego. Najgorszy scenariusz, który może się zdarzyć to: wysyłamy sygnał do procesu, on umiera, dostajemy 'zgubione' czekając na odpowiedź; na szczęście użytkownik spróbuje znowu, wykryjemy, że nie ma procesu sterującego i przełączymy terminal w tryb automatyczny. */ if (vt_cons[fg_console]->vt_mode.mode == VT_PROCESS) { /* * Send the signal as privileged - kill_proc() will * tell us if the process has gone or something else * is awry */ /* Wysyłamy sygnał jako uprzywilejowany (na pewno zostanie wysłany). kill_proc przekaże nam czy proces skończył się. */ if (kill_proc(vt_cons[fg_console]->vt_pid, vt_cons[fg_console]->vt_mode.relsig, 1) == 0) { /* * It worked. Mark the vt to switch to and * return. The process needs to send us a * VT_RELDISP ioctl to complete the switch. */ /* Proces działa. Zaznaczamy wirtualny terminal, na który chcemy się przełączyć. Proces sterujący musi nam przesłać ioctl VT_RELDISP, abyśmy skończyli przełączanie. */ vt_cons[fg_console]->vt_newvt = new_console; return; } /* * The controlling process has died, so we revert back to * normal operation. In this case, we'll also change back * to KD_TEXT mode. I'm not sure if this is strictly correct * but it saves the agony when the X server dies and the screen * remains blanked due to KD_GRAPHICS! It would be nice to do * this outside of VT_PROCESS but there is no single process * to account for and tracking tty count may be undesirable. */ /* Proces sterujący zmarł, więc wracamy do normy. Przełączamy się również do trybu tekstowego. Nie jest pewne czy to jest zupełnie poprawne, lecz ratuje przed zawieszeniem, jeżeli X serwer umrze i ekran pozostaje wygaszony w trybie graficznym. */ reset_vc(fg_console); /* * Fall through to normal (VT_AUTO) handling of the switch... */ } /* * Ignore all switches in KD_GRAPHICS+VT_AUTO mode */ /* Bieżąca konsola nie miała procesu sterującego i jest w trybie graficznym: nie pezłączamy się. */ if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS) return; /* Kończymy przełacznie konsoli, jeżeli bieżąca konsola miała proces sterujący, który zmarł lub nie miała procesu sterującego i jest w trybie tekstowym. */ complete_change_console(new_console); }
/* wait_for_keypress -czekamy na naciśnięcie klawisza. */ void wait_for_keypress(void) { sleep_on(&keypress_wait); }
/* stop_tty -wstrzymanie wypisywania na terminalu. */ void stop_tty(struct tty_struct *tty) { /* Jeżeli terminal już zastopowany to nic nie robimy. */ if (tty->stopped) return; /* Ustawiamy znacznik zastopowania terminala. */ tty->stopped = 1; /* Jeżeli jest to część podrzędna pseudoterminala pracującego w trybie pakietowym to kasujemy maskę TIOCPKT_START i ustawiamy maskę TIOCPKT_STOP. Budzimy procesy czekające na odczyt w drugiej, nadrzędnej części naszego pseudoterminala. */ if (tty->link && tty->link->packet) { tty->ctrl_status &= ~TIOCPKT_START; tty->ctrl_status |= TIOCPKT_STOP; wake_up_interruptible(&tty->link->read_wait); } /* Wywołujemy funkcję zatrzymania ze sterownika. */ if (tty->driver.stop) (tty->driver.stop)(tty); }
/* start_tty -wznowienie wypisywania na terminalu. */ void start_tty(struct tty_struct *tty) { /* Jeżeli terminal nie był zatrzymany to nie mamy nic do zrobienia. */ if (!tty->stopped) return; /* Kasujemy znacznik informujący o zatrzymaniu terminala. */ tty->stopped = 0; /* Jeżeli jesteśmy w części podrzędnej psudoterminala pracującego w trybie pakietowym to kasujemy maskę zatrzymania terminala TIOCPKT_STOP i ustwiamy maskę pracy TIOCPKT_START oraz budzimy procesy czekające na odczyt w części nadrzędnej pseudoterminala. */ if (tty->link && tty->link->packet) { tty->ctrl_status &= ~TIOCPKT_STOP; tty->ctrl_status |= TIOCPKT_START; wake_up_interruptible(&tty->link->read_wait); } /* Wywołujemy funkcję wznowienia przetwarzania ze sterownika. */ if (tty->driver.start) (tty->driver.start)(tty); if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); /* Budzimy procesy czekające na zapis do terminala. */ wake_up_interruptible(&tty->write_wait); }
/* tty_read -czytamy z terminala. Argumenty: inode :i-węzeł pliku, z którego chcemy czytać, file :struktura poisująca plik, z którego chcemy czytać, buf :bufor, w którym zapiszemy odczytane bajty, count :liczba bajtów, które chcemy przeczytać. Powrót: liczba zapisanych bajtów :nie wystąpił błąd, kod błędu :wpp. */ static int tty_read(struct inode * inode, struct file * file, char * buf, int count) { int i; struct tty_struct * tty; /* Pobieramy ze struktury file strukturę opisującą terminal. */ tty = (struct tty_struct *)file->private_data; /* Sprawdzamy, czy wskaźnik nie jest pusty oraz czy jest prawidłowy numer magic. */ if (tty_paranoia_check(tty, inode->i_rdev, "tty_read")) return -EIO; /* Jeżeli nie ma terminala lub jest ustawiona flaga błędu wejścia-wyjścia to powracamy z błędem wejścia-wyjścia. */ if (!tty || (tty->flags & (1 << TTY_IO_ERROR))) return -EIO; /* This check not only needs to be done before reading, but also whenever read_chan() gets woken up after sleeping, so I've moved it to there. This should only be done for the N_TTY line discipline, anyway. Same goes for write_chan(). -- jlc. */ #if 0 if ((inode->i_rdev != CONSOLE_DEV) && /* don't stop on /dev/console */ (tty->pgrp > 0) && (current->tty == tty) && (tty->pgrp != current->pgrp)) if (is_ignored(SIGTTIN) || is_orphaned_pgrp(current->pgrp)) return -EIO; else { (void) kill_pg(current->pgrp, SIGTTIN, 1); return -ERESTARTSYS; } #endif /* Jeżeli istnieje fukcja odczytu w dyscyplinie linii to ją wywołujemy, w przeciwnym przypadku powrót z błędem wejścia-wyjścia. */ if (tty->ldisc.read) /* XXX casts are for what kernel-wide prototypes should be. */ i = (tty->ldisc.read)(tty,file,(unsigned char *)buf,(unsigned int)count); else i = -EIO; /* Jeżeli funkcja z dyscypliny linii zwróciła wartość większą od 0 (oznacza to, że coś zapisaliśmy) aktualizujemy czas ostatniego dostępu w i-węźle. */ if (i > 0) inode->i_atime = CURRENT_TIME; return i; }
/* * Split writes up in sane blocksizes to avoid * denial-of-service type attacks */ /* do_tty_write -zapisujemy na terminalu. Argumenty: write :funkcja zapisu z dyscypliny linii, inode :i-węzeł pliku (terminala), w którym chcemy pisąć, tty :terminal, na którym chcemy pisać, file :plik, w którym chcemy pisać, buf :bufor zawierający dane do zapisania, count :liczba bajtów, ile chcemy zapisać. Powrót: liczba_zapisanych bajtów :nie wystąpił błąd, kod błędu :wpp. */ static inline int do_tty_write( int (*write)(struct tty_struct *, struct file *, const unsigned char *, unsigned int), struct inode *inode, struct tty_struct *tty, struct file *file, const unsigned char *buf, unsigned int count) { int ret = 0, written = 0; /* Dzielimy bufor na kawałki, które przekazujemy funkcji zapisu z dyscypliny linii (argument write). */ for (;;) { unsigned int size = PAGE_SIZE*2; if (size > count) size = count; /* Zapisujemy size elementów z bufora. */ ret = write(tty, file, buf, size); /* Jeżeli nie udało się nam nic zapisać to przerywamy. */ if (ret <= 0) break; /* Zwiększamy liczbę zapisanych bajtów. */ written += ret; /* Przesuwamy się w buforze. */ buf += ret; /* Zmniejszamy liczbę bajtów do zapisania. */ count -= ret; /* Jeżeli nic nie zostało do zapisania to przerywamy. */ if (!count) break; /* Jeżeli był sygnał i nie był on blokowany to przerywamy. */ ret = -ERESTARTSYS; if (current->signal & ~current->blocked) break; /* Jeżeli potrzebujemy sponownego szeregowania to szeregujemy. */ if (need_resched) schedule(); } /* Jeżeli udało się coś zapisać to uaktualniamy czas ostatniego zapisu w i-węźle. */ if (written) { inode->i_mtime = CURRENT_TIME; ret = written; } /* Zwracamy liczbę zapisanych bajtów lub błąd. */ return ret; }
/* tty_write -funkcja zapisu do terminala. Argumenty: inode :i-węzeł pliku, do którego chcemy pisać, file :plik, do którego chcemy pisać, buf :bufor z danymi, które chcemy zapisać, count :liczba bajtów danych, ile chcemy zapisać. Powrót: liczba zapisanych bajtów :nie wystąpił błąd, kod błędu :wpp. */ static int tty_write(struct inode * inode, struct file * file, const char * buf, int count) { int is_console; struct tty_struct * tty; /* Czy urządzenie, na którym mamy pisać jest bieżącą konsolą (urządzeniem o numerze głównym TTY_MAJOR i numerze drugorzędnym 0). */ is_console = (inode->i_rdev == CONSOLE_DEV); /* Jeżeli jest bieżącą konsolą i jest przekierowane to terminalem, na którym będziemy pisać to będzie redirect, w przeciwnym przypadku pobieramy strukturę terminala z file. */ if (is_console && redirect) tty = redirect; else tty = (struct tty_struct *)file->private_data; /* Sprawdzamy, czy terminal nie jest NULLem oraz czy ma właściwy numer magic. */ if (tty_paranoia_check(tty, inode->i_rdev, "tty_write")) return -EIO; /* Jeżlei struktura terminalowa jest NULLem lub nie istnieje funkcja zapisu w sterowniku lub jest ustawiona flaga błędu wejścia-wyjścia to zwracamy błąd wejścia-wyjścia. */ if (!tty || !tty->driver.write || (tty->flags & (1 << TTY_IO_ERROR))) return -EIO; #if 0 if (!is_console && L_TOSTOP(tty) && (tty->pgrp > 0) && (current->tty == tty) && (tty->pgrp != current->pgrp)) { if (is_orphaned_pgrp(current->pgrp)) return -EIO; if (!is_ignored(SIGTTOU)) { (void) kill_pg(current->pgrp, SIGTTOU, 1); return -ERESTARTSYS; } } #endif /* Jeżeli nie istnieje funkcja zapisu w dyscyplinie linii zwracamy błąd wejścia-wyjścia. */ if (!tty->ldisc.write) return -EIO; /* Zapisujemy dane do terminala. */ return do_tty_write(tty->ldisc.write, inode, tty, file, (const unsigned char *)buf, (unsigned int)count); }
/* Semaphore to protect creating and releasing a tty */ /* Semafor do ochrony tworzenia i zwalniania struktury terminalowej. */ static struct semaphore tty_sem = MUTEX;
static void down_tty_sem(int index) { down(&tty_sem); }
static void up_tty_sem(int index) { up(&tty_sem); }
static void release_mem(struct tty_struct *tty, int idx);
/* * Rewritten to remove races and properly clean up after a failed open. * The new code protects the open with a semaphore, so it's really * quite straightforward. The semaphore locking can probably be * relaxed for the (most common) case of reopening a tty. */ /* init_dev -alokacja pamięci i inicjacja struktury terminala. Kod ten przepisano, aby usunąć wyścig procesów i poprawnie posprzątać po nieudanym otwarciu. W tej chwili otworzenie terminala jest chronione przez semafory, prawdopodobnie byłoby można zwolnić semafor dla większości przypadków powtórnego otwierania. */ Powrót: 0 :sukces, kod błędu :wpp. */ static int init_dev(kdev_t device, struct tty_struct **ret_tty) { struct tty_struct *tty, *o_tty; struct termios *tp, **tp_loc, *o_tp, **o_tp_loc; struct termios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc; struct tty_driver *driver; int retval; int idx; /* Pobieramy sterownnik dla dango urządzenia. */ driver = get_tty_driver(device); /* Jeżeli nie znaleźliśmy sterownika zwracamy błąd braku urządzenia. */ if (!driver) return -ENODEV; /* Obliczamy indeks dla urządzenia w tablicy table otworzonych urządzeń w sterowniku. Sterownik obsługuje urządzenia o tym samym numerze głównym i numerach drugorzędnych od numeru minor_start. */ idx = MINOR(device) - driver->minor_start; /* * Check whether we need to acquire the tty semaphore to avoid * race conditions. For now, play it safe. */ /* Opuszczamy odpowiedni semafor. */ down_tty_sem(idx); /* check whether we're reopening an existing tty */ /* Jeżeli powtórnie otwieramy istniejący terminal następuje, tak zwane, szybkie otworzenie :fast_track. */ tty = driver->table[idx]; if(tty) goto fast_track; /* * First time open is complex, especially for PTY devices. * This code guarantees that either everything succeeds and the * TTY is ready for operation, or else the table slots are vacated * and the allocated memory released. (Except that the termios * and locked termios may be retained.) */ /* Pierwsze otworzenie jest złożone, zwłaszcza dla pseudoterminali. Poniższy kod gwarantuje, że albo wszystko powiedzie się i terminal będzie gotowy do pracy, albo miejsca w tablicy i zaalokowana pamięć zostaną zwolnione. (Z wyjątkiem termios i termios locked, które mogą zostać zachowane w pamięci.) */ o_tty = NULL; tp = o_tp = NULL; ltp = o_ltp = NULL; /* Pobieramy miejsce dla struktury terminala. */ tty = (struct tty_struct*) get_free_page(GFP_KERNEL); /* Jeżeli nie powiodło się :fail_no_mem. */ if(!tty) goto fail_no_mem; /* Inicjujemy strukturę terminala. */ initialize_tty_struct(tty); tty->device = device; tty->driver = *driver; /* Pobieramy ze sterownika adres wskaźnika termios dla naszego terminala. */ tp_loc = &driver->termios[idx]; /* Sprawdzamy, czy wskaźnik termios jest NULLem. Mógł on zostać zainicjalizowany podczas nieudanego otworzenia. */ if (!*tp_loc) { /* Alokujemy pamięc i inicjalizujemy termios. W przypadku błędu :free_mem_out. */ tp = (struct termios *) kmalloc(sizeof(struct termios), GFP_KERNEL); if (!tp) goto free_mem_out; *tp = driver->init_termios; } /* Pobieramy ze sterownika adres wskaźnika locked termios dla naszego terminala. */ ltp_loc = &driver->termios_locked[idx]; /* Sprawdzamy, czy wskaźnik locked termios jest NULLem. Mógł zostać zainicjalizowany podczas nieudanego otworzenia. */ if (!*ltp_loc) { /* Alokujemy pamięć i zerujemy locked termios. W przypadku błędu :free_mem_out. */ ltp = (struct termios *) kmalloc(sizeof(struct termios), GFP_KERNEL); if (!ltp) goto free_mem_out; memset(ltp, 0, sizeof(struct termios)); } /* Jeżeli otwieramy psudoterminal ... */ if (driver->type == TTY_DRIVER_TYPE_PTY) { /* ...przydzielamy pamięć dla drugiej części naszego pseudoterminala. */ o_tty = (struct tty_struct *) get_free_page(GFP_KERNEL); /* Jeżeli nie mogliśmy przydzialić pamięci :free_mem_out. */ if (!o_tty) goto free_mem_out; /* Inicjalizujemy drugą część naszego pseudoterminala. */ initialize_tty_struct(o_tty); /* Przypisujemy odpowiedni numer urządzenia dla drugiej części pseudoterminala (Numer główny pobieramy ze sterownika dla drugiej części, a numer drugorzędny wyznaczamy na podstawie minor_start ze sterownika dla drugiej części oraz indeksu naszego terminala). */ o_tty->device = (kdev_t) MKDEV(driver->other->major, driver->other->minor_start + idx); /* Ustawiamy sterownik w strukturze terminalowej drugiej części psudoterminala. */ o_tty->driver = *driver->other; /* Pobieramy ze sterownika dla drugiej części pseudoterminala adres wskaźnika termios. */ o_tp_loc = &driver->other->termios[idx]; /* Sprawdzamy, czy wskaźnik termios jest NULLem. Mógł on zostać zainicjalizowany wcześniej. */ if (!*o_tp_loc) { /* Jeżeli termios dla drugiej części pseudoterminala jest NULLem to przydzielamy pamięć dla termios i je inicjalizujemy. W przypadku błędu :free_mem_out. */ o_tp = (struct termios *) kmalloc(sizeof(struct termios), GFP_KERNEL); if (!o_tp) goto free_mem_out; *o_tp = driver->other->init_termios; } /* Pobieramy ze sterownika dla drugiej części pseudoterminala adres wskaźnika locked termios. */ o_ltp_loc = &driver->other->termios_locked[idx]; /* Sprawdzamy, czy wskaźnik locked termios jest NULLem. Mógł on zostać zainicjalizowany wcześniej. */ if (!*o_ltp_loc) { /* Jeżeli locked termios dla drugiej części pseudoterminala jest NULLem to przydzielamy pamięć dla termios i ją zerujemy. W przypadku błędu :free_mem_out. */ o_ltp = (struct termios *) kmalloc(sizeof(struct termios), GFP_KERNEL); if (!o_ltp) goto free_mem_out; memset(o_ltp, 0, sizeof(struct termios)); } /* * Everything allocated ... set up the o_tty structure. */ /* Wszystko zaalokowane ... należy teraz ustawić strukturę o_tty reprezentującą drugą część naszegi pseudoterminla. */ /* Pole other w sterowniku reprezentuje sterownik dla drugiej części pseudoterminala. Wstawiamy drugą część pseudoterminal do tablicy table otworzonych urządzeń w sterowniku dla drugiej części. */ driver->other->table[idx] = o_tty; /* Ustawiamy termios i termios_locked w o_tty. */ if (!*o_tp_loc) *o_tp_loc = o_tp; if (!*o_ltp_loc) *o_ltp_loc = o_ltp; o_tty->termios = *o_tp_loc; o_tty->termios_locked = *o_ltp_loc; /* Zwiększamy licznik refcount w sterowniku dla drugiej części. Licznik ten wskazuje, ile otworzono urządzeń obsługiwanych przez ten sterownik (ile jest niepustych miejsc w tablicy table otworzonych urządzen w sterowniku). */ (*driver->other->refcount)++; /* Licznik count w strukturze terminala w części podrzędnej pseudoterminal jest zawsze o jeden większy od rzeczywistej liczby otworzonych częsci, aby nie zamknąć części podrzędnej przed nadrzędną. Dlatego, jeżeli naszą częścią jest część nadrzędna, to zwiększamy licznik count w drugiej części pseudoterminala. */ if (driver->subtype == PTY_TYPE_MASTER) o_tty->count++; /* Establish the links in both directions */ /* Ustawiamy połącznia w obie strony pomiędzy częścią nadrzędną i podrzędną pseudoterminala. */ tty->link = o_tty; o_tty->link = tty; } /* * All structures have been allocated, so now we install them. * Failures after this point use release_mem to clean up, so * there's no need to null out the local pointers. */ /* Wszystkie struktury zostały zaalokowane, więc teraz będziemy je instalować. Błąd po tym miejscu używa do porządków funkcji release_mem, w związku z tym nie ma potrzeby zwalniania lokalnych wskaźników. */ /* Wstawiamy strukturę tty do tablicy table otworzonych urządzeń w sterowniku. */ driver->table[idx] = tty; /* Ustawiamy termios i termios_locked w tty. */ if (!*tp_loc) *tp_loc = tp; if (!*ltp_loc) *ltp_loc = ltp; tty->termios = *tp_loc; tty->termios_locked = *ltp_loc; /* Zwiększamy licznik otworzonych urządzeń obsługiwanych przez dany sterownik. */ (*driver->refcount)++; /* Zwiększamy licznik w tty mówiący, ile razy otworzono urządzenie. */ tty->count++; /* * Structures all installed ... call the ldisc open routines. * If we fail here just call release_mem to clean up. No need * to decrement the use counts, as release_mem doesn't care. */ /* Wszystkie struktury zainstalowane. Otwieramy dyscyplinę linii dla naszego terminala. Jeżeli wystąpi błąd wywołujemy release_mem aby posprzątać. Nie ma potrzeby aby zmiejszać licznik count, ponieważ release_mem i tak zwolni pamięć przydzieloną dla tty i, ewentualnie, o_tty. */ if (tty->ldisc.open) { retval = (tty->ldisc.open)(tty); if (retval) goto release_mem_out; } /* Jeżeli otwieraliśmy pseudoterminal to również dla drugiej części pseudoterminala otwieramy jego dyscyplinę linii. */ if (o_tty && o_tty->ldisc.open) { retval = (o_tty->ldisc.open)(o_tty); /* Jeżeli się nie powiodło się otworzenie dyscypliny linii dla drugiej części naszego pseudoterminala to zamykamy dyscyplinę linii naszego pseudoterminala i release_mem_out. */ if (retval) { if (tty->ldisc.close) (tty->ldisc.close)(tty); goto release_mem_out; } } /* Udało się poprawnie zainicjować struktury terminala. */ goto success; /* * This fast open can be used if the tty is already open. * No memory is allocated, and the only failures are from * attempting to open a closing tty or attempting multiple * opens on a pty master. */ /* fast_track -szybkie otworzenie możę być używane tylko jeżeli terminal jest już otworzony. Nie alokujemy wtedy pamięci, więc jedyne błedy pochodzą od próby otworzenia zamykanego terminala lub próby wielokrotnego otworzenia części nadrzędnej pseudoterminala. */ fast_track: retval = -EIO; /* Sprawdzamy ustawienie flagi zamykania terminala. */ if (test_bit(TTY_CLOSING, &tty->flags)) goto end_init; /* Licznik count w strukturze terminala w części podrzędnej pseudoterminal jest zawsze o jeden większy od rzeczywistej liczby otworzonych częsci, aby nie zamknąć części podrzędnej przed nadrzędną, oprócz tego część nadrzędną mo9żna otworzyć tylko jeden raz. Dlatego, jeżeli naszą częścią jest część nadrzędna, to najpierw sprawdzamy czy była już otworzona, jeśli tak to end_init, a następnie zwiększamy licznik count w drugiej, podrzędnej, części pseudoterminala. */ if (driver->type == TTY_DRIVER_TYPE_PTY && driver->subtype == PTY_TYPE_MASTER) { /* * special case for PTY masters: only one open permitted, * and the slave side open count is incremented as well. */ if (tty->count) goto end_init; tty->link->count++; } /* Zwiększamy licznik mówiący, ile razy otworzono terminal. */ tty->count++; /* Ponownie ustawiamy sterownik w strukturze opisującej terminal. */ tty->driver = *driver; /* N.B. why do this every time?? */ /* Sukces. Udało się zaalokować i zainicjalizować wszystkie struktury dla naszego terminala. */ success: retval = 0; *ret_tty = tty; /* All paths come through here to release the semaphore */ end_init: /* Wszystkie drogi prowadzą do podniesienia semafora. */ up_tty_sem(idx); return retval; /* Release locally allocated memory ... nothing placed in slots */ /* Zwalniamy lokalnie zaalokowaną pamięć ... nic nie ma w tablicy w sterowniku. */ free_mem_out: if (o_tp) kfree_s(o_tp, sizeof(struct termios)); if (o_tty) free_page((unsigned long) o_tty); if (ltp) kfree_s(ltp, sizeof(struct termios)); if (tp) kfree_s(tp, sizeof(struct termios)); free_page((unsigned long) tty); /* Nie udało się przydzielić pamięci. */ fail_no_mem: retval = -ENOMEM; goto end_init; /* call the tty release_mem routine to clean out this slot */ /* Wywołujemy funkcję release_mem, aby wyczyścić odpowiednie miejsca w tablicy w sterowniku. */ release_mem_out: printk("init_dev: ldisc open failed, clearing slot %d\n", idx); release_mem(tty, idx); goto end_init; }
/* * Releases memory associated with a tty structure, and clears out the * driver table slots. */ /* release_mem -zwalniamy pamięć związaną ze strukturą tty i czyścimy miejsca w tablicy table w sterowniku. */ static void release_mem(struct tty_struct *tty, int idx) { struct tty_struct *o_tty; struct termios *tp; /* Jeżeli istnieje druga część pseudoterminala to ... */ if ((o_tty = tty->link) != NULL) { /* ... czyścimy miejsce w tablicy table w sterowniku dla drugoej części. */ o_tty->driver.table[idx] = NULL; /* Jeżeli była ustawiona w sterowniku flaga resetowania struktury termios to czyścimy miejsce w tablicy struktur termios w sterowniku dla drugiej części oraz zwalniamy pamięć przydzieloną dla odpowiedniego termios. */ if (o_tty->driver.flags & TTY_DRIVER_RESET_TERMIOS) { tp = o_tty->driver.termios[idx]; o_tty->driver.termios[idx] = NULL; kfree_s(tp, sizeof(struct termios)); } /* Zerujemy numer magic. */ o_tty->magic = 0; /* Zmiejszamy licznik aktualnie otworzonych urządzeń obsługiwanych przez sterownik. */ (*o_tty->driver.refcount)--; /* Zwalniamy miejsce przydzielone dla o_tty. */ free_page((unsigned long) o_tty); } /* Zerujemy miejsce w tablicy table w sterowniku. */ tty->driver.table[idx] = NULL; /* Jeżeli jest ustawiona w sterowniku flaga resetowania termios to zerujemy odpowiedni element w tablicy struktur termios w sterowniku oraz zwalniamy pamięć przydzieloną dla naszego termios. */ if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS) { tp = tty->driver.termios[idx]; tty->driver.termios[idx] = NULL; kfree_s(tp, sizeof(struct termios)); } /* Zerujemy numer magic. */ tty->magic = 0; /* Zmiejszamy licznik otworzonych urządzeń obsługiwanych przez sterownik. */ (*tty->driver.refcount)--; /* Zwalniamy pamięć przydzieloną dla tty. */ free_page((unsigned long) tty); }
/* * Even releasing the tty structures is a tricky business.. We have * to be very careful that the structures are all released at the * same time, as interrupts might otherwise get the wrong pointers. */ /* release_dev -zamykamy urządzenie. Nawet zwalnianie struktury terminala nie jest prostą sprawą. Musimy bardzo uważać i zwolnić wszystko w tym samym czasie, w przeciwnym przypadku przerwania mogą dostać niewłaściwe wskaźniki. */ static void release_dev(struct file * filp) { struct tty_struct *tty, *o_tty; int pty_master, tty_closing, o_tty_closing, do_sleep; int idx; /* Pobieramy terminal ze struktury file. */ tty = (struct tty_struct *)filp->private_data; /* Jeżeli terminal jest NULLem lub jest niewłaściwy numer magic to nie nie robimy. */ if (tty_paranoia_check(tty, filp->f_inode->i_rdev, "release_dev")) return; /* Sprawdzamy, czy licznik mówiący ile razy otworzono terminal wskazuje prawidłową wartośc. */ check_tty_count(tty, "release_dev"); tty_fasync(filp->f_inode, filp, 0); /* Obliczamy indeks naszego terminala w tablicy table w jego sterowniku. */ idx = MINOR(tty->device) - tty->driver.minor_start; /* pty_master będzie informowało czy zamykamy część nadrzędną pseudoterminala. */ pty_master = (tty->driver.type == TTY_DRIVER_TYPE_PTY && tty->driver.subtype == PTY_TYPE_MASTER); /* o_tty -ewentulanie druga część pseudoterminala. */ o_tty = tty->link; #ifdef TTY_PARANOIA_CHECK /* Trochę paranoicznych sprawdzeń. */ /* Czy obliczony indeks mieści się w zakresie dla tego sterownika. */ if (idx < 0 || idx >= tty->driver.num) { printk("release_dev: bad idx when trying to free (%s)\n", kdevname(tty->device)); return; } /* Czy element pod obliczonym indeksem w sterowniku wskazuje zamykany terminal. */ if (tty != tty->driver.table[idx]) { printk("release_dev: driver.table[%d] not tty for (%s)\n", idx, kdevname(tty->device)); return; } /* Czy zgadzają się struktury termios w naszym terminalu i w sterowniku. */ if (tty->termios != tty->driver.termios[idx]) { printk("release_dev: driver.termios[%d] not termios " "for (%s)\n", idx, kdevname(tty->device)); return; } /* Czy zgadzają się termios_locked w naszym terminalu i w sterowniku. */ if (tty->termios_locked != tty->driver.termios_locked[idx]) { printk("release_dev: driver.termios_locked[%d] not " "termios_locked for (%s)\n", idx, kdevname(tty->device)); return; } #endif #ifdef TTY_DEBUG_HANGUP printk("release_dev of %s (tty count=%d)...", tty_name(tty), tty->count); #endif #ifdef TTY_PARANOIA_CHECK /* Te same paranoiczne sprawdzenie dla drugiej części pseudoterminala. */ if (tty->driver.other) { /* Czy obliczony indeks mieści się w zakresie dla tego sterownika. */ if (o_tty != tty->driver.other->table[idx]) { printk("release_dev: other->table[%d] not o_tty for (" "%s)\n", idx, kdevname(tty->device)); return; } /* Czy element pod obliczonym indeksem w sterowniku wskazuje zamykany terminal. */ if (o_tty->termios != tty->driver.other->termios[idx]) { printk("release_dev: other->termios[%d] not o_termios " "for (%s)\n", idx, kdevname(tty->device)); return; } /* Czy zgadzają się struktury termios w naszym terminalu i w sterowniku. */ if (o_tty->termios_locked != tty->driver.other->termios_locked[idx]) { printk("release_dev: other->termios_locked[%d] not " "o_termios_locked for (%s)\n", idx, kdevname(tty->device)); return; } /* Czy zgadzają się termios_locked w naszym terminalu i w sterowniku. */ if (o_tty->link != tty) { printk("release_dev: bad pty pointers\n"); return; } } #endif /* * Sanity check: if tty->count is going to zero, there shouldn't be * any waiters on tty->read_wait or tty->write_wait. We test the * wait queues and kick everyone out _before_ actually starting to * close. This ensures that we won't block while releasing the tty * structure. * * The test for the o_tty closing is necessary, since the master and * slave sides may close in any order. If the slave side closes out * first, its count will be one, since the master side holds an open. * Thus this test wouldn't be triggered at the time the slave closes, * so we do it now. * * Note that it's possible for the tty to be opened again while we're * flushing out waiters. By recalculating the closing flags before * each iteration we avoid any problems. */ /* Rozsądne sprawdzenie: jeżeli tty->count jest 0 to nie powinno być żadnych czekających w kolejkach tty->read_wait i tty->write_wait. Sprawdzamy te kolejki i wyrzycamy wszystkich przed rozpoczęciem zamykania. To zapenia brak blokady podczas zwalniania struktury tty. Sprawdzenie zamykania o_tty jest konieczne, gdyż część nadrzędna i podrzędna pseudoterminala mogą być zamykane w dowolnej kolejności. Jeżeli najpierw strona podrzędna została zamknięta to jej licznik będzie 1, ponieważ strona nadrzędna jest otworzona. Jest możliwe ponowne otworzenie terminala podczas wyrzucania czekających, ale przez obliczanie flag zamykania przed każdą iteracją unikamy problemów. */ while (1) { /* Jeżeli licznik, ile razy otworzono ten terminal jest mniejszy równy 1 to oznacza, żę urżądzenie jest zamykane i znacznik tty_closing będzie ustawiony. */ tty_closing = tty->count <= 1; /* Znacznik o_tty_closing zostanie ustawiony, jeżeli mamy do czynienia z pseudoterminalem i licznik jest mniejszy równy 1, jeśli jest to część podrzędna lub mniejszy równy 0, jeśli jest to część nadrzędna. */ o_tty_closing = o_tty && (o_tty->count <= (pty_master ? 1 : 0)); /* do_sleep będzie wskazywać ile procesów wyrzuciliśmy z kolejek read_wait i write_wait. */ do_sleep = 0; /* Jeżeli jest ustawiony znacznik zamykania terminala. */ if (tty_closing) { /* Budzimy czekających w kolejce do odczytu z tty. */ if (waitqueue_active(&tty->read_wait)) { wake_up(&tty->read_wait); do_sleep++; } /* Budzimy czekających w kolejce do zapisu do tty. */ if (waitqueue_active(&tty->write_wait)) { wake_up(&tty->write_wait); do_sleep++; } } /* Jeżeli jest ustawiony znacznik zamykania o_tty (drugiej części pseudoterminala). */ if (o_tty_closing) { /* Budzimy czekających w kolejce do odczytu z o_tty. */ if (waitqueue_active(&o_tty->read_wait)) { wake_up(&o_tty->read_wait); do_sleep++; } /* Budzimy czekających w kolejce do zapisu do o_tty. */ if (waitqueue_active(&o_tty->write_wait)) { wake_up(&o_tty->write_wait); do_sleep++; } } /* Jeżeli nie było nikogo do obudzenia :przerywamy pętle. */ if (!do_sleep) break; printk("release_dev: %s: read/write wait queue active!\n", tty_name(tty)); /* Szeregujemy. */ schedule(); } /* * The closing flags are now consistent with the open counts on * both sides, and we've completed the last operation that could * block, so it's safe to proceed with closing. */ /* Flagi zamykania są teraz zgodne z licznikami z obu stron i zakończyliśmy ostatnią operację, która mogła doprowadzić do blokady, możemy bezpiecznie kontynuować zamykanie. */ /* Wywołujemy funkcję zamknięcia ze sterownika. */ if (tty->driver.close) tty->driver.close(tty, filp); /* Jeżeli zamykany terminal jest częścią nadrzędną pseudoterminala to zmiejszamy licznik count w drugiej części. */ if (pty_master) { if (--o_tty->count < 0) { printk("release_dev: bad pty slave count (%d) for %s\n", o_tty->count, tty_name(o_tty)); o_tty->count = 0; } } /* Zmiejszamy licznik count w terminalu. */ if (--tty->count < 0) { printk("release_dev: bad tty->count (%d) for %s\n", tty->count, tty_name(tty)); tty->count = 0; } /* * Perform some housekeeping before deciding whether to return. * * Set the TTY_CLOSING flag if this was the last open. In the * case of a pty we may have to wait around for the other side * to close, and TTY_CLOSING makes sure we can't be reopened. */ /* Robimy trochę porządków przed zakończeniem. Ustawiamy flagę TTY_CLOSING jeśli było to ostatnie otworzenie. W przypadku pseudoterminali możemy zostać zmuszeni do zaczekania na zamknięcie drugiej strony i TTY_CLOSING zapewnia, że nie zostaniemy powtórnie otworzeni. */ if(tty_closing) set_bit(TTY_CLOSING, &tty->flags); if(o_tty_closing) set_bit(TTY_CLOSING, &o_tty->flags); /* * If _either_ side is closing, make sure there aren't any * processes that still think tty or o_tty is their controlling * tty. Also, clear redirect if it points to either tty. */ /* Jeżeli któraś ze stron (tty lub o_tty) jest zamykana musimy upewnić się, że nie ma żadnych procesów, które uważają tty lub o_tty za swój terminal sterujący. Zerujemy również redirect, jeżeli wskazuje na tty lub o_tty. */ if (tty_closing || o_tty_closing) { struct task_struct *p; /* Jeżeli proces uważa tty lub o_tty za swój terminal sterujący to zerujemy mu terminal sterujący. */ for_each_task(p) { if (p->tty == tty || (o_tty && p->tty == o_tty)) p->tty = NULL; } /* Jeżeli wyjście jest przekierowane na któryś z zamykanych terminali to kasujemy przekierowanie. */ if (redirect == tty || (o_tty && redirect == o_tty)) redirect = NULL; } /* check whether both sides are closing ... */ /* Jeżeli nie zamykamy ostatni raz to powrót. */ if (!tty_closing || (o_tty && !o_tty_closing)) return; /* Zerujemy strukturę terminala w filp. */ filp->private_data = 0; #ifdef TTY_DEBUG_HANGUP printk("freeing tty structure..."); #endif /* * Shutdown the current line discipline, and reset it to N_TTY. * N.B. why reset ldisc when we're releasing the memory?? */ /* Zamykamy bieżącą dycsyplinę linii dla terminala tty. */ if (tty->ldisc.close) (tty->ldisc.close)(tty); /* Ustawiamy standardową dyscypliny linii N_TTY w terminalu tty. */ tty->ldisc = ldiscs[N_TTY]; tty->termios->c_line = N_TTY; if (o_tty) { /* Dla o_tty (jeżeli istnieje) zamykamy bieżącą dyscyplinę linii i ustawiamy N_TTY. */ if (o_tty->ldisc.close) (o_tty->ldisc.close)(o_tty); o_tty->ldisc = ldiscs[N_TTY]; } /* * Make sure that the tty's task queue isn't activated. If it * is, take it o ut of the linked list. The tqueue isn't used by * pty's, so skip the test for them. */ /* Upewniamy się, że kolejka zadań terminala nie jest aktywna. Jeżeli jest to usuwamy ją z listy. Kolejka nie jest używana przez pseudoterminale więc dla nich nie sprawdzamy. */ if (tty->driver.type != TTY_DRIVER_TYPE_PTY) { /* Zerujemy znacznik odbierania przerwań, aby nie zniszczyć kolejki. Gdyby przyszło przerwanie w trakcie zmiany mogłoby otrzymać nieprawidłowy wskaźnik i/lub coś zniszczyć. */ cli(); /* Pole sync okręśla czy kolejka została wstawiona do kolejki zadań. Jeżeli tak to ją usuwamy z listy zadań. */ if (tty->flip.tqueue.sync) { struct tq_struct *tq, *prev; for (tq=tq_timer, prev=0; tq; prev=tq, tq=tq->next) { if (tq == &tty->flip.tqueue) { if (prev) prev->next = tq->next; else tq_timer = tq->next; break; } } } /* Włączamy odbieranie przerwań. */ sti(); } /* * The release_mem function takes care of the details of clearing * the slots and preserving the termios structure. */ /* release_mem dba o poprawne zwolnienie struktur terminala i zachowanie struktur termios. */ release_mem(tty, idx); }
/* * tty_open and tty_release keep up the tty count that contains the * number of opens done on a tty. We cannot use the inode-count, as * different inodes might point to the same tty. * * Open-counting is needed for pty masters, as well as for keeping * track of serial lines: DTR is dropped when the last close happens. * (This is not done solely through tty->count, now. - Ted 1/27/92) * * The termios state of a pty is reset on first open so that * settings don't persist across reuse. */ /* tty_open i tty_release dbają o poprawną wartość licznika count, który mówi ile razy terminal został otworzony. Nie możemy używać do tego celu licznika w i-węźle, ponieważ różne i-węzły mogą reprezentować to samo urządzenie. Powrót: 0 :sukces, kod błędu :wpp. */ static int tty_open(struct inode * inode, struct file * filp) { struct tty_struct *tty; int minor; int noctty, retval; kdev_t device; retry_open: /* noctty wskazuje czy jest ustawiona flaga O_NOCTTY, jeżeli jest ustawiona to dany terminal nie może zostać terminalem sterującym dla procesu, który go otwiera. */ noctty = filp->f_flags & O_NOCTTY; /* Musimy ustalić konkretny numer urządzenia, które otwieramy. */ device = inode->i_rdev; /* Jeżeli otwieramy urządzenie reprezentujące terminal sterujący dla procesu to ... */ if (device == TTY_DEV) { /* ... sprawdzamy czy dany proces ma w ogóle terminal sterujący. Jeżeli nie to powrót z błędem. */ if (!current->tty) return -ENXIO; /* Jeżeli proces ma terminal sterujący to będziemy go otwierać. */ device = current->tty->device; /* noctty = 1; */ } /* Jeżeli otwieramy urządznie reprezentujące bieżącą konsolę to ... */ if (device == CONSOLE_DEV) { /* ... obliczamy jego numer. */ device = MKDEV(TTY_MAJOR, fg_console+1); /* Zaznaczamy, że nie może być terminalem sterującym dla procesu . */ noctty = 1; } /* Pobieramy numer drugorzędny urządzenia. */ minor = MINOR(device); /* Inicjujemy struktury terminala. */ retval = init_dev(device, &tty); if (retval) return retval; /* Wpisujemy zainicjowaną strukturę terminala do filp. */ filp->private_data = tty; /* Sprawdzamy, czy licznik count jest poprawny. */ check_tty_count(tty, "tty_open"); /* Jeżeli otwieramy część nadrzędną pseudoterminala to nie może ona być termianlem sterującym dla procesu. */ if (tty->driver.type == TTY_DRIVER_TYPE_PTY && tty->driver.subtype == PTY_TYPE_MASTER) noctty = 1; #ifdef TTY_DEBUG_HANGUP printk("opening %s...", tty_name(tty)); #endif /* Jeżeli istnieje funkcja open w sterowniku to ją wywołujemy, a w przeciwnym przypadku błąd :brak urządzenia. */ if (tty->driver.open) retval = tty->driver.open(tty, filp); else retval = -ENODEV; /* Jeżeli do tej pory nie było błędu i jest ustawiona flaga wyłączności w terminalu i nie jesteśmy superużytkownikiem to błąd :urządzenie zajęte. */ if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) && !suser()) retval = -EBUSY; /* Jeżeli wystąpił błąd. */ if (retval) { #ifdef TTY_DEBUG_HANGUP printk("error %d in opening %s...", retval, tty_name(tty)); #endif /* Zwalniamy urządzenie. */ release_dev(filp); if (retval != -ERESTARTSYS) return retval; if (current->signal & ~current->blocked) return retval; /* Szeregujemy. */ schedule(); /* * Need to reset f_op in case a hangup happened. */ /* Musimy ustawić f_op na tty_fops gdyż mogło zdarzyć się zerwanie łączności z terminalem. */ filp->f_op = &tty_fops; /* Próbujemy jeszcze raz otworzyć terminal. */ goto retry_open; } /* Jeżeli możemy uczynić terminal terminalem sterującym dla procesu i jesteśmy liderem sesji i otwierany terminal nie jset naszym terminalem sterującym i otwierany terminala nie jest termianlem żadnej sesji to ... */ if (!noctty && current->leader && !current->tty && tty->session == 0) { /* ... otwierany terminal będzie naszym terminalem sterującym, */ current->tty = tty; /* kasujemy pole tty_old_pgrp, */ current->tty_old_pgrp = 0; /* terminal będzie terminalem naszej sesji, */ tty->session = current->session; /* ustawiamy grupę terminala na naszą grupę. */ tty->pgrp = current->pgrp; } return 0; }
/* tty_release -zamykamy urządzenie terminalowe. Powrót: 0 :sukces, kod błędu :wpp. */ static void tty_release(struct inode * inode, struct file * filp) { release_dev(filp); }
/* tty_select -select ogólnie służy do odpytywania urządzeń, ale dla terminali nie robi nic poza wywołaniem funkcji select z dyscypliny linii. Powrót: 0 :sukces, kod błędu :wpp. */ static int tty_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait) { struct tty_struct * tty; /* Pobieramy terminal z filp. */ tty = (struct tty_struct *)filp->private_data; /* Jeżeli nie powiodło się sprawdzenie struktury terminala powracamy (ale bez błędu). */ if (tty_paranoia_check(tty, inode->i_rdev, "tty_select")) return 0; /* Struktura terminala jest poprawna. */ /* Jeżeli istnieje funkcja select w dyscyplinie linii to ją wywołujemy. */ if (tty->ldisc.select) return (tty->ldisc.select)(tty, inode, filp, sel_type, wait); return 0; }
/* * fasync_helper() is used by some character device drivers (mainly mice) * to set up the fasync queue. It returns negative on error, 0 if it did * no changes and positive if it added/deleted the entry. */ /* fasync_helper -używana przez niektóre urządzenia znakowe (głównie myszy) aby aktualizować kolejkę fasync. Wstawia argument filp do kolejki fapp, jeżeli jeszcze nie jest wstawiony i jest ustawiony on. Argumenty: inode :i-węzeł terminala (nieużywane), filp :plik, on :czy wstawiamy (1), czy usuwamy (0) z kolejki fapp strukturę filp, fapp :kolejka struktur fasync_struct. Powrót: ujemna liczba (kod błędu) :wystąpił błąd, 0 :nie było zmian, dodatnia liczba :dodała lub usunęła coś z kolejki. */ int fasync_helper(struct inode * inode, struct file * filp, int on, struct fasync_struct **fapp) { struct fasync_struct *fa, **fp; unsigned long flags; /* Szukamy na liście fapp struktury reprezentującej plik filp. */ for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) { if (fa->fa_file == filp) break; } if (on) { /* Mamy wstawić strukturę filp do kolejki fapp. */ /* Jeżeli znależliśmy plik filp to powrót, nic nie zmienialiśmy. */ if (fa) return 0; /* Przydzielamy pamięć dla struktury fasync_struct. */ fa = (struct fasync_struct *)kmalloc(sizeof(struct fasync_struct), GFP_KERNEL); /* Jeżeli nie udało się przydzielić pamięci wracamu z błędem :brak pamięci. */ if (!fa) return -ENOMEM; /* Wypełniamy strukturę fasync_struct. */ fa->magic = FASYNC_MAGIC; fa->fa_file = filp; save_flags(flags); /* Zerujemy znacznik odbieranie przerwań. */ cli(); /* Wstawiamy fa na początek listy fapp. */ fa->fa_next = *fapp; *fapp = fa; restore_flags(flags); return 1; } /* Mamy usunąc filp z kolejki fapp. */ /* Jeżeli nie znaleźliśmy filp na liście fapp to powrót. */ if (!fa) return 0; /* Znaleźliśmy filp na liście fapp. */ save_flags(flags); /* Wyłączamy odbieranie przerwań. */ cli(); /* Usuwamy filp z listy. */ *fp = fa->fa_next; restore_flags(flags); kfree(fa); return 1; }
/* tty_fasync. Powrót: 0 :sukces, kod błędu :wpp. */ static int tty_fasync(struct inode * inode, struct file * filp, int on) { struct tty_struct * tty; int retval; /* Pobieramy terminal z flip. */ tty = (struct tty_struct *)filp->private_data; /* Jeżeli terminal jest nieprawidłowy to powrót (bez błędu). */ if (tty_paranoia_check(tty, inode->i_rdev, "tty_fasync")) return 0; retval = fasync_helper(inode, filp, on, &tty->fasync); if (retval <= 0) return retval; if (on) { /* Jeżeli kolejka czekających na odczyt z terminala nie jest aktywna to ustawiamy minimum_to_wake na 1. Pole minimum_to_wake oznacza ilość znaków w buforze wystarczającą, aby obudzić procesy czekające na odczyt z terminala. */ if (!waitqueue_active(&tty->read_wait)) tty->minimum_to_wake = 1; if (filp->f_owner.pid == 0) { filp->f_owner.pid = (-tty->pgrp) ? : current->pid; filp->f_owner.uid = current->uid; filp->f_owner.euid = current->euid; } } else { /* Jeżeli nie ma niczego w kolejce fasync i kolejka czekających na odczyt z terminala nie jest aktywna to ustawiamy minimum_to_wake na rozmiar bufora. */ if (!tty->fasync && !waitqueue_active(&tty->read_wait)) tty->minimum_to_wake = N_TTY_BUF_SIZE; } return 0; }
#if 0 /* * XXX does anyone use this anymore?!? */ static int do_get_ps_info(unsigned long arg) { struct tstruct { int flag; int present[NR_TASKS]; struct task_struct tasks[NR_TASKS]; }; struct tstruct *ts = (struct tstruct *)arg; struct task_struct **p; char *c, *d; int i, n = 0; i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct tstruct)); if (i) return i; for (p = &FIRST_TASK ; p <= &LAST_TASK ; p++, n++) if (*p) { c = (char *)(*p); d = (char *)(ts->tasks+n); for (i=0 ; i<sizeof(struct task_struct) ; i++) put_user(*c++, d++); put_user(1, ts->present+n); } else put_user(0, ts->present+n); return(0); } #endif
/* tty_ioctl -wykonuje polecenia specyficzne dla terminali. Powrót: 0 :sukces, kod błędu :wpp. */ static int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) { int retval; struct tty_struct * tty; struct tty_struct * real_tty; struct winsize tmp_ws; pid_t pgrp; unsigned char ch; char mbz = 0; /* Pobieramy terminal z file. */ tty = (struct tty_struct *)file->private_data; /* Jeżeli struktura terminala jest nieprawidłowa zwracamy błąd :nieprawidłowa wartość. */ if (tty_paranoia_check(tty, inode->i_rdev, "tty_ioctl")) return -EINVAL; /* Dla części nadrzędnej pseudoterminala terminalem, na którym będziemy wykonywać operacje będzie jego para. */ if (tty->driver.type == TTY_DRIVER_TYPE_PTY && tty->driver.subtype == PTY_TYPE_MASTER) real_tty = tty->link; else real_tty = tty; /* Wykonujemy określone czynności w zależności od komendy, którą dostaliśmy. */ switch (cmd) { case TIOCSTI: /* Przekazujemy jeden znak do obrobienia dla dyscypliny linii. */ /* Musimy wykonywać operacię na własnym terminalu sterującym i musimy mieć uprawnienia superużytkownika. */ if ((current->tty != tty) && !suser()) return -EPERM; retval = verify_area(VERIFY_READ, (void *) arg, 1); if (retval) return retval; ch = get_user((char *) arg); tty->ldisc.receive_buf(tty, &ch, &mbz, 1); return 0; case TIOCGWINSZ: /* Zlecenie pobrania struktury winsize opisującej rozmiar okna. */ retval = verify_area(VERIFY_WRITE, (void *) arg, sizeof (struct winsize)); if (retval) return retval; memcpy_tofs((struct winsize *) arg, &tty->winsize, sizeof (struct winsize)); return 0; case TIOCSWINSZ: /* Zmieniamy rozmiar okna. */ retval = verify_area(VERIFY_READ, (void *) arg, sizeof (struct winsize)); if (retval) return retval; memcpy_fromfs(&tmp_ws, (struct winsize *) arg, sizeof (struct winsize)); /* Wysyłamy sygnał SIGWINCH (zmiany rozmiaru okna) do grupy terminala tty i do grupy terminala real_tty (jeżeli są to różne grupy). Sygnał ten może być przechwytywany przez procesy, które muszą reagować na zmianę rozmiaru okna np. edytory. */ if (memcmp(&tmp_ws, &tty->winsize, sizeof(struct winsize))) { if (tty->pgrp > 0) kill_pg(tty->pgrp, SIGWINCH, 1); if ((real_tty->pgrp != tty->pgrp) && (real_tty->pgrp > 0)) kill_pg(real_tty->pgrp, SIGWINCH, 1); } /* Ustawiamy nowe rozmiary okna w tty i real_tty. */ tty->winsize = tmp_ws; real_tty->winsize = tmp_ws; return 0; case TIOCCONS: /* Przekierowujemy wyjście. Jeżeli operacja jest wykonywana na konsoli to oznacza wyzerowanie przekierowania (tylko superużytkownik ma prawo wykonać tę operację). */ if (tty->driver.type == TTY_DRIVER_TYPE_CONSOLE) { if (!suser()) return -EPERM; redirect = NULL; return 0; } /* Jeżeli wyjście już jest przekierowane to powrót z błędem :zajęte. */ if (redirect) return -EBUSY; /* Ustawiamy redirect na real_tty (oznacza część podrzędną pseudoterminala). */ redirect = real_tty; return 0; case FIONBIO: /* Ustawiamy lub zerujemy (w zależności od argumentu arg) flagę wykonywania operacji bez blokowania. */ retval = verify_area(VERIFY_READ, (void *) arg, sizeof(int)); if (retval) return retval; arg = get_user((unsigned int *) arg); if (arg) file->f_flags |= O_NONBLOCK; else file->f_flags &= ~O_NONBLOCK; return 0; case TIOCEXCL: /* Ustawiamy flagę wyłączności dla terminala. */ set_bit(TTY_EXCLUSIVE, &tty->flags); return 0; case TIOCNXCL: /* Kasujemy flagę wyłączności dla terminala. */ clear_bit(TTY_EXCLUSIVE, &tty->flags); return 0; case TIOCNOTTY: /* Operacja odłączania terminala sterującego. */ /* Jeżeli wykonywana na terminalu innym niż terminal sterujący dla procesu to zwracamy błąd. */ if (current->tty != tty) return -ENOTTY; /* Jeżeli wykonuje ją lider to wywołujemy disassociate_ctty. */ if (current->leader) disassociate_ctty(0); /* Proces nie ma już terminala sterującego. */ current->tty = NULL; return 0; case TIOCSCTTY: /* Zdobywa terminal sterujący. */ /* Jeżeli jest liderem sesji i należy do sesji terminala powrót z sukcesem. */ if (current->leader && (current->session == tty->session)) return 0; /* * The process must be a session leader and * not have a controlling tty already. */ /* Proces musi być liderem sesji i nie może mieć terminala sterującego. */ if (!current->leader || current->tty) return -EPERM; if (tty->session > 0) { /* * This tty is already the controlling * tty for another session group! */ /* Ten terminal jest już terminalem sterujący, dla innej grupy sesji. */ /* Jeżeli jesteśmy superużytkownikiem możemy go ukraść, a w przeciwnym przypadku zwracamy błąd. */ if ((arg == 1) && suser()) { /* * Steal it away */ struct task_struct *p; /* Kasujemy terminal sterujący dla procesów, dla których zdobywany terminal jest sterującym. */ for_each_task(p) if (p->tty == tty) p->tty = NULL; } else return -EPERM; } /* Ustawiamy terminal terminalem sterującym dla procesu. */ current->tty = tty; current->tty_old_pgrp = 0; tty->session = current->session; tty->pgrp = current->pgrp; return 0; case TIOCGPGRP: /* Pobieramy identyfikator grupy terminalowej. */ /* * (tty == real_tty) is a cheap way of * testing if the tty is NOT a master pty. */ /* Jeżeli tty nie jest częścią nadrzędną pseudoterminala i nie jest terminalem strującym dla procesu to błąd. */ if (tty == real_tty && current->tty != real_tty) return -ENOTTY; /* Identyfikator grupy terminalowej pobieramy tylko wtedy, gdy tty jest terminalem sterującym dla procesu lub jest częścią nadrzędną pseudoterminala. */ retval = verify_area(VERIFY_WRITE, (void *) arg, sizeof (pid_t)); if (retval) return retval; put_user(real_tty->pgrp, (pid_t *) arg); return 0; case TIOCSPGRP: /* Zmieniamy identyfikator grupy terminalowej. */ /* Sprawdzamy, czy możemy zmienić stan terminala. */ retval = tty_check_change(real_tty); if (retval == -EIO) return -ENOTTY; if (retval) return retval; /* Jeżeli proces nie terminala sterującego lub ma inny terminal sterujący lub nie należy do grupy sesji terminala to zwracamy błąd. */ if (!current->tty || (current->tty != real_tty) || (real_tty->session != current->session)) return -ENOTTY; pgrp = get_user((pid_t *) arg); /* Sprawdzamy poprawność nowego identyfikatora. */ if (pgrp < 0) return -EINVAL; if (session_of_pgrp(pgrp) != current->session) return -EPERM; /* Ustawiamy nowy identyfikator. */ real_tty->pgrp = pgrp; return 0; case TIOCGETD: /* Pobieramy numer bieżącej dyscypliny linii. */ retval = verify_area(VERIFY_WRITE, (void *) arg, sizeof (int)); if (retval) return retval; put_user(tty->ldisc.num, (int *) arg); return 0; case TIOCSETD: /* Zmieniamy dyscyplinę linii. */ /* Czy możemy zmienić stan terminala. */ retval = tty_check_change(tty); if (retval) return retval; retval = verify_area(VERIFY_READ, (void *) arg, sizeof (int)); if (retval) return retval; arg = get_user((int *) arg); return tty_set_ldisc(tty, arg); case TIOCLINUX: /* Komendy Linuxa. */ /* Mogą być wykonywane tylko na konsolach. */ if (tty->driver.type != TTY_DRIVER_TYPE_CONSOLE) return -EINVAL; /* Możemy je wykonywać tylko dla własnego terminala sterującego lub jeżeli jesteśmy superużytkownikiem. */ if (current->tty != tty && !suser()) return -EPERM; retval = verify_area(VERIFY_READ, (void *) arg, 1); if (retval) return retval; switch (retval = get_user((char *)arg)) { case 0: case 8: case 9: printk("TIOCLINUX (0/8/9) ioctl is gone - use /dev/vcs\n"); return -EINVAL; #if 0 case 1: printk("Deprecated TIOCLINUX (1) ioctl\n"); return do_get_ps_info(arg); #endif case 2: /* Zmieniamy sposób wyświetlania wyróżnionych fragmentów. */ return set_selection(arg, tty, 1); case 3: /* Wstawiamy zawartość wyróżnionego bufora do kolejki terminala związanego z bieżącą konsolą. */ return paste_selection(tty); case 4: /* Jeżeli ekran był wygaszony to przywraca stan normalny. */ do_unblank_screen(); return 0; case 5: /* Zmienia tablicę inwordLut (zdefiniowana w pliku selection.c) określającą, które znaki są uważane za alfabetyczne. */ return sel_loadlut(arg); case 6: /* * Make it possible to react to Shift+Mousebutton. * Note that 'shift_state' is an undocumented * kernel-internal variable; programs not closely * related to the kernel should not use this. */ /* Umożliwia reakcję na Shift+PrzyciskMyszy. */ retval = verify_area(VERIFY_WRITE, (void *) arg, 1); if (retval) return retval; put_user(shift_state,(char *) arg); return 0; case 7: /* Pobiera informacje o myszy. */ retval = verify_area(VERIFY_WRITE, (void *) arg, 1); if (retval) return retval; put_user(mouse_reporting(),(char *) arg); return 0; case 10: /* Zmieniamy tryb wygaszania monitora. */ set_vesa_blanking(arg); return 0; case 11: /* set kmsg redirect */ /* Zmiana konsoli dla komunikatów jądra. */ /* Musimy być superużytkownikiem, aby wykonać tę operację. */ if (!suser()) return -EPERM; retval = verify_area(VERIFY_READ, (void *) arg+1, 1); if (retval) return retval; kmsg_redirect = get_user((char *)arg+1); return 0; case 12: /* get fg_console */ /* Pobieramy bieżącą konsolę. */ return fg_console; default: return -EINVAL; } case TIOCTTYGSTRUCT: /* Pobieramy strukturę opisującą terminal. */ retval = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct tty_struct)); if (retval) return retval; memcpy_tofs((struct tty_struct *) arg, tty, sizeof(struct tty_struct)); return 0; default: /* Nieznana komenda. */ /* Wywołujemy funkcję ioctl ze sterownika. */ if (tty->driver.ioctl) { retval = (tty->driver.ioctl)(tty, file, cmd, arg); if (retval != -ENOIOCTLCMD) return retval; } /* Jeżeli ioctl ze sterownika nie potrafiła rozpoznać komendy to wywołujemy ioctl z dyscypliny linii. */ if (tty->ldisc.ioctl) { retval = (tty->ldisc.ioctl)(tty, file, cmd, arg); if (retval != -ENOIOCTLCMD) return retval; } /* Jeżeli nawet ioctl z dyscypliny linii nie potrafiła rozpoznać komendy zwracamy błąd :zła wartość. */ return -EINVAL; } }
/* * This implements the "Secure Attention Key" --- the idea is to * prevent trojan horses by killing all processes associated with this * tty when the user hits the "Secure Attention Key". Required for * super-paranoid applications --- see the Orange Book for more details. * * This code could be nicer; ideally it should send a HUP, wait a few * seconds, then send a INT, and then a KILL signal. But you then * have to coordinate with the init process, since all processes associated * with the current tty must be dead before the new getty is allowed * to spawn. */ /* do_SAK -Funkcja ta jest implementacja tzw. "Secure Attention Key" -jego celem jest unieszkodliwienie koni trojańskich przez zabicie wszystkich procesów związanych z terminalem, kiedy użytkownik naciśnie "Secure Attention Key". */ void do_SAK( struct tty_struct *tty) { #ifdef TTY_SOFT_SAK /* Jeżeli jest zdefiniowany "miękki" SAK to następuje zwykłe zerwanie łączności z terminalem. */ tty_hangup(tty); #else /* W przeciwnym przypadku zabijamy wszystkie procesy związane z terminalem. */ struct task_struct **p; int session; int i; struct file *filp; if (!tty) return; session = tty->session; /* Opróżniamy bufor dyscypliny linii. */ if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); /* Opróżniamy bufor sterownika. */ if (tty->driver.flush_buffer) tty->driver.flush_buffer(tty); for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) { if (!(*p)) continue; /* Wysyłamy sygnał SIGKILL do procesów, dla których terminal jest terminalem sterującym lub które należą do sesji terminala oraz do procesów, które mają otworzony dany terminal. */ if (((*p)->tty == tty) || ((session > 0) && ((*p)->session == session))) send_sig(SIGKILL, *p, 1); else if ((*p)->files) { for (i=0; i < NR_OPEN; i++) { filp = (*p)->files->fd[i]; if (filp && (filp->f_op == &tty_fops) && (filp->private_data == tty)) { send_sig(SIGKILL, *p, 1); break; } } } } #endif }
/* * This routine is called out of the software interrupt to flush data * from the flip buffer to the line discipline. */ /* flush_to_ldisc -procedura ta jest wołana z przerwania programowego, aby przpisać dane z bufora flip w tty do dyscypliny linii. */ static void flush_to_ldisc(void *private_) { struct tty_struct *tty = (struct tty_struct *) private_; unsigned char *cp; char *fp; int count; /* flip zawiera tablice char_buf i flag_buf. Tablice te są podzielone na dwie części i buf_num określa, z której połowy korzystamy. */ if (tty->flip.buf_num) { /* Korzystamy z drugiej połowy tablic char_buf i flag_buf. */ cp = tty->flip.char_buf + TTY_FLIPBUF_SIZE; fp = tty->flip.flag_buf + TTY_FLIPBUF_SIZE; tty->flip.buf_num = 0; /* Zerowanie znacznika zezwolenia na przerwanie. */ cli(); tty->flip.char_buf_ptr = tty->flip.char_buf; tty->flip.flag_buf_ptr = tty->flip.flag_buf; } else { /* Korzystamy z pierwaszej połowy tablic char_buf i flag_buf. */ cp = tty->flip.char_buf; fp = tty->flip.flag_buf; tty->flip.buf_num = 1; /* Zerowanie znacznika zezwolenia na przerwanie. */ cli(); tty->flip.char_buf_ptr = tty->flip.char_buf + TTY_FLIPBUF_SIZE; tty->flip.flag_buf_ptr = tty->flip.flag_buf + TTY_FLIPBUF_SIZE; } count = tty->flip.count; tty->flip.count = 0; /* Włączamy obsługę przerwań. */ sti(); #if 0 if (count > tty->max_flip_cnt) tty->max_flip_cnt = count; #endif /* Przekazujemy dane do dyscypliny linii. */ tty->ldisc.receive_buf(tty, cp, fp, count); }
/* * This subroutine initializes a tty structure. */ /* initialize_tty_struct -inicjalizujemy strukturę terminala. */ static void initialize_tty_struct(struct tty_struct *tty) { /* Ustawiamy właściwy dla terminala numer magic, ustawiamy standardową dyscyplinę linii N_TTY, na razie grupa terminalowa nie istnieje, ustawiamy wskaźniki w buforze sterownika, ustawiamy funkcję bottom half i argument dla niej. */ memset(tty, 0, sizeof(struct tty_struct)); tty->magic = TTY_MAGIC; tty->ldisc = ldiscs[N_TTY]; tty->pgrp = -1; tty->flip.char_buf_ptr = tty->flip.char_buf; tty->flip.flag_buf_ptr = tty->flip.flag_buf; tty->flip.tqueue.routine = flush_to_ldisc; tty->flip.tqueue.data = tty; }
/* * The default put_char routine if the driver did not define one. */ /* tty_default_put_char -domyślna procedura put_char, jeżeli sterownik nie ma zdefiniowanej żadnej. Funkcja ta wywołuje funkcję write ze sterownika z buforem zawierającym tylko jeden znak.*/ void tty_default_put_char(struct tty_struct *tty, unsigned char ch) { tty->driver.write(tty, 0, &ch, 1); }
/* * Called by a tty driver to register itself. */ /* tty_register_driver -rejestracja sterownika dla terminala. Powrót: 0 :sukces, kod błędu :wpp. */ int tty_register_driver(struct tty_driver *driver) { int error; if (driver->flags & TTY_DRIVER_INSTALLED) return 0; /* Wywołujemy funkcję rejestracji urządzenia znakowego. Funckja zwraca numer główny urządzenia lub ujemny kod błędu. Jeżeli w sterowniku numer główny jest 0 oznacza to, że jądro przydziela numer główny dla urządzenia (później aktualizujemy numer główny w sterowniku). */ error = register_chrdev(driver->major, driver->name, &tty_fops); if (error < 0) return error; else if(driver->major == 0) driver->major = error; /* Jeżeli sterownik nie ma zdefiniowanej procedury put_char ustawiamy domyślną procedurę put_char. */ if (!driver->put_char) driver->put_char = tty_default_put_char; /* Dodajemy sterownik do listy sterowników. */ driver->prev = 0; driver->next = tty_drivers; if (tty_drivers) tty_drivers->prev = driver; tty_drivers = driver; return error; }
/* * Called by a tty driver to unregister itself. */ /* tty_unregister_driver -wyrejestrowuje sterownik terminala. */ int tty_unregister_driver(struct tty_driver *driver) { int retval; struct tty_driver *p; int found = 0; const char *othername = NULL; /* Jeżeli jakieś urządzenie korzysta w tej chwili ze sterownika zwracamy błąd :zajęty. */ if (*driver->refcount) return -EBUSY; /* Szukamy sterownika na liście sterowników, a także sprawdzamy czy istnieje inny sterownik, który obsługuje urządzenia o takim samym numerze głównym. */ for (p = tty_drivers; p; p = p->next) { if (p == driver) found++; else if (p->major == driver->major) othername = p->name; } /* Jeżeli nie znaleźliśmy zwracamy błąd. */ if (!found) return -ENOENT; if (othername == NULL) { /* Jeżeli nie istnieje inny sterownik, który obsługuje urządzenia o takim samym numerze głównym odrejestrowujemy urządzenia. */ retval = unregister_chrdev(driver->major, driver->name); if (retval) return retval; } else /* W przeciwnym przypadku rejestrujemy urządzenia z nowym sterownikiem. */ register_chrdev(driver->major, othername, &tty_fops); /* Usuwamy sterownik z listy. */ if (driver->prev) driver->prev->next = driver->next; else tty_drivers = driver->next; if (driver->next) driver->next->prev = driver->prev; return 0; }
/* * Initialize the console device. This is called *early*, so * we can't necessarily depend on lots of kernel help here. * Just do some early initializations, and do the complex setup * later. */ /* console_init -inicjalizacja konsoli. ta funkcja jest wołana "wcześnie", więc nie możemy liczyć na wielką pomoc jądra. Robimy tylko trochę inicjalizacji, a resztę dokończymy później. */ long console_init(long kmem_start, long kmem_end) { /* Rejestrujemy standardową dyscyplinę linii N_TTY. */ /* Setup the default TTY line discipline. */ memset(ldiscs, 0, sizeof(ldiscs)); (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY); /* * Set up the standard termios. Individual tty drivers may * deviate from this; this is used as a template. */ /* Inicjalizujemy standardową strukturę termios. Poszczególne sterowniki mogą odejść od niej, ta jest używana tylko jako przykładowa. */ memset(&tty_std_termios, 0, sizeof(struct termios)); memcpy(tty_std_termios.c_cc, INIT_C_CC, NCCS); tty_std_termios.c_iflag = ICRNL | IXON; tty_std_termios.c_oflag = OPOST | ONLCR; tty_std_termios.c_cflag = B38400 | CS8 | CREAD | HUPCL; tty_std_termios.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN; /* * set up the console device so that later boot sequences can * inform about problems etc.. */ /* Inicjalizujemy konsolę, tak więc następni będą mogli informować o problemach itd.. */ return con_init(kmem_start); }
static struct tty_driver dev_tty_driver, dev_console_driver; /* * Ok, now we can initialize the rest of the tty devices and can count * on memory allocations, interrupts etc.. */ /* tty_init -inicjalizacja pozostałych urządzeń terminalowych. Możemy liczyć na alokację pamięci, przerwania itd.. Powrót: 0. */ int tty_init(void) { if (sizeof(struct tty_struct) > PAGE_SIZE) panic("size of tty structure > PAGE_SIZE!"); /* * dev_tty_driver and dev_console_driver are actually magic * devices which get redirected at open time. Nevertheless, * we register them so that register_chrdev is called * appropriately. */ /* dev_tty_driver i dev_console_driver są dziwnymi urządzeniami, ponieważ nie zawsze wskazują to samo (są to odpowiednio: terminal sterujący:/dev/tty i bieżąca konsola:/dev/tty0 lub /dev/console). Ale pomimo tego normalnie rejestrujemy te sterowniki, a więc także urządzenia. */ /* Rejestracja sterownika dev_tty_driver dla terminala sterującego. */ memset(&dev_tty_driver, 0, sizeof(struct tty_driver)); dev_tty_driver.magic = TTY_DRIVER_MAGIC; dev_tty_driver.name = "tty"; dev_tty_driver.name_base = 0; dev_tty_driver.major = TTY_MAJOR; dev_tty_driver.minor_start = 0; dev_tty_driver.num = 1; if (tty_register_driver(&dev_tty_driver)) panic("Couldn't register /dev/tty driver\n"); /* Rejestracja sterownika dev_console_driver dla bieżącej konsoli. */ dev_console_driver = dev_tty_driver; dev_console_driver.name = "console"; dev_console_driver.major = TTYAUX_MAJOR; if (tty_register_driver(&dev_console_driver)) panic("Couldn't register /dev/console driver\n"); /* A teraz pozostałe inicjalizacje ... */ kbd_init(); #ifdef CONFIG_SERIAL rs_init(); #endif #ifdef CONFIG_SCC scc_init(); #endif #ifdef CONFIG_CYCLADES cy_init(); #endif #ifdef CONFIG_STALLION stl_init(); #endif #ifdef CONFIG_ISTALLION stli_init(); #endif #ifdef CONFIG_DIGI pcxe_init(); #endif #ifdef CONFIG_RISCOM8 riscom8_init(); #endif #ifdef CONFIG_BAYCOM baycom_init(); #endif #ifdef CONFIG_SPECIALIX specialix_init(); #endif pty_init(); vcs_init(); return 0; }
Komentowała: Patrycja Węgrzynowicz