devsynth.c 2.1 KB

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