fireworks_hwdep.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. /*
  2. * fireworks_hwdep.c - a part of driver for Fireworks based devices
  3. *
  4. * Copyright (c) 2013-2014 Takashi Sakamoto
  5. *
  6. * Licensed under the terms of the GNU General Public License, version 2.
  7. */
  8. /*
  9. * This codes have five functionalities.
  10. *
  11. * 1.get information about firewire node
  12. * 2.get notification about starting/stopping stream
  13. * 3.lock/unlock streaming
  14. * 4.transmit command of EFW transaction
  15. * 5.receive response of EFW transaction
  16. *
  17. */
  18. #include "fireworks.h"
  19. static long
  20. hwdep_read_resp_buf(struct snd_efw *efw, char __user *buf, long remained,
  21. loff_t *offset)
  22. {
  23. unsigned int length, till_end, type;
  24. struct snd_efw_transaction *t;
  25. long count = 0;
  26. if (remained < sizeof(type) + sizeof(struct snd_efw_transaction))
  27. return -ENOSPC;
  28. /* data type is SNDRV_FIREWIRE_EVENT_EFW_RESPONSE */
  29. type = SNDRV_FIREWIRE_EVENT_EFW_RESPONSE;
  30. if (copy_to_user(buf, &type, sizeof(type)))
  31. return -EFAULT;
  32. remained -= sizeof(type);
  33. buf += sizeof(type);
  34. /* write into buffer as many responses as possible */
  35. while (efw->resp_queues > 0) {
  36. t = (struct snd_efw_transaction *)(efw->pull_ptr);
  37. length = be32_to_cpu(t->length) * sizeof(__be32);
  38. /* confirm enough space for this response */
  39. if (remained < length)
  40. break;
  41. /* copy from ring buffer to user buffer */
  42. while (length > 0) {
  43. till_end = snd_efw_resp_buf_size -
  44. (unsigned int)(efw->pull_ptr - efw->resp_buf);
  45. till_end = min_t(unsigned int, length, till_end);
  46. if (copy_to_user(buf, efw->pull_ptr, till_end))
  47. return -EFAULT;
  48. efw->pull_ptr += till_end;
  49. if (efw->pull_ptr >= efw->resp_buf +
  50. snd_efw_resp_buf_size)
  51. efw->pull_ptr -= snd_efw_resp_buf_size;
  52. length -= till_end;
  53. buf += till_end;
  54. count += till_end;
  55. remained -= till_end;
  56. }
  57. efw->resp_queues--;
  58. }
  59. return count;
  60. }
  61. static long
  62. hwdep_read_locked(struct snd_efw *efw, char __user *buf, long count,
  63. loff_t *offset)
  64. {
  65. union snd_firewire_event event;
  66. memset(&event, 0, sizeof(event));
  67. event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
  68. event.lock_status.status = (efw->dev_lock_count > 0);
  69. efw->dev_lock_changed = false;
  70. count = min_t(long, count, sizeof(event.lock_status));
  71. if (copy_to_user(buf, &event, count))
  72. return -EFAULT;
  73. return count;
  74. }
  75. static long
  76. hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
  77. loff_t *offset)
  78. {
  79. struct snd_efw *efw = hwdep->private_data;
  80. DEFINE_WAIT(wait);
  81. spin_lock_irq(&efw->lock);
  82. while ((!efw->dev_lock_changed) && (efw->resp_queues == 0)) {
  83. prepare_to_wait(&efw->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
  84. spin_unlock_irq(&efw->lock);
  85. schedule();
  86. finish_wait(&efw->hwdep_wait, &wait);
  87. if (signal_pending(current))
  88. return -ERESTARTSYS;
  89. spin_lock_irq(&efw->lock);
  90. }
  91. if (efw->dev_lock_changed)
  92. count = hwdep_read_locked(efw, buf, count, offset);
  93. else if (efw->resp_queues > 0)
  94. count = hwdep_read_resp_buf(efw, buf, count, offset);
  95. spin_unlock_irq(&efw->lock);
  96. return count;
  97. }
  98. static long
  99. hwdep_write(struct snd_hwdep *hwdep, const char __user *data, long count,
  100. loff_t *offset)
  101. {
  102. struct snd_efw *efw = hwdep->private_data;
  103. u32 seqnum;
  104. u8 *buf;
  105. if (count < sizeof(struct snd_efw_transaction) ||
  106. SND_EFW_RESPONSE_MAXIMUM_BYTES < count)
  107. return -EINVAL;
  108. buf = memdup_user(data, count);
  109. if (IS_ERR(buf))
  110. return PTR_ERR(buf);
  111. /* check seqnum is not for kernel-land */
  112. seqnum = be32_to_cpu(((struct snd_efw_transaction *)buf)->seqnum);
  113. if (seqnum > SND_EFW_TRANSACTION_USER_SEQNUM_MAX) {
  114. count = -EINVAL;
  115. goto end;
  116. }
  117. if (snd_efw_transaction_cmd(efw->unit, buf, count) < 0)
  118. count = -EIO;
  119. end:
  120. kfree(buf);
  121. return count;
  122. }
  123. static unsigned int
  124. hwdep_poll(struct snd_hwdep *hwdep, struct file *file, poll_table *wait)
  125. {
  126. struct snd_efw *efw = hwdep->private_data;
  127. unsigned int events;
  128. poll_wait(file, &efw->hwdep_wait, wait);
  129. spin_lock_irq(&efw->lock);
  130. if (efw->dev_lock_changed || (efw->resp_queues > 0))
  131. events = POLLIN | POLLRDNORM;
  132. else
  133. events = 0;
  134. spin_unlock_irq(&efw->lock);
  135. return events | POLLOUT;
  136. }
  137. static int
  138. hwdep_get_info(struct snd_efw *efw, void __user *arg)
  139. {
  140. struct fw_device *dev = fw_parent_device(efw->unit);
  141. struct snd_firewire_get_info info;
  142. memset(&info, 0, sizeof(info));
  143. info.type = SNDRV_FIREWIRE_TYPE_FIREWORKS;
  144. info.card = dev->card->index;
  145. *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
  146. *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
  147. strlcpy(info.device_name, dev_name(&dev->device),
  148. sizeof(info.device_name));
  149. if (copy_to_user(arg, &info, sizeof(info)))
  150. return -EFAULT;
  151. return 0;
  152. }
  153. static int
  154. hwdep_lock(struct snd_efw *efw)
  155. {
  156. int err;
  157. spin_lock_irq(&efw->lock);
  158. if (efw->dev_lock_count == 0) {
  159. efw->dev_lock_count = -1;
  160. err = 0;
  161. } else {
  162. err = -EBUSY;
  163. }
  164. spin_unlock_irq(&efw->lock);
  165. return err;
  166. }
  167. static int
  168. hwdep_unlock(struct snd_efw *efw)
  169. {
  170. int err;
  171. spin_lock_irq(&efw->lock);
  172. if (efw->dev_lock_count == -1) {
  173. efw->dev_lock_count = 0;
  174. err = 0;
  175. } else {
  176. err = -EBADFD;
  177. }
  178. spin_unlock_irq(&efw->lock);
  179. return err;
  180. }
  181. static int
  182. hwdep_release(struct snd_hwdep *hwdep, struct file *file)
  183. {
  184. struct snd_efw *efw = hwdep->private_data;
  185. spin_lock_irq(&efw->lock);
  186. if (efw->dev_lock_count == -1)
  187. efw->dev_lock_count = 0;
  188. spin_unlock_irq(&efw->lock);
  189. return 0;
  190. }
  191. static int
  192. hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,
  193. unsigned int cmd, unsigned long arg)
  194. {
  195. struct snd_efw *efw = hwdep->private_data;
  196. switch (cmd) {
  197. case SNDRV_FIREWIRE_IOCTL_GET_INFO:
  198. return hwdep_get_info(efw, (void __user *)arg);
  199. case SNDRV_FIREWIRE_IOCTL_LOCK:
  200. return hwdep_lock(efw);
  201. case SNDRV_FIREWIRE_IOCTL_UNLOCK:
  202. return hwdep_unlock(efw);
  203. default:
  204. return -ENOIOCTLCMD;
  205. }
  206. }
  207. #ifdef CONFIG_COMPAT
  208. static int
  209. hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
  210. unsigned int cmd, unsigned long arg)
  211. {
  212. return hwdep_ioctl(hwdep, file, cmd,
  213. (unsigned long)compat_ptr(arg));
  214. }
  215. #else
  216. #define hwdep_compat_ioctl NULL
  217. #endif
  218. static const struct snd_hwdep_ops hwdep_ops = {
  219. .read = hwdep_read,
  220. .write = hwdep_write,
  221. .release = hwdep_release,
  222. .poll = hwdep_poll,
  223. .ioctl = hwdep_ioctl,
  224. .ioctl_compat = hwdep_compat_ioctl,
  225. };
  226. int snd_efw_create_hwdep_device(struct snd_efw *efw)
  227. {
  228. struct snd_hwdep *hwdep;
  229. int err;
  230. err = snd_hwdep_new(efw->card, "Fireworks", 0, &hwdep);
  231. if (err < 0)
  232. goto end;
  233. strcpy(hwdep->name, "Fireworks");
  234. hwdep->iface = SNDRV_HWDEP_IFACE_FW_FIREWORKS;
  235. hwdep->ops = hwdep_ops;
  236. hwdep->private_data = efw;
  237. hwdep->exclusive = true;
  238. end:
  239. return err;
  240. }