77#include "speakup.h"
88#include "spk_priv.h"
99
10- static int misc_registered ;
10+ static int synth_registered , synthu_registered ;
1111static int dev_opened ;
1212
13+ /* Latin1 version */
1314static ssize_t speakup_file_write (struct file * fp , const char __user * buffer ,
1415 size_t nbytes , loff_t * ppos )
1516{
@@ -34,6 +35,97 @@ static ssize_t speakup_file_write(struct file *fp, const char __user *buffer,
3435 return (ssize_t )nbytes ;
3536}
3637
38+ /* UTF-8 version */
39+ static ssize_t speakup_file_writeu (struct file * fp , const char __user * buffer ,
40+ size_t nbytes , loff_t * ppos )
41+ {
42+ size_t count = nbytes , want ;
43+ const char __user * ptr = buffer ;
44+ size_t bytes ;
45+ unsigned long flags ;
46+ unsigned char buf [256 ];
47+ u16 ubuf [256 ];
48+ size_t in , in2 , out ;
49+
50+ if (!synth )
51+ return - ENODEV ;
52+
53+ want = 1 ;
54+ while (count >= want ) {
55+ /* Copy some UTF-8 piece from userland */
56+ bytes = min (count , sizeof (buf ));
57+ if (copy_from_user (buf , ptr , bytes ))
58+ return - EFAULT ;
59+
60+ /* Convert to u16 */
61+ for (in = 0 , out = 0 ; in < bytes ; in ++ ) {
62+ unsigned char c = buf [in ];
63+ int nbytes = 8 - fls (c ^ 0xff );
64+ u32 value ;
65+
66+ switch (nbytes ) {
67+ case 8 : /* 0xff */
68+ case 7 : /* 0xfe */
69+ case 1 : /* 0x80 */
70+ /* Invalid, drop */
71+ goto drop ;
72+
73+ case 0 :
74+ /* ASCII, copy */
75+ ubuf [out ++ ] = c ;
76+ continue ;
77+
78+ default :
79+ /* 2..6-byte UTF-8 */
80+
81+ if (bytes - in < nbytes ) {
82+ /* We don't have it all yet, stop here
83+ * and wait for the rest
84+ */
85+ bytes = in ;
86+ want = nbytes ;
87+ continue ;
88+ }
89+
90+ /* First byte */
91+ value = c & ((1u << (7 - nbytes )) - 1 );
92+
93+ /* Other bytes */
94+ for (in2 = 2 ; in2 <= nbytes ; in2 ++ ) {
95+ c = buf [in + 1 ];
96+ if ((c & 0xc0 ) != 0x80 ) {
97+ /* Invalid, drop the head */
98+ want = 1 ;
99+ goto drop ;
100+ }
101+ value = (value << 6 ) | (c & 0x3f );
102+ in ++ ;
103+ }
104+
105+ if (value < 0x10000 )
106+ ubuf [out ++ ] = value ;
107+ want = 1 ;
108+ break ;
109+ }
110+ drop :
111+ }
112+
113+ count -= bytes ;
114+ ptr += bytes ;
115+
116+ /* And speak this up */
117+ if (out ) {
118+ spin_lock_irqsave (& speakup_info .spinlock , flags );
119+ for (in = 0 ; in < out ; in ++ )
120+ synth_buffer_add (ubuf [in ]);
121+ synth_start ();
122+ spin_unlock_irqrestore (& speakup_info .spinlock , flags );
123+ }
124+ }
125+
126+ return (ssize_t )(nbytes - count );
127+ }
128+
37129static ssize_t speakup_file_read (struct file * fp , char __user * buf ,
38130 size_t nbytes , loff_t * ppos )
39131{
@@ -62,31 +154,57 @@ static const struct file_operations synth_fops = {
62154 .release = speakup_file_release ,
63155};
64156
157+ static const struct file_operations synthu_fops = {
158+ .read = speakup_file_read ,
159+ .write = speakup_file_writeu ,
160+ .open = speakup_file_open ,
161+ .release = speakup_file_release ,
162+ };
163+
65164static struct miscdevice synth_device = {
66165 .minor = MISC_DYNAMIC_MINOR ,
67166 .name = "synth" ,
68167 .fops = & synth_fops ,
69168};
70169
170+ static struct miscdevice synthu_device = {
171+ .minor = MISC_DYNAMIC_MINOR ,
172+ .name = "synthu" ,
173+ .fops = & synthu_fops ,
174+ };
175+
71176void speakup_register_devsynth (void )
72177{
73- if (misc_registered != 0 )
74- return ;
75- /* zero it so if register fails, deregister will not ref invalid ptrs */
76- if (misc_register (& synth_device )) {
77- pr_warn ("Couldn't initialize miscdevice /dev/synth.\n" );
78- } else {
79- pr_info ("initialized device: /dev/synth, node (MAJOR %d, MINOR %d)\n" ,
80- MISC_MAJOR , synth_device .minor );
81- misc_registered = 1 ;
178+ if (!synth_registered ) {
179+ if (misc_register (& synth_device )) {
180+ pr_warn ("Couldn't initialize miscdevice /dev/synth.\n" );
181+ } else {
182+ pr_info ("initialized device: /dev/synth, node (MAJOR %d, MINOR %d)\n" ,
183+ MISC_MAJOR , synth_device .minor );
184+ synth_registered = 1 ;
185+ }
186+ }
187+ if (!synthu_registered ) {
188+ if (misc_register (& synthu_device )) {
189+ pr_warn ("Couldn't initialize miscdevice /dev/synthu.\n" );
190+ } else {
191+ pr_info ("initialized device: /dev/synthu, node (MAJOR %d, MINOR %d)\n" ,
192+ MISC_MAJOR , synthu_device .minor );
193+ synthu_registered = 1 ;
194+ }
82195 }
83196}
84197
85198void speakup_unregister_devsynth (void )
86199{
87- if (!misc_registered )
88- return ;
89- pr_info ("speakup: unregistering synth device /dev/synth\n" );
90- misc_deregister (& synth_device );
91- misc_registered = 0 ;
200+ if (synth_registered ) {
201+ pr_info ("speakup: unregistering synth device /dev/synth\n" );
202+ misc_deregister (& synth_device );
203+ synth_registered = 0 ;
204+ }
205+ if (synthu_registered ) {
206+ pr_info ("speakup: unregistering synth device /dev/synthu\n" );
207+ misc_deregister (& synthu_device );
208+ synthu_registered = 0 ;
209+ }
92210}
0 commit comments