table des matières
Troisièmement, le processus de réalisation
1. Signal
Examinons d'abord "l'interruption". L'interruption est un mécanisme asynchrone fourni par le processeur. Après avoir configuré l'interruption, nous pouvons laisser le processeur gérer d'autres choses. Lorsque l'interruption se produit, elle déclenchera la fonction de service d'interruption que nous avons définie à l'avance. , Effectuez un traitement spécifique dans la fonction de service d'interruption. Une fois l'interruption utilisée, le processeur n'a pas besoin de vérifier si le bouton est enfoncé à tout moment, car l'interruption sera automatiquement déclenchée après avoir appuyé sur le bouton.
De même, les applications Linux peuvent accéder au périphérique d'entraînement de deux manières: bloquante ou non bloquante
- En mode de blocage, l'application sera dans un état dormant, en attendant que le périphérique d'entraînement soit disponible
- En mode non bloquant, il interrogera en permanence la fonction d'interrogation pour vérifier si le fichier de périphérique du lecteur peut être utilisé
Le signal est similaire à "l'interruption" utilisée sur notre matériel, mais le signal est au niveau logiciel. Il peut être considéré comme une simulation d'interruption au niveau du logiciel. Le pilote peut signaler qu'il est accessible en envoyant activement un signal au programme d'application. Une fois que le programme d'application a obtenu le signal, il peut lire ou écrire des données à partir du dispositif d'entraînement . L'ensemble du processus équivaut au fait que le programme d'application reçoit une interruption envoyée par le pilote, puis le programme d'application répond à l'interruption. Pendant tout le processus, le programme d'application ne demande pas si le lecteur est accessible, tout est dit par le lecteur lui-même Pour l'application.
Le cœur de la notification asynchrone est le signal. Tous les signaux pris en charge par Linux sont définis dans le fichier arch / xtensa / include / uapi / asm / signal.h . Ces signaux sont les suivants:
#define SIGHUP 1
#define SIGINT 2
#define SIGQUIT 3
#define SIGILL 4
#define SIGTRAP 5
#define SIGABRT 6
#define SIGIOT 6
#define SIGBUS 7
#define SIGFPE 8
#define SIGKILL 9
#define SIGUSR1 10
#define SIGSEGV 11
#define SIGUSR2 12
#define SIGPIPE 13
#define SIGALRM 14
#define SIGTERM 15
#define SIGSTKFLT 16
#define SIGCHLD 17
#define SIGCONT 18
#define SIGSTOP 19
#define SIGTSTP 20
#define SIGTTIN 21
#define SIGTTOU 22
#define SIGURG 23
#define SIGXCPU 24
#define SIGXFSZ 25
#define SIGVTALRM 26
#define SIGPROF 27
#define SIGWINCH 28
#define SIGIO 29
#define SIGPOLL SIGIO
/*
#define SIGLOST 29
*/
#define SIGPWR 30
#define SIGSYS 31
#define SIGUNUSED 31
/* These should not be considered constants from userland. */
#define SIGRTMIN 32
#define SIGRTMAX _NSIG
#define SIGSWI 32
Deuxièmement, la connexion et la différence entre les E / S synchrones, les E / S asynchrones, les E / S bloquantes et les E / S non bloquantes
https://www.cnblogs.com/euphie/p/6376508.html
Troisièmement, le processus de réalisation
Code source complet du pilote: https://github.com/denghengli/linux_driver/tree/master/17_fasync
1. Application
Pour utiliser la notification asynchrone dans votre application, vous devez ajouter du contenu:
(1) Enregistrer une nouvelle fonction de traitement des nombres
(2) Indiquez au noyau le numéro de processus de cette application
(3) Activer la notification asynchrone
static void sigio_signal_func(int signum)
{
...
}
/*
*argc 应用程序参数个数
*argv 具体的参数内容,字符串形式
*/
int main(int argc, char *argv[])
{
...
signal(SIGIO, sigio_signal_func);/*设置sigio的处理函数*/
/*int fcntl (int __fd, int __cmd, ...);*/
fcntl(fd, F_SETOWN, getpid());/*设置当前进程接收SIGIO信号*/
flags = fcntl(fd, F_GETFL);/*获取当前文件标志*/
fcntl(fd, F_SETFL, flags | FASYNC);/*设置当前文件标志,开启异步通知*/
...
return 0;
}
2. Pilote
(1) Lorsque le périphérique est accessible, le pilote doit envoyer un signal à l'application via la fonction kill_fasync , ce qui équivaut à générer une "interruption"
void kill_fasync (struct fasync_struct ** fp, int sig, bande int)
fp : La fasync_struct à utiliser.
sig le signal à envoyer.
Défini sur POLL_IN lorsque la bande est lisible et POLL_OUT lorsqu'elle peut être écrite.
Valeur de retour : aucune.
(2) Ecrivez la fonction fasync. Lorsque l'application change l'indicateur fasync via fcntl (fd, F_SETFL, flags | FASYNC) , la fonction fasync du jeu d'opérations file_operations du pilote sera exécutée et la structure de contrôle fasync doit être initialisée dans cette fonction
/* key设备结构体 */
struct key_dev{
...
/*异步结构体 --- 异步通知*/
struct fasync_struct *fasync_queue;
};
/*定时器回调函数*/
static void timer_func(unsigned long arg)
{
struct key_dev *dev = (struct key_dev*)arg;
...
if (dev->fasync_queue){ /*有效的按键过程,相应层发送信号实现异步通知*/
/*SIFIO为发送的信号,POLL_IO表示可读,POLL_OUT表示可写*/
kill_fasync(&dev->fasync_queue, SIGIO, POLL_IN);
}
}
}
static int key_release(struct inode *inode, struct file *filp)
{
int i = 0;
struct key_dev *dev = filp->private_data;
...
/*删除fasync结构体*/
return fasync_helper(-1, filp, 0, &dev->fasync_queue);
}
static int key_fasync(int fd, struct file *filp, int on)
{
struct key_dev *dev = filp->private_data;
/*初始化fasync结构体*/
return fasync_helper(fd, filp, on, &dev->fasync_queue);
}
/* 设备操作函数 */
static struct file_operations key_fops = {
...
.fasync = key_fasync,
};