brintos

brintos / linux-shallow public Read only

0
0
Text · 4.0 KiB · e3d909b Raw
179 lines · c
1// SPDX-License-Identifier: GPL-2.02#include <linux/errno.h>3#include <linux/miscdevice.h>	/* for misc_register, and MISC_DYNAMIC_MINOR */4#include <linux/types.h>5#include <linux/uaccess.h>6 7#include "speakup.h"8#include "spk_priv.h"9 10static int synth_registered, synthu_registered;11static int dev_opened;12 13/* Latin1 version */14static ssize_t speakup_file_write(struct file *fp, const char __user *buffer,15				  size_t nbytes, loff_t *ppos)16{17	size_t count = nbytes;18	const char __user *ptr = buffer;19	size_t bytes;20	unsigned long flags;21	u_char buf[256];22 23	if (!synth)24		return -ENODEV;25	while (count > 0) {26		bytes = min(count, sizeof(buf));27		if (copy_from_user(buf, ptr, bytes))28			return -EFAULT;29		count -= bytes;30		ptr += bytes;31		spin_lock_irqsave(&speakup_info.spinlock, flags);32		synth_write(buf, bytes);33		spin_unlock_irqrestore(&speakup_info.spinlock, flags);34	}35	return (ssize_t)nbytes;36}37 38/* UTF-8 version */39static 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, consumed, 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, 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 += consumed) {62			s32 value;63 64			value = synth_utf8_get(buf + in, bytes - in, &consumed, &want);65			if (value == -1) {66				/* Invalid or incomplete */67 68				if (want > bytes - in)69					/* We don't have it all yet, stop here70					 * and wait for the rest71					 */72					bytes = in;73 74				continue;75			}76 77			if (value < 0x10000)78				ubuf[out++] = value;79		}80 81		count -= bytes;82		ptr += bytes;83 84		/* And speak this up */85		if (out) {86			spin_lock_irqsave(&speakup_info.spinlock, flags);87			for (in = 0; in < out; in++)88				synth_buffer_add(ubuf[in]);89			synth_start();90			spin_unlock_irqrestore(&speakup_info.spinlock, flags);91		}92	}93 94	return (ssize_t)(nbytes - count);95}96 97static ssize_t speakup_file_read(struct file *fp, char __user *buf,98				 size_t nbytes, loff_t *ppos)99{100	return 0;101}102 103static int speakup_file_open(struct inode *ip, struct file *fp)104{105	if (!synth)106		return -ENODEV;107	if (xchg(&dev_opened, 1))108		return -EBUSY;109	return 0;110}111 112static int speakup_file_release(struct inode *ip, struct file *fp)113{114	dev_opened = 0;115	return 0;116}117 118static const struct file_operations synth_fops = {119	.read = speakup_file_read,120	.write = speakup_file_write,121	.open = speakup_file_open,122	.release = speakup_file_release,123};124 125static const struct file_operations synthu_fops = {126	.read = speakup_file_read,127	.write = speakup_file_writeu,128	.open = speakup_file_open,129	.release = speakup_file_release,130};131 132static struct miscdevice synth_device = {133	.minor = MISC_DYNAMIC_MINOR,134	.name = "synth",135	.fops = &synth_fops,136};137 138static struct miscdevice synthu_device = {139	.minor = MISC_DYNAMIC_MINOR,140	.name = "synthu",141	.fops = &synthu_fops,142};143 144void speakup_register_devsynth(void)145{146	if (!synth_registered) {147		if (misc_register(&synth_device)) {148			pr_warn("Couldn't initialize miscdevice /dev/synth.\n");149		} else {150			pr_info("initialized device: /dev/synth, node (MAJOR %d, MINOR %d)\n",151				MISC_MAJOR, synth_device.minor);152			synth_registered = 1;153		}154	}155	if (!synthu_registered) {156		if (misc_register(&synthu_device)) {157			pr_warn("Couldn't initialize miscdevice /dev/synthu.\n");158		} else {159			pr_info("initialized device: /dev/synthu, node (MAJOR %d, MINOR %d)\n",160				MISC_MAJOR, synthu_device.minor);161			synthu_registered = 1;162		}163	}164}165 166void speakup_unregister_devsynth(void)167{168	if (synth_registered) {169		pr_info("speakup: unregistering synth device /dev/synth\n");170		misc_deregister(&synth_device);171		synth_registered = 0;172	}173	if (synthu_registered) {174		pr_info("speakup: unregistering synth device /dev/synthu\n");175		misc_deregister(&synthu_device);176		synthu_registered = 0;177	}178}179