xref: /minix3/minix/lib/libinputdriver/inputdriver.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1*433d6423SLionel Sambuc /* This file contains the device independent input driver interface. */
2*433d6423SLionel Sambuc /*
3*433d6423SLionel Sambuc  * Changes:
4*433d6423SLionel Sambuc  *   Sep 22, 2013   created  (D.C. van Moolenbroek)
5*433d6423SLionel Sambuc  */
6*433d6423SLionel Sambuc 
7*433d6423SLionel Sambuc #include <minix/drivers.h>
8*433d6423SLionel Sambuc #include <minix/inputdriver.h>
9*433d6423SLionel Sambuc #include <minix/ds.h>
10*433d6423SLionel Sambuc 
11*433d6423SLionel Sambuc static endpoint_t input_endpt = NONE;
12*433d6423SLionel Sambuc static int kbd_id = INVALID_INPUT_ID;
13*433d6423SLionel Sambuc static int mouse_id = INVALID_INPUT_ID;
14*433d6423SLionel Sambuc 
15*433d6423SLionel Sambuc static int running;
16*433d6423SLionel Sambuc 
17*433d6423SLionel Sambuc /*
18*433d6423SLionel Sambuc  * Announce that we are up after a fresh start or restart.
19*433d6423SLionel Sambuc  */
20*433d6423SLionel Sambuc void
inputdriver_announce(unsigned int type)21*433d6423SLionel Sambuc inputdriver_announce(unsigned int type)
22*433d6423SLionel Sambuc {
23*433d6423SLionel Sambuc 	const char *driver_prefix = "drv.inp.";
24*433d6423SLionel Sambuc 	char key[DS_MAX_KEYLEN];
25*433d6423SLionel Sambuc 	char label[DS_MAX_KEYLEN];
26*433d6423SLionel Sambuc 	int r;
27*433d6423SLionel Sambuc 
28*433d6423SLionel Sambuc 	/* Publish a driver up event. */
29*433d6423SLionel Sambuc 	if ((r = ds_retrieve_label_name(label, sef_self())) != OK)
30*433d6423SLionel Sambuc 		panic("libinputdriver: unable to retrieve own label: %d", r);
31*433d6423SLionel Sambuc 
32*433d6423SLionel Sambuc 	snprintf(key, sizeof(key), "%s%s", driver_prefix, label);
33*433d6423SLionel Sambuc 	if ((r = ds_publish_u32(key, type, DSF_OVERWRITE)) != OK)
34*433d6423SLionel Sambuc 		panic("libinputdriver: unable to publish up event: %d", r);
35*433d6423SLionel Sambuc 
36*433d6423SLionel Sambuc 	/* Now we wait for the input server to contact us. */
37*433d6423SLionel Sambuc }
38*433d6423SLionel Sambuc 
39*433d6423SLionel Sambuc /*
40*433d6423SLionel Sambuc  * Send an event to the input server.
41*433d6423SLionel Sambuc  */
42*433d6423SLionel Sambuc void
inputdriver_send_event(int mouse,unsigned short page,unsigned short code,int value,int flags)43*433d6423SLionel Sambuc inputdriver_send_event(int mouse, unsigned short page, unsigned short code,
44*433d6423SLionel Sambuc 	int value, int flags)
45*433d6423SLionel Sambuc {
46*433d6423SLionel Sambuc 	message m;
47*433d6423SLionel Sambuc 	int id;
48*433d6423SLionel Sambuc 
49*433d6423SLionel Sambuc 	if (input_endpt == NONE)
50*433d6423SLionel Sambuc 		return;
51*433d6423SLionel Sambuc 
52*433d6423SLionel Sambuc 	id = mouse ? mouse_id : kbd_id;
53*433d6423SLionel Sambuc 	if (id == INVALID_INPUT_ID)
54*433d6423SLionel Sambuc 		return;
55*433d6423SLionel Sambuc 
56*433d6423SLionel Sambuc 	memset(&m, 0, sizeof(m));
57*433d6423SLionel Sambuc 
58*433d6423SLionel Sambuc 	m.m_type = INPUT_EVENT;
59*433d6423SLionel Sambuc 	m.m_linputdriver_input_event.id = id;
60*433d6423SLionel Sambuc 	m.m_linputdriver_input_event.page = page;
61*433d6423SLionel Sambuc 	m.m_linputdriver_input_event.code = code;
62*433d6423SLionel Sambuc 	m.m_linputdriver_input_event.value = value;
63*433d6423SLionel Sambuc 	m.m_linputdriver_input_event.flags = flags;
64*433d6423SLionel Sambuc 
65*433d6423SLionel Sambuc 	/*
66*433d6423SLionel Sambuc 	 * Use a blocking send call, for two reasons.  First, this avoids the
67*433d6423SLionel Sambuc 	 * situation that we ever end up queuing too many asynchronous messages
68*433d6423SLionel Sambuc 	 * to the input server.  Second, it allows us to detect trivially if
69*433d6423SLionel Sambuc 	 * the input server has crashed, in which case we should stop sending
70*433d6423SLionel Sambuc 	 * more messages to it.
71*433d6423SLionel Sambuc 	 */
72*433d6423SLionel Sambuc 	if (ipc_send(input_endpt, &m) != OK)
73*433d6423SLionel Sambuc 		input_endpt = NONE;
74*433d6423SLionel Sambuc }
75*433d6423SLionel Sambuc 
76*433d6423SLionel Sambuc /*
77*433d6423SLionel Sambuc  * The input server requests that we configure the driver.  This request should
78*433d6423SLionel Sambuc  * be sent to us once, although it may be sent multiple times if the input
79*433d6423SLionel Sambuc  * server crashes and recovers.  The configuration consists of device IDs for
80*433d6423SLionel Sambuc  * use in keyboard and/or mouse events, one per each device type.
81*433d6423SLionel Sambuc  */
82*433d6423SLionel Sambuc static void
do_conf(message * m_ptr)83*433d6423SLionel Sambuc do_conf(message *m_ptr)
84*433d6423SLionel Sambuc {
85*433d6423SLionel Sambuc 	endpoint_t ep;
86*433d6423SLionel Sambuc 	int r;
87*433d6423SLionel Sambuc 
88*433d6423SLionel Sambuc 	/* Make sure that the sender is actually the input server. */
89*433d6423SLionel Sambuc 	if ((r = ds_retrieve_label_endpt("input", &ep)) != OK) {
90*433d6423SLionel Sambuc 		printf("libinputdriver: unable to get input endpoint (%d)\n",
91*433d6423SLionel Sambuc 		    r);
92*433d6423SLionel Sambuc 
93*433d6423SLionel Sambuc 		return; /* ignore message */
94*433d6423SLionel Sambuc 	}
95*433d6423SLionel Sambuc 
96*433d6423SLionel Sambuc 	if (ep != m_ptr->m_source) {
97*433d6423SLionel Sambuc 		printf("libinputdriver: ignoring CONF request from %u\n",
98*433d6423SLionel Sambuc 		    m_ptr->m_source);
99*433d6423SLionel Sambuc 
100*433d6423SLionel Sambuc 		return;
101*433d6423SLionel Sambuc 	}
102*433d6423SLionel Sambuc 
103*433d6423SLionel Sambuc 	/* Save the new state. */
104*433d6423SLionel Sambuc 	input_endpt = m_ptr->m_source;
105*433d6423SLionel Sambuc 	kbd_id = m_ptr->m_input_linputdriver_input_conf.kbd_id;
106*433d6423SLionel Sambuc 	mouse_id = m_ptr->m_input_linputdriver_input_conf.mouse_id;
107*433d6423SLionel Sambuc 
108*433d6423SLionel Sambuc 	/* If the input server is "full" there's nothing for us to do. */
109*433d6423SLionel Sambuc 	if (kbd_id == INVALID_INPUT_ID && mouse_id == INVALID_INPUT_ID)
110*433d6423SLionel Sambuc 		printf("libinputdriver: no IDs given, driver disabled\n");
111*433d6423SLionel Sambuc }
112*433d6423SLionel Sambuc 
113*433d6423SLionel Sambuc /*
114*433d6423SLionel Sambuc  * The input server is telling us to change the LEDs to a particular mask.
115*433d6423SLionel Sambuc  * For now this is for keyboards only, so no device type is provided.
116*433d6423SLionel Sambuc  * This approach was chosen over sending toggle events for the individual LEDs
117*433d6423SLionel Sambuc  * for convenience reasons only.
118*433d6423SLionel Sambuc  */
119*433d6423SLionel Sambuc static void
do_setleds(struct inputdriver * idp,message * m_ptr)120*433d6423SLionel Sambuc do_setleds(struct inputdriver *idp, message *m_ptr)
121*433d6423SLionel Sambuc {
122*433d6423SLionel Sambuc 	unsigned int mask;
123*433d6423SLionel Sambuc 
124*433d6423SLionel Sambuc 	if (m_ptr->m_source != input_endpt) {
125*433d6423SLionel Sambuc 		printf("libinputdriver: ignoring SETLEDS request from %u\n",
126*433d6423SLionel Sambuc 			m_ptr->m_source);
127*433d6423SLionel Sambuc 
128*433d6423SLionel Sambuc 		return;
129*433d6423SLionel Sambuc 	}
130*433d6423SLionel Sambuc 
131*433d6423SLionel Sambuc 	mask = m_ptr->m_input_linputdriver_setleds.led_mask;
132*433d6423SLionel Sambuc 
133*433d6423SLionel Sambuc 	if (idp->idr_leds)
134*433d6423SLionel Sambuc 		idp->idr_leds(mask);
135*433d6423SLionel Sambuc }
136*433d6423SLionel Sambuc 
137*433d6423SLionel Sambuc /*
138*433d6423SLionel Sambuc  * Call the appropriate driver function, based on the type of message.
139*433d6423SLionel Sambuc  * All messages in the input protocol are one-way, so we never send a reply.
140*433d6423SLionel Sambuc  */
141*433d6423SLionel Sambuc void
inputdriver_process(struct inputdriver * idp,message * m_ptr,int ipc_status)142*433d6423SLionel Sambuc inputdriver_process(struct inputdriver *idp, message *m_ptr, int ipc_status)
143*433d6423SLionel Sambuc {
144*433d6423SLionel Sambuc 	/* Check for notifications first. */
145*433d6423SLionel Sambuc 	if (is_ipc_notify(ipc_status)) {
146*433d6423SLionel Sambuc 		switch (_ENDPOINT_P(m_ptr->m_source)) {
147*433d6423SLionel Sambuc 		case HARDWARE:
148*433d6423SLionel Sambuc 			if (idp->idr_intr)
149*433d6423SLionel Sambuc 				idp->idr_intr(m_ptr->m_notify.interrupts);
150*433d6423SLionel Sambuc 			break;
151*433d6423SLionel Sambuc 
152*433d6423SLionel Sambuc 		case CLOCK:
153*433d6423SLionel Sambuc 			if (idp->idr_alarm)
154*433d6423SLionel Sambuc 				idp->idr_alarm(m_ptr->m_notify.timestamp);
155*433d6423SLionel Sambuc 			break;
156*433d6423SLionel Sambuc 
157*433d6423SLionel Sambuc 		default:
158*433d6423SLionel Sambuc 			if (idp->idr_other)
159*433d6423SLionel Sambuc 				idp->idr_other(m_ptr, ipc_status);
160*433d6423SLionel Sambuc 		}
161*433d6423SLionel Sambuc 
162*433d6423SLionel Sambuc 		return;
163*433d6423SLionel Sambuc 	}
164*433d6423SLionel Sambuc 
165*433d6423SLionel Sambuc 	switch (m_ptr->m_type) {
166*433d6423SLionel Sambuc 	case INPUT_CONF:		do_conf(m_ptr);		break;
167*433d6423SLionel Sambuc 	case INPUT_SETLEDS:		do_setleds(idp, m_ptr);	break;
168*433d6423SLionel Sambuc 	default:
169*433d6423SLionel Sambuc 		if (idp->idr_other)
170*433d6423SLionel Sambuc 			idp->idr_other(m_ptr, ipc_status);
171*433d6423SLionel Sambuc 	}
172*433d6423SLionel Sambuc }
173*433d6423SLionel Sambuc 
174*433d6423SLionel Sambuc /*
175*433d6423SLionel Sambuc  * Break out of the main loop after finishing the current request.
176*433d6423SLionel Sambuc  */
177*433d6423SLionel Sambuc void
inputdriver_terminate(void)178*433d6423SLionel Sambuc inputdriver_terminate(void)
179*433d6423SLionel Sambuc {
180*433d6423SLionel Sambuc 	running = FALSE;
181*433d6423SLionel Sambuc 
182*433d6423SLionel Sambuc 	sef_cancel();
183*433d6423SLionel Sambuc }
184*433d6423SLionel Sambuc 
185*433d6423SLionel Sambuc /*
186*433d6423SLionel Sambuc  * Main program of any input driver task.
187*433d6423SLionel Sambuc  */
188*433d6423SLionel Sambuc void
inputdriver_task(struct inputdriver * idp)189*433d6423SLionel Sambuc inputdriver_task(struct inputdriver *idp)
190*433d6423SLionel Sambuc {
191*433d6423SLionel Sambuc 	message m;
192*433d6423SLionel Sambuc 	int r, ipc_status;
193*433d6423SLionel Sambuc 
194*433d6423SLionel Sambuc 	running = TRUE;
195*433d6423SLionel Sambuc 
196*433d6423SLionel Sambuc 	while (running) {
197*433d6423SLionel Sambuc 		if ((r = sef_receive_status(ANY, &m, &ipc_status)) != OK) {
198*433d6423SLionel Sambuc 			if (r == EINTR && !running)
199*433d6423SLionel Sambuc 				break;
200*433d6423SLionel Sambuc 
201*433d6423SLionel Sambuc 			panic("libinputdriver: receive failed: %d", r);
202*433d6423SLionel Sambuc 		}
203*433d6423SLionel Sambuc 
204*433d6423SLionel Sambuc 		inputdriver_process(idp, &m, ipc_status);
205*433d6423SLionel Sambuc 	}
206*433d6423SLionel Sambuc }
207