1 #include <linux/errno.h>
2 #include <linux/miscdevice.h>	/* for misc_register, and SYNTH_MINOR */
3 #include <linux/types.h>
4 #include <linux/uaccess.h>
5 
6 #include "speakup.h"
7 #include "spk_priv.h"
8 
9 #ifndef SYNTH_MINOR
10 #define SYNTH_MINOR 25
11 #endif
12 
13 static int misc_registered;
14 static int dev_opened;
15 
speakup_file_write(struct file * fp,const char * buffer,size_t nbytes,loff_t * ppos)16 static ssize_t speakup_file_write(struct file *fp, const char *buffer,
17 		   size_t nbytes, loff_t *ppos)
18 {
19 	size_t count = nbytes;
20 	const char *ptr = buffer;
21 	size_t bytes;
22 	unsigned long flags;
23 	u_char buf[256];
24 
25 	if (synth == NULL)
26 		return -ENODEV;
27 	while (count > 0) {
28 		bytes = min(count, sizeof(buf));
29 		if (copy_from_user(buf, ptr, bytes))
30 			return -EFAULT;
31 		count -= bytes;
32 		ptr += bytes;
33 		spk_lock(flags);
34 		synth_write(buf, bytes);
35 		spk_unlock(flags);
36 	}
37 	return (ssize_t) nbytes;
38 }
39 
speakup_file_read(struct file * fp,char * buf,size_t nbytes,loff_t * ppos)40 static ssize_t speakup_file_read(struct file *fp, char *buf, size_t nbytes,
41 	loff_t *ppos)
42 {
43 	return 0;
44 }
45 
speakup_file_open(struct inode * ip,struct file * fp)46 static int speakup_file_open(struct inode *ip, struct file *fp)
47 {
48 	if (synth == NULL)
49 		return -ENODEV;
50 	if (xchg(&dev_opened, 1))
51 		return -EBUSY;
52 	return 0;
53 }
54 
speakup_file_release(struct inode * ip,struct file * fp)55 static int speakup_file_release(struct inode *ip, struct file *fp)
56 {
57 	dev_opened = 0;
58 	return 0;
59 }
60 
61 static const struct file_operations synth_fops = {
62 	.read = speakup_file_read,
63 	.write = speakup_file_write,
64 	.open = speakup_file_open,
65 	.release = speakup_file_release,
66 };
67 
68 static struct miscdevice synth_device = {
69 	.minor = SYNTH_MINOR,
70 	.name = "synth",
71 	.fops = &synth_fops,
72 };
73 
speakup_register_devsynth(void)74 void speakup_register_devsynth(void)
75 {
76 	if (misc_registered != 0)
77 		return;
78 /* zero it so if register fails, deregister will not ref invalid ptrs */
79 	if (misc_register(&synth_device))
80 		pr_warn("Couldn't initialize miscdevice /dev/synth.\n");
81 	else {
82 		pr_info("initialized device: /dev/synth, node (MAJOR %d, MINOR %d)\n",
83 			MISC_MAJOR, SYNTH_MINOR);
84 		misc_registered = 1;
85 	}
86 }
87 
speakup_unregister_devsynth(void)88 void speakup_unregister_devsynth(void)
89 {
90 	if (!misc_registered)
91 		return;
92 	pr_info("speakup: unregistering synth device /dev/synth\n");
93 	misc_deregister(&synth_device);
94 	misc_registered = 0;
95 }
96