18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <linux/errno.h> 38c2ecf20Sopenharmony_ci#include <linux/miscdevice.h> /* for misc_register, and MISC_DYNAMIC_MINOR */ 48c2ecf20Sopenharmony_ci#include <linux/types.h> 58c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include "speakup.h" 88c2ecf20Sopenharmony_ci#include "spk_priv.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_cistatic int misc_registered; 118c2ecf20Sopenharmony_cistatic int dev_opened; 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_cistatic ssize_t speakup_file_write(struct file *fp, const char __user *buffer, 148c2ecf20Sopenharmony_ci size_t nbytes, loff_t *ppos) 158c2ecf20Sopenharmony_ci{ 168c2ecf20Sopenharmony_ci size_t count = nbytes; 178c2ecf20Sopenharmony_ci const char __user *ptr = buffer; 188c2ecf20Sopenharmony_ci size_t bytes; 198c2ecf20Sopenharmony_ci unsigned long flags; 208c2ecf20Sopenharmony_ci u_char buf[256]; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci if (!synth) 238c2ecf20Sopenharmony_ci return -ENODEV; 248c2ecf20Sopenharmony_ci while (count > 0) { 258c2ecf20Sopenharmony_ci bytes = min(count, sizeof(buf)); 268c2ecf20Sopenharmony_ci if (copy_from_user(buf, ptr, bytes)) 278c2ecf20Sopenharmony_ci return -EFAULT; 288c2ecf20Sopenharmony_ci count -= bytes; 298c2ecf20Sopenharmony_ci ptr += bytes; 308c2ecf20Sopenharmony_ci spin_lock_irqsave(&speakup_info.spinlock, flags); 318c2ecf20Sopenharmony_ci synth_write(buf, bytes); 328c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&speakup_info.spinlock, flags); 338c2ecf20Sopenharmony_ci } 348c2ecf20Sopenharmony_ci return (ssize_t)nbytes; 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic ssize_t speakup_file_read(struct file *fp, char __user *buf, 388c2ecf20Sopenharmony_ci size_t nbytes, loff_t *ppos) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci return 0; 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic int speakup_file_open(struct inode *ip, struct file *fp) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci if (!synth) 468c2ecf20Sopenharmony_ci return -ENODEV; 478c2ecf20Sopenharmony_ci if (xchg(&dev_opened, 1)) 488c2ecf20Sopenharmony_ci return -EBUSY; 498c2ecf20Sopenharmony_ci return 0; 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic int speakup_file_release(struct inode *ip, struct file *fp) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci dev_opened = 0; 558c2ecf20Sopenharmony_ci return 0; 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic const struct file_operations synth_fops = { 598c2ecf20Sopenharmony_ci .read = speakup_file_read, 608c2ecf20Sopenharmony_ci .write = speakup_file_write, 618c2ecf20Sopenharmony_ci .open = speakup_file_open, 628c2ecf20Sopenharmony_ci .release = speakup_file_release, 638c2ecf20Sopenharmony_ci}; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic struct miscdevice synth_device = { 668c2ecf20Sopenharmony_ci .minor = MISC_DYNAMIC_MINOR, 678c2ecf20Sopenharmony_ci .name = "synth", 688c2ecf20Sopenharmony_ci .fops = &synth_fops, 698c2ecf20Sopenharmony_ci}; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_civoid speakup_register_devsynth(void) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci if (misc_registered != 0) 748c2ecf20Sopenharmony_ci return; 758c2ecf20Sopenharmony_ci/* zero it so if register fails, deregister will not ref invalid ptrs */ 768c2ecf20Sopenharmony_ci if (misc_register(&synth_device)) { 778c2ecf20Sopenharmony_ci pr_warn("Couldn't initialize miscdevice /dev/synth.\n"); 788c2ecf20Sopenharmony_ci } else { 798c2ecf20Sopenharmony_ci pr_info("initialized device: /dev/synth, node (MAJOR %d, MINOR %d)\n", 808c2ecf20Sopenharmony_ci MISC_MAJOR, synth_device.minor); 818c2ecf20Sopenharmony_ci misc_registered = 1; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_civoid speakup_unregister_devsynth(void) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci if (!misc_registered) 888c2ecf20Sopenharmony_ci return; 898c2ecf20Sopenharmony_ci pr_info("speakup: unregistering synth device /dev/synth\n"); 908c2ecf20Sopenharmony_ci misc_deregister(&synth_device); 918c2ecf20Sopenharmony_ci misc_registered = 0; 928c2ecf20Sopenharmony_ci} 93