Differences
This shows you the differences between two versions of the page.
| Both sides previous revision Previous revision Next revision | Previous revision | ||
| nicholassouchu:kernelgraphicsinterface [2022/06/10 02:18] – Import KII content KubilayKocak | nicholassouchu:kernelgraphicsinterface [2022/06/10 02:46] (current) – Finally, expand acronyms for page names KubilayKocak | ||
|---|---|---|---|
| Line 21: | Line 21: | ||
| * [[# | * [[# | ||
| * [[#kii|KII Input System]] | * [[#kii|KII Input System]] | ||
| - | * input drivers ([[/KgiInput|KgiInput]]) | + | * [[#kgiinput|KGI Input]] Drivers |
| - | * keyboard / mouse multiplexing ([[/KgiFocus|KgiFocus]]) | + | * [[#kgifocus|KGI Focus]]: Keyboard & Mouse Multiplexing |
| * keymap support (not yet) | * keymap support (not yet) | ||
| + | * [[# | ||
| * a console (KGC) with: | * a console (KGC) with: | ||
| Line 77: | Line 78: | ||
| Drivers using the %%KgimAPI%% are known as %%KgimDrivers%%. | Drivers using the %%KgimAPI%% are known as %%KgimDrivers%%. | ||
| + | |||
| + | === KGIM Drivers === | ||
| + | |||
| + | A KGIM driver is the driver of a graphic board written for KGI and respecting the %%KgimAPI%%. | ||
| + | |||
| + | KGIM drivers are broken down in several subsystems (or subdrivers) which are typically the components of a graphic display HW chain: | ||
| + | |||
| + | * chipset | ||
| + | * clock | ||
| + | * ramdac | ||
| + | * monitor | ||
| + | |||
| + | The result of linking the compilation objects of the above subsystems gives you a %%KgimBoard%%. Currently, the glue-code between the subsystems is partly KGI API dependent for implementing a %%KgiDisplay%% and partly dependent of the operating system supposed to load the %%KgimBoard%% as a module. | ||
| + | |||
| + | A KGIM board is not yet a Plugins because it is specific to the OS it was compiled for. | ||
| + | |||
| + | Code which is system specific is isolated from the rest of the subsystems' | ||
| + | |||
| + | In the %%FreeBSD%% implementation, | ||
| + | |||
| + | When the board module is loaded into the %%FreeBSD%% kernel, the probe routine has already acknowledged the chipset existance. Consequently, | ||
| ==== KII ==== | ==== KII ==== | ||
| Line 100: | Line 122: | ||
| / | / | ||
| </ | </ | ||
| + | |||
| + | === KGI Input === | ||
| + | |||
| + | A [[/ | ||
| + | |||
| + | The [[/ | ||
| + | |||
| + | === KGI Focus === | ||
| + | |||
| + | The [[/ | ||
| + | |||
| + | When you hit a key on your keyboard, you want it to go to the console you are working on and application(s) running on that console should get the event delivered. | ||
| + | |||
| + | Other applications running on other consoles should not get the event (for obvious security reasons). | ||
| + | |||
| + | When you want to switch to another physical (dual-head) or virtual (also known as VTs) console, you press a key combination to switch and then want now your chars to be sent to the right console. | ||
| + | |||
| + | In other words, you need the system manages the focus for you in a convenient, deterministic and safe manner. | ||
| + | |||
| + | These connections are at the same time dynamic and static. Static because the relationship between | ||
| + | display and input instances is predefined. Dynamic because you can register any [[/ | ||
| + | mouse or keyboards) or [[/ | ||
| + | |||
| + | So what is predefined relationship? | ||
| + | |||
| + | < | ||
| + | device 0 on focus 0, display 0, console 0 | ||
| + | device 1 on focus 0, display 0, console 1 | ||
| + | device 2 on focus 0, display 1, console 2 | ||
| + | device 3 on focus 0, display 1, console 3 | ||
| + | device 4 on focus 0, display 1, console 4 | ||
| + | device 5 on focus 0, display 1, console 5 | ||
| + | device 6 on focus 0, display 1, console 6 | ||
| + | device 7 on focus 0, display 1, console 7 | ||
| + | device 8 on focus 0, display 1, console 8 | ||
| + | device 9 on focus 0, display 1, console 9 | ||
| + | device 10 on focus 0, display 1, console 10 | ||
| + | device 11 on focus 0, display 1, console 11 | ||
| + | device 12 on focus 1, display 2, console 0 | ||
| + | device 13 on focus 1, display 2, console 1 | ||
| + | device 14 on focus 1, display 2, console 2 | ||
| + | device 15 on focus 1, display 2, console 3 | ||
| + | device 16 on focus 1, display 2, console 4 | ||
| + | device 17 on focus 1, display 2, console 5 | ||
| + | device 18 on focus 1, display 2, console 6 | ||
| + | device 19 on focus 1, display 2, console 7 | ||
| + | device 20 on focus 1, display 2, console 8 | ||
| + | device 21 on focus 1, display 2, console 9 | ||
| + | device 22 on focus 1, display 2, console 10 | ||
| + | device 23 on focus 1, display 2, console 11 | ||
| + | </ | ||
| + | |||
| + | It presents the case of 2 keyboards (represented by 2 focuses) for which one has 3 screens. | ||
| + | Each focus can reach 12 consoles (typically what you get with a PC keyboard with F1..F12). Focus 1 | ||
| + | is totally linked to display 2 (1 keyboard + 1 screen wired config) and | ||
| + | focus 1 can either control consoles 0 and 1 through display 0 and others through | ||
| + | display 1. It means that with focus 0, when you hit ALT+F1 you edit commands on display 0, | ||
| + | ALT-F3 : you edit on display 1, ALT-F1 you change VT on display 0 and ALT-F4 to ALT-F12 : you | ||
| + | switch to VTs on display 1. | ||
| + | |||
| + | ==== KGI Mutex ==== | ||
| + | |||
| + | Mutexes are the basic KGI execution control mechanism. | ||
| + | |||
| + | The mutex API was originaly design on the basis of %%FreeBSD%% mutex(9) and condvar(9) implementations. | ||
| + | On %%FreeBSD%%, | ||
| + | to merge them. It is mutex centric e.g some events may be associated to a mutex. It's convenient | ||
| + | when you have a mutex locking a object, the events associated to the mutex are obviously | ||
| + | related to the object locked. | ||
| + | |||
| + | For example, when a buffer is finished to execute, you want to own the buffer mutex when returning from | ||
| + | the waiting queue. That way you can proceed on the buffer immediatly after the wait. The downside | ||
| + | is that you must own the mutex before waiting... | ||
| + | |||
| + | See the [[/ | ||
| ===== KGI for FreeBSD (kgi4BSD) Project ===== | ===== KGI for FreeBSD (kgi4BSD) Project ===== | ||
| Line 135: | Line 232: | ||
| ===== Application Programming Interface ===== | ===== Application Programming Interface ===== | ||
| - | The KGI API includes: | + | ==== KGI Device |
| - | * [[/ | + | kgi_device_t |
| - | * [[/ | + | |
| - | * [[/ | + | |
| - | The %%KgimAPI%% is part of [[/ | + | * The unique identifier of the device |
| + | |||
| + | < | ||
| + | kgi_u_t id; | ||
| + | </ | ||
| + | |||
| + | * The identifier of the [[/ | ||
| + | |||
| + | < | ||
| + | kgi_u_t dpy_id; | ||
| + | </ | ||
| + | |||
| + | * Various flags | ||
| + | |||
| + | < | ||
| + | kgi_device_flags_t flags; | ||
| + | </ | ||
| + | |||
| + | * Currently set mode for the device | ||
| + | |||
| + | < | ||
| + | kgi_mode_t *mode; | ||
| + | </ | ||
| + | |||
| + | * Per device instance private data | ||
| + | |||
| + | < | ||
| + | kgi_private_t priv; | ||
| + | </ | ||
| + | |||
| + | The three methods of a KGI device are callbacks called by KGI on KGI events: | ||
| + | |||
| + | * When the device is mapped to its display | ||
| + | |||
| + | < | ||
| + | kgi_device_map_device_fn *MapDevice; | ||
| + | </ | ||
| + | |||
| + | * When the device is unmapped from its display | ||
| + | |||
| + | < | ||
| + | kgi_device_unmap_device_fn *UnmapDevice; | ||
| + | </ | ||
| + | |||
| + | * When a %%KiiEvent%% has to be delivered to the KGI device | ||
| + | |||
| + | < | ||
| + | kgi_device_handle_event_fn *HandleEvent; | ||
| + | </ | ||
| + | |||
| + | ==== KGI Input API ==== | ||
| + | |||
| + | kii_input_t: | ||
| + | |||
| + | * The next input in the linked list | ||
| + | |||
| + | < | ||
| + | kii_input_t *next; | ||
| + | </ | ||
| + | |||
| + | * The focus we belong to | ||
| + | |||
| + | < | ||
| + | kii_u_t focus; | ||
| + | </ | ||
| + | |||
| + | * Unique input device ID | ||
| + | |||
| + | < | ||
| + | kii_u_t id; | ||
| + | </ | ||
| + | |||
| + | * Bit mask of generated events | ||
| + | |||
| + | < | ||
| + | kii_event_mask_t events; | ||
| + | </ | ||
| + | |||
| + | * Bit mask of events to report | ||
| + | |||
| + | < | ||
| + | kii_event_mask_t report; | ||
| + | </ | ||
| + | |||
| + | * Vendor and Model strings for info only | ||
| + | |||
| + | < | ||
| + | kii_ascii_t | ||
| + | kii_ascii_t | ||
| + | </ | ||
| + | |||
| + | * Method for executing a command specific to the input | ||
| + | |||
| + | < | ||
| + | int (*Command)(kii_input_t *, kii_u_t cmd, void *); | ||
| + | </ | ||
| + | |||
| + | * Method called to poll a 32bits scancode | ||
| + | |||
| + | < | ||
| + | int (*Poll)(kii_input_t *); | ||
| + | </ | ||
| + | |||
| + | * Method called to parse a 32bits scancode got by Poll method | ||
| + | |||
| + | < | ||
| + | void (*Parse)(kii_input_t *, kii_event_t *, int); | ||
| + | </ | ||
| + | |||
| + | * Private data of the input | ||
| + | |||
| + | < | ||
| + | kii_private_t | ||
| + | </ | ||
| + | |||
| + | kii_register_input() | ||
| + | |||
| + | kii_register_input() | ||
| + | |||
| + | < | ||
| + | kii_error_t kii_register_input( | ||
| + | |||
| + | /* Comment: the focus to register to */ | ||
| + | | ||
| + | |||
| + | /* Comment: preinitialized data about the input to register */ | ||
| + | | ||
| + | ); | ||
| + | </ | ||
| + | |||
| + | The return code is null (KII_EOK) on succes. Otherwise, the appropriate return code is given back. | ||
| + | |||
| + | A typical registration | ||
| + | |||
| + | < | ||
| + | snprintf(sc-> | ||
| + | snprintf(sc-> | ||
| + | sc-> | ||
| + | sc-> | ||
| + | sc-> | ||
| + | sc-> | ||
| + | sc-> | ||
| + | |||
| + | kii_error = kii_register_input((~0), | ||
| + | </ | ||
| + | |||
| + | In the above example, KII_INVALID_FOCUS is passed as focus id to let [[/KII]] auto register the input | ||
| + | according to its capabilities e.g sc-> | ||
| + | the software data pointer of the kbd device. | ||
| + | |||
| + | kbdriver_parser() takes scancodes from the RAW output of a kbd and fills the event structure passed in. | ||
| + | Event is only reported to [[/KII]] if the event type corresponds (e.g bit set) in sc-> | ||
| + | |||
| + | Here is another example of registration: | ||
| + | |||
| + | < | ||
| + | snprintf(mouse-> | ||
| + | snprintf(mouse-> | ||
| + | |||
| + | mouse-> | ||
| + | mouse-> | ||
| + | mouse-> | ||
| + | mouse-> | ||
| + | mouse-> | ||
| + | |||
| + | /* XXX Force registration to focus 0 */ | ||
| + | if (!(error = kii_register_input(0, | ||
| + | make_dev(& | ||
| + | UID_ROOT, GID_WHEEL, 0600, " | ||
| + | } else { | ||
| + | KRN_ERROR(" | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | The above registration comes from the scemul device provided by KII to %%FreeBSD%%. It emulates the | ||
| + | / | ||
| + | This data is processed internally and sent back to userland by / | ||
| + | |||
| + | In this example, no Parser or Poll methods are set. Instead, scemul responds to the mouse | ||
| + | daemon inputs by sending directly the event to KII. | ||
| + | |||
| + | kii_unregister_input(): | ||
| + | |||
| + | kii_unregister_input() is typically called when the module of an input driver is unloaded. | ||
| + | |||
| + | < | ||
| + | void kii_unregister_input( | ||
| + | |||
| + | /* Comment: the input to unregister from its focus */ | ||
| + | | ||
| + | ); | ||
| + | </ | ||
| + | |||
| + | ==== KGI Display API ==== | ||
| + | |||
| + | kgi_display_t | ||
| + | |||
| + | Data of a KGI display are: | ||
| + | |||
| + | * KGI display revision | ||
| + | |||
| + | < | ||
| + | kgi_u_t revision; | ||
| + | </ | ||
| + | |||
| + | * Vendor and Model strings | ||
| + | |||
| + | < | ||
| + | kgi_ascii_t vendor[KGI_MAX_VENDOR_STRING]; | ||
| + | kgi_ascii_t model[KGI_MAX_VENDOR_STRING]; | ||
| + | </ | ||
| + | |||
| + | * Flags about special capabilities | ||
| + | |||
| + | < | ||
| + | kgi_u32_t flags; | ||
| + | </ | ||
| + | |||
| + | * Size of the private mode data | ||
| + | |||
| + | < | ||
| + | kgi_u_t mode_size; | ||
| + | </ | ||
| + | |||
| + | * Current mode | ||
| + | |||
| + | < | ||
| + | kgi_mode_t *mode; | ||
| + | </ | ||
| + | |||
| + | * The display id | ||
| + | |||
| + | < | ||
| + | kgi_u_t id; | ||
| + | </ | ||
| + | |||
| + | * non-console device attached | ||
| + | |||
| + | < | ||
| + | kgi_u_t graphic; | ||
| + | </ | ||
| + | |||
| + | * Previous display in linked list | ||
| + | |||
| + | < | ||
| + | struct kgi_display_s *prev; | ||
| + | </ | ||
| + | |||
| + | * Device currently focused to the display | ||
| + | |||
| + | < | ||
| + | struct kgi_device_s *focus; | ||
| + | </ | ||
| + | |||
| + | The methods of a KGI display are: | ||
| + | |||
| + | < | ||
| + | kgi_display_refcount_fn *IncRefcount; | ||
| + | </ | ||
| + | |||
| + | < | ||
| + | kgi_display_refcount_fn *DecRefcount; | ||
| + | </ | ||
| + | |||
| + | < | ||
| + | kgi_display_check_mode_fn *CheckMode; | ||
| + | </ | ||
| + | |||
| + | < | ||
| + | kgi_display_set_mode_fn *SetMode; | ||
| + | </ | ||
| + | |||
| + | < | ||
| + | kgi_display_set_mode_fn *UnsetMode; | ||
| + | </ | ||
| + | |||
| + | < | ||
| + | kgi_display_command_fn *Command; | ||
| + | </ | ||
| + | |||
| + | kgi_register_display() | ||
| + | |||
| + | A display must register itself to offer its services to the [[/ | ||
| + | |||
| + | < | ||
| + | kgi_s_t kgi_register_display( | ||
| + | |||
| + | /* Comment: the preinitialized display to register */ | ||
| + | | ||
| + | |||
| + | /* Comment: the suggested id for the display */ | ||
| + | | ||
| + | ); | ||
| + | </ | ||
| + | |||
| + | A registration typically occur when loading a display module. The display must be initialized | ||
| + | before registration: | ||
| + | be described. | ||
| + | |||
| + | For example, for the %%FreeBSD%% native VESA display: | ||
| + | |||
| + | < | ||
| + | | ||
| + | snprintf(dpy-> | ||
| + | snprintf(dpy-> | ||
| + | </ | ||
| + | |||
| + | No specific flag and the display mode specific area is sizeof(vidsw_mode_t) long. | ||
| + | |||
| + | < | ||
| + | dpy-> | ||
| + | dpy-> | ||
| + | </ | ||
| + | |||
| + | with (dpm is mandatory here IIRC): | ||
| + | |||
| + | < | ||
| + | typedef struct vidsw_mode_s { | ||
| + | |||
| + | kgi_dot_port_mode_t dpm; | ||
| + | |||
| + | video_info_t mode_info; | ||
| + | video_info_t oldmode_info; | ||
| + | |||
| + | } vidsw_mode_t; | ||
| + | </ | ||
| + | |||
| + | The display methods are then initialized with yet not device focused: | ||
| + | |||
| + | < | ||
| + | mode = & | ||
| + | |||
| + | dpy-> | ||
| + | dpy->id = -1; | ||
| + | dpy-> | ||
| + | dpy-> | ||
| + | dpy-> | ||
| + | |||
| + | dpy-> | ||
| + | dpy-> | ||
| + | dpy-> | ||
| + | dpy-> | ||
| + | |||
| + | dpy-> | ||
| + | </ | ||
| + | |||
| + | < | ||
| + | mode-> | ||
| + | mode-> | ||
| + | mode-> | ||
| + | mode-> | ||
| + | mode-> | ||
| + | mode-> | ||
| + | mode-> | ||
| + | mode-> | ||
| + | mode-> | ||
| + | mode-> | ||
| + | mode-> | ||
| + | mode-> | ||
| + | mode-> | ||
| + | mode-> | ||
| + | mode-> | ||
| + | mode-> | ||
| + | </ | ||
| + | |||
| + | The framebuffer resource is described that way: | ||
| + | |||
| + | < | ||
| + | fb->meta = dpy; | ||
| + | fb->type = KGI_RT_MMIO_FRAME_BUFFER; | ||
| + | fb->prot = KGI_PF_APP_RWS | KGI_PF_LIB_RWS | KGI_PF_DRV_RWS; | ||
| + | fb->name = "Frame buffer"; | ||
| + | fb-> | ||
| + | fb-> | ||
| + | fb-> | ||
| + | fb-> | ||
| + | fb-> | ||
| + | fb-> | ||
| + | fb->size = (kgi_size_t)adp-> | ||
| + | fb-> | ||
| + | fb-> | ||
| + | </ | ||
| + | |||
| + | kgi_unregister_display() | ||
| + | |||
| + | < | ||
| + | void kgi_unregister_display( | ||
| + | |||
| + | /* Comment: the display to unregister */ | ||
| + | | ||
| + | ); | ||
| + | </ | ||
| + | |||
| + | kgi_display_registered() | ||
| + | |||
| + | kgi_display_registered shall be used to know if a display id is already bound | ||
| + | to a registered display. | ||
| + | |||
| + | < | ||
| + | kgi_s_t kgi_display_registered( | ||
| + | |||
| + | /* Comment: the display id */ | ||
| + | | ||
| + | ); | ||
| + | </ | ||
| + | |||
| + | Returns KGI_EOK if bound, KGI_ENODEV otherwise. | ||
| + | |||
| + | ==== KGIM API ==== | ||
| + | |||
| + | The %%KgimAPI%% is part of KGI but strictly speaking, it is a lower level API interfaced to KGI thanks to the [[/ | ||
| + | |||
| + | ==== KGI Mutex API ==== | ||
| + | |||
| + | kgi_mutex_t | ||
| + | |||
| + | The kgi_mutex_t is an opaque structure. One shall use it with the following methods and never | ||
| + | access it directly. It is OS specific and its content, its size may vary from one platform to | ||
| + | another. | ||
| + | |||
| + | kgi_mutex_alloc() | ||
| + | |||
| + | Allocate a mutex. mtx must be null. The return parameter is 0 (KGI_EOK) in case of success. | ||
| + | |||
| + | If the mutex has to be owned in the context of event synchronisation | ||
| + | mechanisms, the number of different events has to be specified, otherwise | ||
| + | KGI_MUTEX_NOEVENT shall be passed. Anyway nb_event can't exceed the maximum number KGI_MUTEX_MAXEVENT. | ||
| + | |||
| + | < | ||
| + | kgi_u_t kgi_mutex_alloc( | ||
| + | |||
| + | /* Comment: pointer to the mutex to initialize */ | ||
| + | | ||
| + | |||
| + | /* Comment: max number of events */ | ||
| + | | ||
| + | </ | ||
| + | |||
| + | kgi_mutex_free() | ||
| + | |||
| + | Free a mutex. The mutex must have be done before free. | ||
| + | mtx is null when returning from this function. Memory allocated | ||
| + | for event management is also freed. | ||
| + | |||
| + | < | ||
| + | void kgi_mutex_free( | ||
| + | |||
| + | /* Comment: pointer to the mutex to free */ | ||
| + | | ||
| + | ); | ||
| + | </ | ||
| + | |||
| + | kgi_mutex_init() | ||
| + | |||
| + | Initialize a pre-allocated mutex. The name passed is used for debug etc. | ||
| + | |||
| + | < | ||
| + | void kgi_mutex_init( | ||
| + | |||
| + | /* Comment: pointer to the mutex to initialize */ | ||
| + | | ||
| + | |||
| + | /* Comment: name of the mutex */ | ||
| + | const char *name | ||
| + | ); | ||
| + | </ | ||
| + | |||
| + | kgi_mutex_done() | ||
| + | |||
| + | Release a mutex. Memory allocated for the mutex itself is not freed. | ||
| + | |||
| + | < | ||
| + | void kgi_mutex_done( | ||
| + | |||
| + | /* Comment: pointer to the mutex to release */ | ||
| + | | ||
| + | ); | ||
| + | </ | ||
| + | |||
| + | kgi_mutex_lock() | ||
| + | |||
| + | Lock the mutex. If the mutex is not free, the thread is blocked. | ||
| + | |||
| + | < | ||
| + | void kgi_mutex_lock( | ||
| + | |||
| + | /* Comment: pointer to the mutex to lock */ | ||
| + | | ||
| + | ); | ||
| + | </ | ||
| + | |||
| + | kgi_mutex_unlock() | ||
| + | |||
| + | Unlock the mutex previously locked. | ||
| + | |||
| + | < | ||
| + | void kgi_mutex_unlock( | ||
| + | |||
| + | /* Comment: pointer to the mutex to unlock */ | ||
| + | | ||
| + | ); | ||
| + | </ | ||
| + | |||
| + | kgi_mutex_wait() | ||
| + | |||
| + | Wait on event e.g unlock the mutex and add the thread to the list of waiting | ||
| + | threads on this event. When the thread is made runnable again, it owns the mutex. | ||
| + | |||
| + | Important: the mutex must be already locked by the current running thread when calling | ||
| + | kgi_mutex_wait(). | ||
| + | |||
| + | Callers are responsible for managing the relationship between event ids and their | ||
| + | signification. the event parameter can't exceed nb_events passed when the mutex was | ||
| + | initialized. | ||
| + | |||
| + | < | ||
| + | void kgi_mutex_wait( | ||
| + | |||
| + | /* Comment: pointer to the mutex hold */ | ||
| + | | ||
| + | |||
| + | /* Comment: the event to wait on */ | ||
| + | | ||
| + | ); | ||
| + | </ | ||
| + | |||
| + | kgi_mutex_signal() | ||
| + | |||
| + | Wakeup threads waiting on an event to occur with mutex ownership. | ||
| + | If unblock_all is TRUE then unblock all waiters otherwise only one. | ||
| + | |||
| + | < | ||
| + | void kgi_mutex_signal( | ||
| + | |||
| + | /* Comment: pointer to the mutex processes are blocked on */ | ||
| + | | ||
| + | |||
| + | /* Comment: event to signal */ | ||
| + | | ||
| + | |||
| + | /* Comment: 1 = unblock all processes waiting on the mutex, 0 = unblock only the next one */ | ||
| + | int unblock_all | ||
| + | ); | ||
| + | </ | ||
| ---- | ---- | ||