|  |  | 
|  | The Lockronomicon | 
|  |  | 
|  | Your guide to the ancient and twisted locking policies of the tty layer and | 
|  | the warped logic behind them. Beware all ye who read on. | 
|  |  | 
|  | FIXME: still need to work out the full set of BKL assumptions and document | 
|  | them so they can eventually be killed off. | 
|  |  | 
|  |  | 
|  | Line Discipline | 
|  | --------------- | 
|  |  | 
|  | Line disciplines are registered with tty_register_ldisc() passing the | 
|  | discipline number and the ldisc structure. At the point of registration the | 
|  | discipline must be ready to use and it is possible it will get used before | 
|  | the call returns success. If the call returns an error then it won't get | 
|  | called. Do not re-use ldisc numbers as they are part of the userspace ABI | 
|  | and writing over an existing ldisc will cause demons to eat your computer. | 
|  | After the return the ldisc data has been copied so you may free your own | 
|  | copy of the structure. You must not re-register over the top of the line | 
|  | discipline even with the same data or your computer again will be eaten by | 
|  | demons. | 
|  |  | 
|  | In order to remove a line discipline call tty_unregister_ldisc(). | 
|  | In ancient times this always worked. In modern times the function will | 
|  | return -EBUSY if the ldisc is currently in use. Since the ldisc referencing | 
|  | code manages the module counts this should not usually be a concern. | 
|  |  | 
|  | Heed this warning: the reference count field of the registered copies of the | 
|  | tty_ldisc structure in the ldisc table counts the number of lines using this | 
|  | discipline. The reference count of the tty_ldisc structure within a tty | 
|  | counts the number of active users of the ldisc at this instant. In effect it | 
|  | counts the number of threads of execution within an ldisc method (plus those | 
|  | about to enter and exit although this detail matters not). | 
|  |  | 
|  | Line Discipline Methods | 
|  | ----------------------- | 
|  |  | 
|  | TTY side interfaces: | 
|  |  | 
|  | open()		-	Called when the line discipline is attached to | 
|  | the terminal. No other call into the line | 
|  | discipline for this tty will occur until it | 
|  | completes successfully. Returning an error will | 
|  | prevent the ldisc from being attached. Can sleep. | 
|  |  | 
|  | close()		-	This is called on a terminal when the line | 
|  | discipline is being unplugged. At the point of | 
|  | execution no further users will enter the | 
|  | ldisc code for this tty. Can sleep. | 
|  |  | 
|  | hangup()	-	Called when the tty line is hung up. | 
|  | The line discipline should cease I/O to the tty. | 
|  | No further calls into the ldisc code will occur. | 
|  | The return value is ignored. Can sleep. | 
|  |  | 
|  | write()		-	A process is writing data through the line | 
|  | discipline.  Multiple write calls are serialized | 
|  | by the tty layer for the ldisc.  May sleep. | 
|  |  | 
|  | flush_buffer()	-	(optional) May be called at any point between | 
|  | open and close, and instructs the line discipline | 
|  | to empty its input buffer. | 
|  |  | 
|  | chars_in_buffer() -	(optional) Report the number of bytes in the input | 
|  | buffer. | 
|  |  | 
|  | set_termios()	-	(optional) Called on termios structure changes. | 
|  | The caller passes the old termios data and the | 
|  | current data is in the tty. Called under the | 
|  | termios semaphore so allowed to sleep. Serialized | 
|  | against itself only. | 
|  |  | 
|  | read()		-	Move data from the line discipline to the user. | 
|  | Multiple read calls may occur in parallel and the | 
|  | ldisc must deal with serialization issues. May | 
|  | sleep. | 
|  |  | 
|  | poll()		-	Check the status for the poll/select calls. Multiple | 
|  | poll calls may occur in parallel. May sleep. | 
|  |  | 
|  | ioctl()		-	Called when an ioctl is handed to the tty layer | 
|  | that might be for the ldisc. Multiple ioctl calls | 
|  | may occur in parallel. May sleep. | 
|  |  | 
|  | compat_ioctl()	-	Called when a 32 bit ioctl is handed to the tty layer | 
|  | that might be for the ldisc. Multiple ioctl calls | 
|  | may occur in parallel. May sleep. | 
|  |  | 
|  | Driver Side Interfaces: | 
|  |  | 
|  | receive_buf()	-	Hand buffers of bytes from the driver to the ldisc | 
|  | for processing. Semantics currently rather | 
|  | mysterious 8( | 
|  |  | 
|  | write_wakeup()	-	May be called at any point between open and close. | 
|  | The TTY_DO_WRITE_WAKEUP flag indicates if a call | 
|  | is needed but always races versus calls. Thus the | 
|  | ldisc must be careful about setting order and to | 
|  | handle unexpected calls. Must not sleep. | 
|  |  | 
|  | The driver is forbidden from calling this directly | 
|  | from the ->write call from the ldisc as the ldisc | 
|  | is permitted to call the driver write method from | 
|  | this function. In such a situation defer it. | 
|  |  | 
|  | dcd_change()	-	Report to the tty line the current DCD pin status | 
|  | changes and the relative timestamp. The timestamp | 
|  | cannot be NULL. | 
|  |  | 
|  |  | 
|  | Driver Access | 
|  |  | 
|  | Line discipline methods can call the following methods of the underlying | 
|  | hardware driver through the function pointers within the tty->driver | 
|  | structure: | 
|  |  | 
|  | write()			Write a block of characters to the tty device. | 
|  | Returns the number of characters accepted. The | 
|  | character buffer passed to this method is already | 
|  | in kernel space. | 
|  |  | 
|  | put_char()		Queues a character for writing to the tty device. | 
|  | If there is no room in the queue, the character is | 
|  | ignored. | 
|  |  | 
|  | flush_chars()		(Optional) If defined, must be called after | 
|  | queueing characters with put_char() in order to | 
|  | start transmission. | 
|  |  | 
|  | write_room()		Returns the numbers of characters the tty driver | 
|  | will accept for queueing to be written. | 
|  |  | 
|  | ioctl()			Invoke device specific ioctl. | 
|  | Expects data pointers to refer to userspace. | 
|  | Returns ENOIOCTLCMD for unrecognized ioctl numbers. | 
|  |  | 
|  | set_termios()		Notify the tty driver that the device's termios | 
|  | settings have changed. New settings are in | 
|  | tty->termios. Previous settings should be passed in | 
|  | the "old" argument. | 
|  |  | 
|  | The API is defined such that the driver should return | 
|  | the actual modes selected. This means that the | 
|  | driver function is responsible for modifying any | 
|  | bits in the request it cannot fulfill to indicate | 
|  | the actual modes being used. A device with no | 
|  | hardware capability for change (eg a USB dongle or | 
|  | virtual port) can provide NULL for this method. | 
|  |  | 
|  | throttle()		Notify the tty driver that input buffers for the | 
|  | line discipline are close to full, and it should | 
|  | somehow signal that no more characters should be | 
|  | sent to the tty. | 
|  |  | 
|  | unthrottle()		Notify the tty driver that characters can now be | 
|  | sent to the tty without fear of overrunning the | 
|  | input buffers of the line disciplines. | 
|  |  | 
|  | stop()			Ask the tty driver to stop outputting characters | 
|  | to the tty device. | 
|  |  | 
|  | start()			Ask the tty driver to resume sending characters | 
|  | to the tty device. | 
|  |  | 
|  | hangup()		Ask the tty driver to hang up the tty device. | 
|  |  | 
|  | break_ctl()		(Optional) Ask the tty driver to turn on or off | 
|  | BREAK status on the RS-232 port.  If state is -1, | 
|  | then the BREAK status should be turned on; if | 
|  | state is 0, then BREAK should be turned off. | 
|  | If this routine is not implemented, use ioctls | 
|  | TIOCSBRK / TIOCCBRK instead. | 
|  |  | 
|  | wait_until_sent()	Waits until the device has written out all of the | 
|  | characters in its transmitter FIFO. | 
|  |  | 
|  | send_xchar()		Send a high-priority XON/XOFF character to the device. | 
|  |  | 
|  |  | 
|  | Flags | 
|  |  | 
|  | Line discipline methods have access to tty->flags field containing the | 
|  | following interesting flags: | 
|  |  | 
|  | TTY_THROTTLED		Driver input is throttled. The ldisc should call | 
|  | tty->driver->unthrottle() in order to resume | 
|  | reception when it is ready to process more data. | 
|  |  | 
|  | TTY_DO_WRITE_WAKEUP	If set, causes the driver to call the ldisc's | 
|  | write_wakeup() method in order to resume | 
|  | transmission when it can accept more data | 
|  | to transmit. | 
|  |  | 
|  | TTY_IO_ERROR		If set, causes all subsequent userspace read/write | 
|  | calls on the tty to fail, returning -EIO. | 
|  |  | 
|  | TTY_OTHER_CLOSED	Device is a pty and the other side has closed. | 
|  |  | 
|  | TTY_NO_WRITE_SPLIT	Prevent driver from splitting up writes into | 
|  | smaller chunks. | 
|  |  | 
|  |  | 
|  | Locking | 
|  |  | 
|  | Callers to the line discipline functions from the tty layer are required to | 
|  | take line discipline locks. The same is true of calls from the driver side | 
|  | but not yet enforced. | 
|  |  | 
|  | Three calls are now provided | 
|  |  | 
|  | ldisc = tty_ldisc_ref(tty); | 
|  |  | 
|  | takes a handle to the line discipline in the tty and returns it. If no ldisc | 
|  | is currently attached or the ldisc is being closed and re-opened at this | 
|  | point then NULL is returned. While this handle is held the ldisc will not | 
|  | change or go away. | 
|  |  | 
|  | tty_ldisc_deref(ldisc) | 
|  |  | 
|  | Returns the ldisc reference and allows the ldisc to be closed. Returning the | 
|  | reference takes away your right to call the ldisc functions until you take | 
|  | a new reference. | 
|  |  | 
|  | ldisc = tty_ldisc_ref_wait(tty); | 
|  |  | 
|  | Performs the same function as tty_ldisc_ref except that it will wait for an | 
|  | ldisc change to complete and then return a reference to the new ldisc. | 
|  |  | 
|  | While these functions are slightly slower than the old code they should have | 
|  | minimal impact as most receive logic uses the flip buffers and they only | 
|  | need to take a reference when they push bits up through the driver. | 
|  |  | 
|  | A caution: The ldisc->open(), ldisc->close() and driver->set_ldisc | 
|  | functions are called with the ldisc unavailable. Thus tty_ldisc_ref will | 
|  | fail in this situation if used within these functions. Ldisc and driver | 
|  | code calling its own functions must be careful in this case. | 
|  |  | 
|  |  | 
|  | Driver Interface | 
|  | ---------------- | 
|  |  | 
|  | open()		-	Called when a device is opened. May sleep | 
|  |  | 
|  | close()		-	Called when a device is closed. At the point of | 
|  | return from this call the driver must make no | 
|  | further ldisc calls of any kind. May sleep | 
|  |  | 
|  | write()		-	Called to write bytes to the device. May not | 
|  | sleep. May occur in parallel in special cases. | 
|  | Because this includes panic paths drivers generally | 
|  | shouldn't try and do clever locking here. | 
|  |  | 
|  | put_char()	-	Stuff a single character onto the queue. The | 
|  | driver is guaranteed following up calls to | 
|  | flush_chars. | 
|  |  | 
|  | flush_chars()	-	Ask the kernel to write put_char queue | 
|  |  | 
|  | write_room()	-	Return the number of characters tht can be stuffed | 
|  | into the port buffers without overflow (or less). | 
|  | The ldisc is responsible for being intelligent | 
|  | about multi-threading of write_room/write calls | 
|  |  | 
|  | ioctl()		-	Called when an ioctl may be for the driver | 
|  |  | 
|  | set_termios()	-	Called on termios change, serialized against | 
|  | itself by a semaphore. May sleep. | 
|  |  | 
|  | set_ldisc()	-	Notifier for discipline change. At the point this | 
|  | is done the discipline is not yet usable. Can now | 
|  | sleep (I think) | 
|  |  | 
|  | throttle()	-	Called by the ldisc to ask the driver to do flow | 
|  | control.  Serialization including with unthrottle | 
|  | is the job of the ldisc layer. | 
|  |  | 
|  | unthrottle()	-	Called by the ldisc to ask the driver to stop flow | 
|  | control. | 
|  |  | 
|  | stop()		-	Ldisc notifier to the driver to stop output. As with | 
|  | throttle the serializations with start() are down | 
|  | to the ldisc layer. | 
|  |  | 
|  | start()		-	Ldisc notifier to the driver to start output. | 
|  |  | 
|  | hangup()	-	Ask the tty driver to cause a hangup initiated | 
|  | from the host side. [Can sleep ??] | 
|  |  | 
|  | break_ctl()	-	Send RS232 break. Can sleep. Can get called in | 
|  | parallel, driver must serialize (for now), and | 
|  | with write calls. | 
|  |  | 
|  | wait_until_sent() -	Wait for characters to exit the hardware queue | 
|  | of the driver. Can sleep | 
|  |  | 
|  | send_xchar()	  -	Send XON/XOFF and if possible jump the queue with | 
|  | it in order to get fast flow control responses. | 
|  | Cannot sleep ?? | 
|  |  |