For mouse, keyboard and joystick drivers, it may X call the 'open' then using these drivers.
( when I check CentOS 7 (text mode only) in VirtualBox, I didn't see X after executed lsof /dev/input/event2 ( keyboard ), but my keyboard still working )
How about tty_open() ?
According to a call trace, we can roughly know the sequence:
( at least, we know someone called 'sys_open' )
https://bugzilla.redhat.com/show_bug.cgi?id=630464
However, I still don't know who calls the 'open'?
When I check CentOS 7, text mode only, in VirtualBox, I didn't see X after executed lsof /dev/input/event2 (keyboard), but my keyboard still works
That is because you use the virtual console then, one of the /dev/ttyN devices. These are directly wired to the Linux input event subsystem inside the kernel itself (by the vt module); essentially all keyboard-like devices act as inputs to the currently active virtual terminal.
X itself uses a virtual console, just so that the kernel can switch between it and any text-based virtual consoles.
How about tty_open()?
If you run sudo lsof /dev/tty[0-9], you can see which processes are accessing a virtual console.
The processes with getty in their name are the ones that provide login terminals. (The ones that are used with serial terminals are very similar; in fact, many getty programs can handle both virtual consoles and serial terminals just fine.)
When you log in, that getty launches login (program!), which in turn starts the default shell defined for that user (see getent passwd username; it is the last field, and it must be one that is listed in /etc/shells to be allowed).
The kernel itself supports switching to a different virtual console via Ctrl+Alt+Fn (F1 for tty1, F2 for tty2, and so on). If you use suitable graphics drivers, you can even switch between Xorg and virtual consoles. (Usually, Xorg is run on tty6 or tty7, but that varies from distribution to distribution.) The Ctrl+Alt+ā and Ctrl+Alt+ā can also usually be used to switch to the previous or next virtual console.
Thanks for Nominal Animal for the information.
I am tracing linux 2.0 ( https://mirrors.edge.kernel.org/pub/linux/kernel/v2.0/ ), thing maybe a little different.
Sorry, I can't find an online Linux 2.0 source to link reference.
For keyboard, in text mode, I think no one calling 'open' in kernel,
In 'int tty_init(void)' ( tty_io.c ), it will call 'kbd_init();'
then we can see:
request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard", NULL);
therefore, keyboard HW can work with this IRQ & callback ('keyboard_interrupt').
For tty_open(), I finally see it in main.c
open("/dev/tty1",O_RDWR,0);
For the newer version of kernel, I think this part migrated to getty application, that's why I can't find it in kernel source.
tty_* routines are UNIX hardware independent code to implement the terminal interface in the kernel. They are responsible of the tty disciplines, the job control stuff and the linemode processing of characters (including the generation of signals on Ctrl-C for example) They also implement the interface to tty/pty pairs and the like.
This is common code to include all the common functionality of the terminal drivers into any kind of hardware you can have attached for (console keyboard/display is just one example, but you have, at least, uart RS-232C interfaces, usb serial dongles, PCI serial line multiplexors, etc)
Terminal functionality dates from the ancient v7 unix, and has many improvements coming from BSD unix (like job control)
By the way, linux implementation of serial interface is not very good, you should look at the BSD implementation for a good one.
Related
What is the real difference between the LINUX_REBOOT_CMD_HALT and LINUX_REBOOT_CMD_POWER_OFF arguments to the reboot() system call (resp. the RB_HALT_SYSTEM and RB_POWER_OFF arguments given to its wrapper function)?
The reboot(2) manual page has the following descriptions (differences emphasized):
RB_HALT_SYSTEM
LINUX_REBOOT_CMD_HALT
(RB_HALT_SYSTEM, 0xcdef0123; since Linux 1.1.76). The message "System halted." is printed, and the system is halted. Control is given to the ROM monitor, if there is one. If not preceded by a sync(2), data will be lost.
LINUX_REBOOT_CMD_POWER_OFF
(RB_POWER_OFF, 0x4321fedc; since Linux 2.1.30).
The message "Power down." is printed, the system is stopped, and all power is removed from the system, if possible. If not preceded by a sync(2), data will be lost.
Reading the descriptions, a few questions come up:
What is the difference between halted and stopped?
Would a reboot(RB_HALT_SYSTEM) call not remove power from the
system?
Where would the "System halted." and "Power down." messages be printed?
I don't think there is a difference; those words are synonyms in common English and I think this documentation is just using their English meaning, not as specific technical terms.
correct, that's exactly what the docs are trying to tell you.
on the console and/or kernel log, duh. Where kernel messages are normally printed, like during bootup.
You can easily try these for yourself to see what they do; the user-space shutdown(8) command has -H (halt) and -P / -h (poweroff) options, as well as -r. Read the man page. I assume it eventually makes a reboot(2) system call, or causes init to make one, after a sync.
And yes, the traditional shutdown -h command is halt + power off, i.e. POWER_OFF. Back in the old days, computers didn't used to be able to power themselves off, but these days that's usually what people think of as a non-reboot shutdown. Especially on systems where the kernel can't "return" to a BIOS / firmware command interface.
On a PC, one of the few use-cases I could imagine for halt without poweroff would be to insert a USB drive or CD before pressing the reset button (or ctrl+alt+delete). But maybe you don't want the currently-booted Linux kernel to react to the new hardware at all, so you want to halt Linux first.
You could poweroff to do this, but you don't need to and there's no need to start/stop your rotating disks and put extra wear on their motors.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I'm making a Command-Line Operating system (command line interpreter). How to I get a line of input from the user?
I'm making a Command-Line Operating system. How to I get a line of input form a user?
The first things you'll need are some boot code (to get things like a memory map from firmware), physical memory management, virtual memory management, a scheduler and some kind of inter-process communication (IPC).
The next things you'll need is some kind of device enumeration framework, to help make a tree of devices to keep track of everything; followed by scanning PCI buses to add them to the tree of devices.
Next you'll want to tackle device resources - determining IO port ranges, memory mapped IO ranges and managing IRQs. This can be messy (e.g. AML interpreter for ACPI to determine IO APIC inputs, and "interrupt vector allocator" to handle MSI).
The next thing is USB controller drivers, USB hub driver and maybe (for obsolete hardware) a PS/2 controller driver. These all find devices connected to them (e.g. USB keyboard) and add them to the tree of devices, and then communicate with the drivers for those devices. At some point you might also want to worry about fault tolerance, power management and hot-plug (e.g. if a USB controller driver crashes, is put to sleep or is removed/unplugged; then you'd use the "tree of devices" to figure out which other drivers are effected).
Next, you'll want keyboard drivers. Specifically, a driver for "USB HID" (which is a single specification that covers all human input devices - keyboard, mouse, touchpad, joystick, ..), and maybe (for obsolete hardware) a PS/2 keyboard driver. Note that you'll probably also want an on-screen keyboard for touch-screen users, and input method editor/s to assist with input of some languages (Chinese, Japanese, Korean, etc).
Next, you'll want something for video output. Typically early boot code uses minimal "just enough to display boot log" code (if it's not hidden by a pretty splash image); but you'll want something that's actually good instead (likely including a font engine with Unicode support).
The end result of all of the above is that you'll have a set of (hopefully "standardised for your OS" and documented) device driver interfaces and all of the things that device drivers depend on; a way (the inter-process communication I mentioned near the start) to send "events" (key-presses) to a process and a way for processes to display output (draw things on the screen).
Once all that is done you can write a terminal emulation layer. This is a thing (process?) that hides all the nice modern stuff (e.g. OpenGL, events) under a layer of historic memorabilia (so that the end user's computer, which is likely to be capable of emulating realistic virtual reality environments, can be used as a glorified teleprinter from early last century). This also uses the inter-process communication I mentioned near the start (e.g. maybe pipes - stdin, stdout) to communicate with a child process.
Finally, you can begin writing some sort of command shell. This is just a process that communicates with its parent (e.g. with the terminal emulation layer) via. whatever you're using for inter-process communication (e.g. stdin, stdout) that allows users to start other processes and handles a little "forwarding" (e.g. while a child process is running, keyboard input that shell receives from terminal emulation layer gets forwarded by shell to its child process, and output the shell receives from its child gets forwarded by shell back to shell's parent/terminal emulator).
Note that as part of writing the command shell, or before writing the command shell, you might want to write some libraries to handle simple chores (e.g. getting a whole line of user input and handling things like "home", "end", "delete", "backspace", etc) so that these libraries can be used by all programs including the command shell itself.
It seems doubtful that you are truly implementing an operating system, but if you simply mean a command shell, then it might follow the following structure:
int main()
{
char command_line[1024] ;
char* input = NULL ;
int errorlevel = 0 ;
do
{
// Show command prompt
putchar( '>' ) ;
fflush( stdout ) ;
// Get command line
input = fgets( command_line, stdin, sizeof(command_line) ) ;
if( input != NULL )
{
// Process command line
errorlevel = parseCommand( input, &errorlevel ) ;
}
} while( input != NULL ) ;
return errorlevel ;
}
where parse parseCommand() is a function with the following interface:
int parseCommand( const char* cmd_line, const int* current_errorlevel ) ;
Here the answer to your question of how to get a line of user input is the fgets() function.
The complex part perhaps is in the implementation of parseCommand(); user input is the easy part, but make a start - have fun.
Unlike everyone I appreciate you thinking big but focus on the basics first as it is good to start small. Also, what you are doing is making a command line interpreter and not an OS. There's a big difference between the two. For an OS, you need a kernel, GUI, etc. However here's the solution to your query:
You can use gets, but you might receive a warning in this one
char *gets(char *str)
To overcome above limitation, we can use fgets as :
char *fgets(char *str, int size, FILE *stream)
Using %[^\n]%*c inside scanf
scanf(ā%[^\n]%*cā, str);
This one comes quite in handy when using for loop.
You have a bright future if you think innovatively (people lack this).
But it's always better to brush your base before going big. Welcome to stackoverflow :)
I know how to open a serial port using 'open' function:
open("/dev/portname", flags)
But I want two programs to open this port but with reversed read/write lines. For example when program 2 writes something to the port, program 1 can read it.
If you're using a Unix-like operating system, and if you don't need full serial port semantics, named pipes can be quite useful for doing this sort of thing.
If you need more control, you could perhaps use a pair of pseudoterminals, with a third program running in the background shuttling characters between the master ends.
And do see the related question "Virtual Serial Port for Linux" that the StackOverflow machinery already found for you.
You cannot typically do that in software.
Such things are normally done by hardware, and that is what cross-over cables and "null-modem" cables are good for.
How can I write a C program (in userspace) to call functions that are part of a kernel driver? If it's not possible to do directly, how else do I do it?
CONTEXT: I am trying to use the PWM pins of my single-board computer (Intel NUC DE3815TYBE) so that I can control fans. A linux driver called pwm_lpss allows control of these pins (driver developed by Intel, source code here). I have verified that this driver is installed by using the lsmod command. Here is the driver information after typing modinfo pwm_lpss:
filename: /lib/modules/3.19.0-25-generic/kernel/drivers/pwm/pwm-lpss.ko
license: GPL v2
author: Mika Westerberg <mika.westerberg#linux.intel.com>
description: PWM driver for Intel LPSS
srcversion: 44AA14AF3E2F96C813770A8
depends:
intree: Y
vermagic: 3.19.0-25-generic SMP mod_unload modversions
signer: Magrathea: Glacier signing key
sig_key: 6A:AA:11:D1:8C:2D:3A:40:B1:B4:DB:E5:BF:8A:D6:56:DD:F5:18:38
sig_hashalgo: sha512
So I know where the driver module is (the pwm-lpss.ko file) and I have the source code which I know has a function in it called pwm_lpss_config() that I'd like to use. How do I call the function from my userspace C program? How would I go about #including it? Or is this not possible to do from userspace?
Unfortunately Intel has provided zero documentation for how to use this driver. I thought drivers normally map their functionality to some user-accessible file. I was able to find some PWM-related files after some digging, but I haven't been able to find a file that looks like it can set PWM duty cycle/frequency.
It's a standard Linux PWM driver, so no special documentation is necessary.
Check the /sys/class/pwm/ directory. (/sys is the interface the kernel provides for access to its data structures. It just looks and acts like a filesystem.) You should have something like /sys/class/pwm/pwmchip0/. Each such directory corresponds to a PWM chip.
The directory will have the following entries. You may need superuser privileges to access these (as you wouldn't want everybody to mess with them):
npwm: Read this to find out how many PWM channels this chip has.
export: Write a channel number (0 to whatever-the-number-in-npwm-1) to make that channel available via this sysfs interface
unexport: Write a channel number to remove the channel from sysfs interface control
Each PWM channel exported to be used via the sysfs interface will show up as a subdirectory named pwmN, where N is the channel number. Here, you can read and write to entries
period: Total period (off + on) in nanoseconds.
duty_cycle: On time in nanoseconds. Must be less than period.
polarity: If the chip supports reversing the signal polarity, you can write inversed here to invert the polarity; normal is the default/normal polarity.
enable: 1 if enabled, 0 if disabled.
When reading or writing to these entries, no special locking is necessary. The kernel will receive all data in one write(), and return all data in one read() operation. When a write() succeeds, the kernel has applied the setting.
some ioctl ? The ioctl() function manipulates the underlying device parameters of special files.
Along the lines
fd = open("/dev/pwm0", O_RDONLY); // put whatever device you've got
if (ioctl(fd, STATUSGET, &status) == -1) // magic constant should be set
....
} else {
....
}
I'm customising Linux for an ARM9 Atmel AT91SAM960 board.
In the device file Atmel named all the USART the same atmel_usart. Of course with id enumeration:
static struct platform_device at91sam9260_uart0_device = {
.name = "atmel_usart",
.id = 1,
.dev = { ...}
}
According to the Linux Device model, all these devices (5 UARTS on a SAM9260) would be bind to the driver named atmel_usart.
I don't want to set a TTYS driver on all UARTS which will be registerd. I have several own drivers which serve for different specialised purposes (LON, RS-485 etc.) I want the control which driver does serve a certain USART. So what could I do:
The Atmel device files are unsatisfiable and I can do it better. So I rename (patch) the devices in the device file. However, in case I want a TTYS driver on UART4 I would be in trouble.
I manipulate (patch) the device file,
so that I'm able the access the
structures platform_device. I could
change their names before I would
register them. But as far as I
understood the idea of the Linux Driver Model,
devices should be
registered early during boot-up but the binding to a driver follows .... later.
I could write a driver, which has an
alias name and which would be binded
to a specific bus_Id ->
atmel_usart.4. Can I really?
What solutions else exist. I want to touch a minimal set of Kernel files but I want all the freedom possible?
Addendum what freedom means to me: I can specify at runtime how the UARTS can be used
with the Atmel-Serial driver (ttyS)
with my own drivers
It means also, that changes to the kernel source are minimal.
I built my own line discipline drivers. You can build them as kernel modules and attach them to the UARTs at runtime. No changes to the Linux source are necessary.
Any funny timing or control stuff can be done through ioctl(). Specifically, I implemented a timing-sensitive RS-485 protocol in this way.
When I did this (Linux 2.6.17) there was no dynamic registration mechanism, so I overwrote the existing line disciplines. The Linux code is (was) pretty straightforward, and I was satisfied that this would be a safe thing to do.
Your problem is quite easily solved. The 5 UART devices are presently registered at kernel startup and their function is locked. This is now how it normally works for PCI or USB devices, right? So what you need to do is pull the device registration out of the startup code and register it dynamically. You can even register/unregister as needed.
at91_register_uart() is being called from your board file for every UART that needs registered. at91_add_device_serial() will then platform_device_register all those you what setup. One solution is to let at91_register_uart() be called for all 5 UARTS, but then remove the call to at91_add_device_serial() from your board. You can then make it an exported function that can be called by your loadable drivers. You can even add an argument to it (int) so that instead of looping on all UARTS, you can select which ones to register individually. You can also mirror this function by making one that unregisters the devices.
NOTE: I think you'll need to always leave one UART dedicated as your console, if you are using one that way. You could probably hide that in the exported function by only allowing index 0->3 as in input and then mapping 0->3 to 0-4, skipping the UART that you want to use for console.