xref: /OK3568_Linux_fs/kernel/drivers/input/serio/serio_raw.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Raw serio device providing access to a raw byte stream from underlying
4*4882a593Smuzhiyun  * serio port. Closely emulates behavior of pre-2.6 /dev/psaux device
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Copyright (c) 2004 Dmitry Torokhov
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/kref.h>
10*4882a593Smuzhiyun #include <linux/sched.h>
11*4882a593Smuzhiyun #include <linux/slab.h>
12*4882a593Smuzhiyun #include <linux/poll.h>
13*4882a593Smuzhiyun #include <linux/module.h>
14*4882a593Smuzhiyun #include <linux/serio.h>
15*4882a593Smuzhiyun #include <linux/major.h>
16*4882a593Smuzhiyun #include <linux/device.h>
17*4882a593Smuzhiyun #include <linux/miscdevice.h>
18*4882a593Smuzhiyun #include <linux/wait.h>
19*4882a593Smuzhiyun #include <linux/mutex.h>
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun #define DRIVER_DESC	"Raw serio driver"
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
24*4882a593Smuzhiyun MODULE_DESCRIPTION(DRIVER_DESC);
25*4882a593Smuzhiyun MODULE_LICENSE("GPL");
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun #define SERIO_RAW_QUEUE_LEN	64
28*4882a593Smuzhiyun struct serio_raw {
29*4882a593Smuzhiyun 	unsigned char queue[SERIO_RAW_QUEUE_LEN];
30*4882a593Smuzhiyun 	unsigned int tail, head;
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun 	char name[16];
33*4882a593Smuzhiyun 	struct kref kref;
34*4882a593Smuzhiyun 	struct serio *serio;
35*4882a593Smuzhiyun 	struct miscdevice dev;
36*4882a593Smuzhiyun 	wait_queue_head_t wait;
37*4882a593Smuzhiyun 	struct list_head client_list;
38*4882a593Smuzhiyun 	struct list_head node;
39*4882a593Smuzhiyun 	bool dead;
40*4882a593Smuzhiyun };
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun struct serio_raw_client {
43*4882a593Smuzhiyun 	struct fasync_struct *fasync;
44*4882a593Smuzhiyun 	struct serio_raw *serio_raw;
45*4882a593Smuzhiyun 	struct list_head node;
46*4882a593Smuzhiyun };
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun static DEFINE_MUTEX(serio_raw_mutex);
49*4882a593Smuzhiyun static LIST_HEAD(serio_raw_list);
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun /*********************************************************************
52*4882a593Smuzhiyun  *             Interface with userspace (file operations)            *
53*4882a593Smuzhiyun  *********************************************************************/
54*4882a593Smuzhiyun 
serio_raw_fasync(int fd,struct file * file,int on)55*4882a593Smuzhiyun static int serio_raw_fasync(int fd, struct file *file, int on)
56*4882a593Smuzhiyun {
57*4882a593Smuzhiyun 	struct serio_raw_client *client = file->private_data;
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 	return fasync_helper(fd, file, on, &client->fasync);
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun 
serio_raw_locate(int minor)62*4882a593Smuzhiyun static struct serio_raw *serio_raw_locate(int minor)
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun 	struct serio_raw *serio_raw;
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	list_for_each_entry(serio_raw, &serio_raw_list, node) {
67*4882a593Smuzhiyun 		if (serio_raw->dev.minor == minor)
68*4882a593Smuzhiyun 			return serio_raw;
69*4882a593Smuzhiyun 	}
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 	return NULL;
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun 
serio_raw_open(struct inode * inode,struct file * file)74*4882a593Smuzhiyun static int serio_raw_open(struct inode *inode, struct file *file)
75*4882a593Smuzhiyun {
76*4882a593Smuzhiyun 	struct serio_raw *serio_raw;
77*4882a593Smuzhiyun 	struct serio_raw_client *client;
78*4882a593Smuzhiyun 	int retval;
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 	retval = mutex_lock_interruptible(&serio_raw_mutex);
81*4882a593Smuzhiyun 	if (retval)
82*4882a593Smuzhiyun 		return retval;
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	serio_raw = serio_raw_locate(iminor(inode));
85*4882a593Smuzhiyun 	if (!serio_raw) {
86*4882a593Smuzhiyun 		retval = -ENODEV;
87*4882a593Smuzhiyun 		goto out;
88*4882a593Smuzhiyun 	}
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	if (serio_raw->dead) {
91*4882a593Smuzhiyun 		retval = -ENODEV;
92*4882a593Smuzhiyun 		goto out;
93*4882a593Smuzhiyun 	}
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	client = kzalloc(sizeof(struct serio_raw_client), GFP_KERNEL);
96*4882a593Smuzhiyun 	if (!client) {
97*4882a593Smuzhiyun 		retval = -ENOMEM;
98*4882a593Smuzhiyun 		goto out;
99*4882a593Smuzhiyun 	}
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	client->serio_raw = serio_raw;
102*4882a593Smuzhiyun 	file->private_data = client;
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 	kref_get(&serio_raw->kref);
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 	serio_pause_rx(serio_raw->serio);
107*4882a593Smuzhiyun 	list_add_tail(&client->node, &serio_raw->client_list);
108*4882a593Smuzhiyun 	serio_continue_rx(serio_raw->serio);
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun out:
111*4882a593Smuzhiyun 	mutex_unlock(&serio_raw_mutex);
112*4882a593Smuzhiyun 	return retval;
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun 
serio_raw_free(struct kref * kref)115*4882a593Smuzhiyun static void serio_raw_free(struct kref *kref)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun 	struct serio_raw *serio_raw =
118*4882a593Smuzhiyun 			container_of(kref, struct serio_raw, kref);
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	put_device(&serio_raw->serio->dev);
121*4882a593Smuzhiyun 	kfree(serio_raw);
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun 
serio_raw_release(struct inode * inode,struct file * file)124*4882a593Smuzhiyun static int serio_raw_release(struct inode *inode, struct file *file)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun 	struct serio_raw_client *client = file->private_data;
127*4882a593Smuzhiyun 	struct serio_raw *serio_raw = client->serio_raw;
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 	serio_pause_rx(serio_raw->serio);
130*4882a593Smuzhiyun 	list_del(&client->node);
131*4882a593Smuzhiyun 	serio_continue_rx(serio_raw->serio);
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	kfree(client);
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	kref_put(&serio_raw->kref, serio_raw_free);
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun 	return 0;
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun 
serio_raw_fetch_byte(struct serio_raw * serio_raw,char * c)140*4882a593Smuzhiyun static bool serio_raw_fetch_byte(struct serio_raw *serio_raw, char *c)
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun 	bool empty;
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	serio_pause_rx(serio_raw->serio);
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	empty = serio_raw->head == serio_raw->tail;
147*4882a593Smuzhiyun 	if (!empty) {
148*4882a593Smuzhiyun 		*c = serio_raw->queue[serio_raw->tail];
149*4882a593Smuzhiyun 		serio_raw->tail = (serio_raw->tail + 1) % SERIO_RAW_QUEUE_LEN;
150*4882a593Smuzhiyun 	}
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	serio_continue_rx(serio_raw->serio);
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	return !empty;
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun 
serio_raw_read(struct file * file,char __user * buffer,size_t count,loff_t * ppos)157*4882a593Smuzhiyun static ssize_t serio_raw_read(struct file *file, char __user *buffer,
158*4882a593Smuzhiyun 			      size_t count, loff_t *ppos)
159*4882a593Smuzhiyun {
160*4882a593Smuzhiyun 	struct serio_raw_client *client = file->private_data;
161*4882a593Smuzhiyun 	struct serio_raw *serio_raw = client->serio_raw;
162*4882a593Smuzhiyun 	char c;
163*4882a593Smuzhiyun 	ssize_t read = 0;
164*4882a593Smuzhiyun 	int error;
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	for (;;) {
167*4882a593Smuzhiyun 		if (serio_raw->dead)
168*4882a593Smuzhiyun 			return -ENODEV;
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 		if (serio_raw->head == serio_raw->tail &&
171*4882a593Smuzhiyun 		    (file->f_flags & O_NONBLOCK))
172*4882a593Smuzhiyun 			return -EAGAIN;
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 		if (count == 0)
175*4882a593Smuzhiyun 			break;
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 		while (read < count && serio_raw_fetch_byte(serio_raw, &c)) {
178*4882a593Smuzhiyun 			if (put_user(c, buffer++))
179*4882a593Smuzhiyun 				return -EFAULT;
180*4882a593Smuzhiyun 			read++;
181*4882a593Smuzhiyun 		}
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 		if (read)
184*4882a593Smuzhiyun 			break;
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 		if (!(file->f_flags & O_NONBLOCK)) {
187*4882a593Smuzhiyun 			error = wait_event_interruptible(serio_raw->wait,
188*4882a593Smuzhiyun 					serio_raw->head != serio_raw->tail ||
189*4882a593Smuzhiyun 					serio_raw->dead);
190*4882a593Smuzhiyun 			if (error)
191*4882a593Smuzhiyun 				return error;
192*4882a593Smuzhiyun 		}
193*4882a593Smuzhiyun 	}
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	return read;
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun 
serio_raw_write(struct file * file,const char __user * buffer,size_t count,loff_t * ppos)198*4882a593Smuzhiyun static ssize_t serio_raw_write(struct file *file, const char __user *buffer,
199*4882a593Smuzhiyun 			       size_t count, loff_t *ppos)
200*4882a593Smuzhiyun {
201*4882a593Smuzhiyun 	struct serio_raw_client *client = file->private_data;
202*4882a593Smuzhiyun 	struct serio_raw *serio_raw = client->serio_raw;
203*4882a593Smuzhiyun 	int retval = 0;
204*4882a593Smuzhiyun 	unsigned char c;
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	retval = mutex_lock_interruptible(&serio_raw_mutex);
207*4882a593Smuzhiyun 	if (retval)
208*4882a593Smuzhiyun 		return retval;
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	if (serio_raw->dead) {
211*4882a593Smuzhiyun 		retval = -ENODEV;
212*4882a593Smuzhiyun 		goto out;
213*4882a593Smuzhiyun 	}
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	if (count > 32)
216*4882a593Smuzhiyun 		count = 32;
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	while (count--) {
219*4882a593Smuzhiyun 		if (get_user(c, buffer++)) {
220*4882a593Smuzhiyun 			retval = -EFAULT;
221*4882a593Smuzhiyun 			goto out;
222*4882a593Smuzhiyun 		}
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 		if (serio_write(serio_raw->serio, c)) {
225*4882a593Smuzhiyun 			/* Either signal error or partial write */
226*4882a593Smuzhiyun 			if (retval == 0)
227*4882a593Smuzhiyun 				retval = -EIO;
228*4882a593Smuzhiyun 			goto out;
229*4882a593Smuzhiyun 		}
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 		retval++;
232*4882a593Smuzhiyun 	}
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun out:
235*4882a593Smuzhiyun 	mutex_unlock(&serio_raw_mutex);
236*4882a593Smuzhiyun 	return retval;
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun 
serio_raw_poll(struct file * file,poll_table * wait)239*4882a593Smuzhiyun static __poll_t serio_raw_poll(struct file *file, poll_table *wait)
240*4882a593Smuzhiyun {
241*4882a593Smuzhiyun 	struct serio_raw_client *client = file->private_data;
242*4882a593Smuzhiyun 	struct serio_raw *serio_raw = client->serio_raw;
243*4882a593Smuzhiyun 	__poll_t mask;
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	poll_wait(file, &serio_raw->wait, wait);
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	mask = serio_raw->dead ? EPOLLHUP | EPOLLERR : EPOLLOUT | EPOLLWRNORM;
248*4882a593Smuzhiyun 	if (serio_raw->head != serio_raw->tail)
249*4882a593Smuzhiyun 		mask |= EPOLLIN | EPOLLRDNORM;
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	return mask;
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun static const struct file_operations serio_raw_fops = {
255*4882a593Smuzhiyun 	.owner		= THIS_MODULE,
256*4882a593Smuzhiyun 	.open		= serio_raw_open,
257*4882a593Smuzhiyun 	.release	= serio_raw_release,
258*4882a593Smuzhiyun 	.read		= serio_raw_read,
259*4882a593Smuzhiyun 	.write		= serio_raw_write,
260*4882a593Smuzhiyun 	.poll		= serio_raw_poll,
261*4882a593Smuzhiyun 	.fasync		= serio_raw_fasync,
262*4882a593Smuzhiyun 	.llseek		= noop_llseek,
263*4882a593Smuzhiyun };
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun /*********************************************************************
267*4882a593Smuzhiyun  *                   Interface with serio port                       *
268*4882a593Smuzhiyun  *********************************************************************/
269*4882a593Smuzhiyun 
serio_raw_interrupt(struct serio * serio,unsigned char data,unsigned int dfl)270*4882a593Smuzhiyun static irqreturn_t serio_raw_interrupt(struct serio *serio, unsigned char data,
271*4882a593Smuzhiyun 					unsigned int dfl)
272*4882a593Smuzhiyun {
273*4882a593Smuzhiyun 	struct serio_raw *serio_raw = serio_get_drvdata(serio);
274*4882a593Smuzhiyun 	struct serio_raw_client *client;
275*4882a593Smuzhiyun 	unsigned int head = serio_raw->head;
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	/* we are holding serio->lock here so we are protected */
278*4882a593Smuzhiyun 	serio_raw->queue[head] = data;
279*4882a593Smuzhiyun 	head = (head + 1) % SERIO_RAW_QUEUE_LEN;
280*4882a593Smuzhiyun 	if (likely(head != serio_raw->tail)) {
281*4882a593Smuzhiyun 		serio_raw->head = head;
282*4882a593Smuzhiyun 		list_for_each_entry(client, &serio_raw->client_list, node)
283*4882a593Smuzhiyun 			kill_fasync(&client->fasync, SIGIO, POLL_IN);
284*4882a593Smuzhiyun 		wake_up_interruptible(&serio_raw->wait);
285*4882a593Smuzhiyun 	}
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun 	return IRQ_HANDLED;
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun 
serio_raw_connect(struct serio * serio,struct serio_driver * drv)290*4882a593Smuzhiyun static int serio_raw_connect(struct serio *serio, struct serio_driver *drv)
291*4882a593Smuzhiyun {
292*4882a593Smuzhiyun 	static atomic_t serio_raw_no = ATOMIC_INIT(-1);
293*4882a593Smuzhiyun 	struct serio_raw *serio_raw;
294*4882a593Smuzhiyun 	int err;
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	serio_raw = kzalloc(sizeof(struct serio_raw), GFP_KERNEL);
297*4882a593Smuzhiyun 	if (!serio_raw) {
298*4882a593Smuzhiyun 		dev_dbg(&serio->dev, "can't allocate memory for a device\n");
299*4882a593Smuzhiyun 		return -ENOMEM;
300*4882a593Smuzhiyun 	}
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	snprintf(serio_raw->name, sizeof(serio_raw->name),
303*4882a593Smuzhiyun 		 "serio_raw%ld", (long)atomic_inc_return(&serio_raw_no));
304*4882a593Smuzhiyun 	kref_init(&serio_raw->kref);
305*4882a593Smuzhiyun 	INIT_LIST_HEAD(&serio_raw->client_list);
306*4882a593Smuzhiyun 	init_waitqueue_head(&serio_raw->wait);
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	serio_raw->serio = serio;
309*4882a593Smuzhiyun 	get_device(&serio->dev);
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	serio_set_drvdata(serio, serio_raw);
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	err = serio_open(serio, drv);
314*4882a593Smuzhiyun 	if (err)
315*4882a593Smuzhiyun 		goto err_free;
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	err = mutex_lock_killable(&serio_raw_mutex);
318*4882a593Smuzhiyun 	if (err)
319*4882a593Smuzhiyun 		goto err_close;
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 	list_add_tail(&serio_raw->node, &serio_raw_list);
322*4882a593Smuzhiyun 	mutex_unlock(&serio_raw_mutex);
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	serio_raw->dev.minor = PSMOUSE_MINOR;
325*4882a593Smuzhiyun 	serio_raw->dev.name = serio_raw->name;
326*4882a593Smuzhiyun 	serio_raw->dev.parent = &serio->dev;
327*4882a593Smuzhiyun 	serio_raw->dev.fops = &serio_raw_fops;
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	err = misc_register(&serio_raw->dev);
330*4882a593Smuzhiyun 	if (err) {
331*4882a593Smuzhiyun 		serio_raw->dev.minor = MISC_DYNAMIC_MINOR;
332*4882a593Smuzhiyun 		err = misc_register(&serio_raw->dev);
333*4882a593Smuzhiyun 	}
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	if (err) {
336*4882a593Smuzhiyun 		dev_err(&serio->dev,
337*4882a593Smuzhiyun 			"failed to register raw access device for %s\n",
338*4882a593Smuzhiyun 			serio->phys);
339*4882a593Smuzhiyun 		goto err_unlink;
340*4882a593Smuzhiyun 	}
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 	dev_info(&serio->dev, "raw access enabled on %s (%s, minor %d)\n",
343*4882a593Smuzhiyun 		 serio->phys, serio_raw->name, serio_raw->dev.minor);
344*4882a593Smuzhiyun 	return 0;
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun err_unlink:
347*4882a593Smuzhiyun 	list_del_init(&serio_raw->node);
348*4882a593Smuzhiyun err_close:
349*4882a593Smuzhiyun 	serio_close(serio);
350*4882a593Smuzhiyun err_free:
351*4882a593Smuzhiyun 	serio_set_drvdata(serio, NULL);
352*4882a593Smuzhiyun 	kref_put(&serio_raw->kref, serio_raw_free);
353*4882a593Smuzhiyun 	return err;
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun 
serio_raw_reconnect(struct serio * serio)356*4882a593Smuzhiyun static int serio_raw_reconnect(struct serio *serio)
357*4882a593Smuzhiyun {
358*4882a593Smuzhiyun 	struct serio_raw *serio_raw = serio_get_drvdata(serio);
359*4882a593Smuzhiyun 	struct serio_driver *drv = serio->drv;
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	if (!drv || !serio_raw) {
362*4882a593Smuzhiyun 		dev_dbg(&serio->dev,
363*4882a593Smuzhiyun 			"reconnect request, but serio is disconnected, ignoring...\n");
364*4882a593Smuzhiyun 		return -1;
365*4882a593Smuzhiyun 	}
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	/*
368*4882a593Smuzhiyun 	 * Nothing needs to be done here, we just need this method to
369*4882a593Smuzhiyun 	 * keep the same device.
370*4882a593Smuzhiyun 	 */
371*4882a593Smuzhiyun 	return 0;
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun /*
375*4882a593Smuzhiyun  * Wake up users waiting for IO so they can disconnect from
376*4882a593Smuzhiyun  * dead device.
377*4882a593Smuzhiyun  */
serio_raw_hangup(struct serio_raw * serio_raw)378*4882a593Smuzhiyun static void serio_raw_hangup(struct serio_raw *serio_raw)
379*4882a593Smuzhiyun {
380*4882a593Smuzhiyun 	struct serio_raw_client *client;
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 	serio_pause_rx(serio_raw->serio);
383*4882a593Smuzhiyun 	list_for_each_entry(client, &serio_raw->client_list, node)
384*4882a593Smuzhiyun 		kill_fasync(&client->fasync, SIGIO, POLL_HUP);
385*4882a593Smuzhiyun 	serio_continue_rx(serio_raw->serio);
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 	wake_up_interruptible(&serio_raw->wait);
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 
serio_raw_disconnect(struct serio * serio)391*4882a593Smuzhiyun static void serio_raw_disconnect(struct serio *serio)
392*4882a593Smuzhiyun {
393*4882a593Smuzhiyun 	struct serio_raw *serio_raw = serio_get_drvdata(serio);
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	misc_deregister(&serio_raw->dev);
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	mutex_lock(&serio_raw_mutex);
398*4882a593Smuzhiyun 	serio_raw->dead = true;
399*4882a593Smuzhiyun 	list_del_init(&serio_raw->node);
400*4882a593Smuzhiyun 	mutex_unlock(&serio_raw_mutex);
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 	serio_raw_hangup(serio_raw);
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	serio_close(serio);
405*4882a593Smuzhiyun 	kref_put(&serio_raw->kref, serio_raw_free);
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 	serio_set_drvdata(serio, NULL);
408*4882a593Smuzhiyun }
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun static const struct serio_device_id serio_raw_serio_ids[] = {
411*4882a593Smuzhiyun 	{
412*4882a593Smuzhiyun 		.type	= SERIO_8042,
413*4882a593Smuzhiyun 		.proto	= SERIO_ANY,
414*4882a593Smuzhiyun 		.id	= SERIO_ANY,
415*4882a593Smuzhiyun 		.extra	= SERIO_ANY,
416*4882a593Smuzhiyun 	},
417*4882a593Smuzhiyun 	{
418*4882a593Smuzhiyun 		.type	= SERIO_8042_XL,
419*4882a593Smuzhiyun 		.proto	= SERIO_ANY,
420*4882a593Smuzhiyun 		.id	= SERIO_ANY,
421*4882a593Smuzhiyun 		.extra	= SERIO_ANY,
422*4882a593Smuzhiyun 	},
423*4882a593Smuzhiyun 	{ 0 }
424*4882a593Smuzhiyun };
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun MODULE_DEVICE_TABLE(serio, serio_raw_serio_ids);
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun static struct serio_driver serio_raw_drv = {
429*4882a593Smuzhiyun 	.driver		= {
430*4882a593Smuzhiyun 		.name	= "serio_raw",
431*4882a593Smuzhiyun 	},
432*4882a593Smuzhiyun 	.description	= DRIVER_DESC,
433*4882a593Smuzhiyun 	.id_table	= serio_raw_serio_ids,
434*4882a593Smuzhiyun 	.interrupt	= serio_raw_interrupt,
435*4882a593Smuzhiyun 	.connect	= serio_raw_connect,
436*4882a593Smuzhiyun 	.reconnect	= serio_raw_reconnect,
437*4882a593Smuzhiyun 	.disconnect	= serio_raw_disconnect,
438*4882a593Smuzhiyun 	.manual_bind	= true,
439*4882a593Smuzhiyun };
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun module_serio_driver(serio_raw_drv);
442