control_compat.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. /*
  2. * compat ioctls for control API
  3. *
  4. * Copyright (c) by Takashi Iwai <tiwai@suse.de>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19. */
  20. /* this file included from control.c */
  21. #include <linux/compat.h>
  22. #include <linux/slab.h>
  23. struct snd_ctl_elem_list32 {
  24. u32 offset;
  25. u32 space;
  26. u32 used;
  27. u32 count;
  28. u32 pids;
  29. unsigned char reserved[50];
  30. } /* don't set packed attribute here */;
  31. static int snd_ctl_elem_list_compat(struct snd_card *card,
  32. struct snd_ctl_elem_list32 __user *data32)
  33. {
  34. struct snd_ctl_elem_list __user *data;
  35. compat_caddr_t ptr;
  36. int err;
  37. data = compat_alloc_user_space(sizeof(*data));
  38. /* offset, space, used, count */
  39. if (copy_in_user(data, data32, 4 * sizeof(u32)))
  40. return -EFAULT;
  41. /* pids */
  42. if (get_user(ptr, &data32->pids) ||
  43. put_user(compat_ptr(ptr), &data->pids))
  44. return -EFAULT;
  45. err = snd_ctl_elem_list(card, data);
  46. if (err < 0)
  47. return err;
  48. /* copy the result */
  49. if (copy_in_user(data32, data, 4 * sizeof(u32)))
  50. return -EFAULT;
  51. return 0;
  52. }
  53. /*
  54. * control element info
  55. * it uses union, so the things are not easy..
  56. */
  57. struct snd_ctl_elem_info32 {
  58. struct snd_ctl_elem_id id; // the size of struct is same
  59. s32 type;
  60. u32 access;
  61. u32 count;
  62. s32 owner;
  63. union {
  64. struct {
  65. s32 min;
  66. s32 max;
  67. s32 step;
  68. } integer;
  69. struct {
  70. u64 min;
  71. u64 max;
  72. u64 step;
  73. } integer64;
  74. struct {
  75. u32 items;
  76. u32 item;
  77. char name[64];
  78. u64 names_ptr;
  79. u32 names_length;
  80. } enumerated;
  81. unsigned char reserved[128];
  82. } value;
  83. unsigned char reserved[64];
  84. } __attribute__((packed));
  85. static int snd_ctl_elem_info_compat(struct snd_ctl_file *ctl,
  86. struct snd_ctl_elem_info32 __user *data32)
  87. {
  88. struct snd_ctl_elem_info data;
  89. int err;
  90. memset(&data, 0, sizeof(data));
  91. err = -EFAULT;
  92. /* copy id */
  93. if (copy_from_user(&data.id, &data32->id, sizeof(data.id)))
  94. goto error;
  95. /* we need to copy the item index.
  96. * hope this doesn't break anything..
  97. */
  98. if (get_user(data.value.enumerated.item, &data32->value.enumerated.item))
  99. goto error;
  100. err = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0);
  101. if (err < 0)
  102. goto error;
  103. err = snd_ctl_elem_info(ctl, &data);
  104. if (err < 0)
  105. goto error;
  106. /* restore info to 32bit */
  107. err = -EFAULT;
  108. /* id, type, access, count */
  109. if (copy_to_user(&data32->id, &data.id, sizeof(data.id)) ||
  110. copy_to_user(&data32->type, &data.type, 3 * sizeof(u32)))
  111. goto error;
  112. if (put_user(data.owner, &data32->owner))
  113. goto error;
  114. switch (data.type) {
  115. case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
  116. case SNDRV_CTL_ELEM_TYPE_INTEGER:
  117. if (put_user(data.value.integer.min, &data32->value.integer.min) ||
  118. put_user(data.value.integer.max, &data32->value.integer.max) ||
  119. put_user(data.value.integer.step, &data32->value.integer.step))
  120. goto error;
  121. break;
  122. case SNDRV_CTL_ELEM_TYPE_INTEGER64:
  123. if (copy_to_user(&data32->value.integer64,
  124. &data.value.integer64,
  125. sizeof(data.value.integer64)))
  126. goto error;
  127. break;
  128. case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
  129. if (copy_to_user(&data32->value.enumerated,
  130. &data.value.enumerated,
  131. sizeof(data.value.enumerated)))
  132. goto error;
  133. break;
  134. default:
  135. break;
  136. }
  137. err = 0;
  138. error:
  139. return err;
  140. }
  141. /* read / write */
  142. struct snd_ctl_elem_value32 {
  143. struct snd_ctl_elem_id id;
  144. unsigned int indirect; /* bit-field causes misalignment */
  145. union {
  146. s32 integer[128];
  147. unsigned char data[512];
  148. #ifndef CONFIG_X86_64
  149. s64 integer64[64];
  150. #endif
  151. } value;
  152. unsigned char reserved[128];
  153. };
  154. #ifdef CONFIG_X86_X32
  155. /* x32 has a different alignment for 64bit values from ia32 */
  156. struct snd_ctl_elem_value_x32 {
  157. struct snd_ctl_elem_id id;
  158. unsigned int indirect; /* bit-field causes misalignment */
  159. union {
  160. s32 integer[128];
  161. unsigned char data[512];
  162. s64 integer64[64];
  163. } value;
  164. unsigned char reserved[128];
  165. };
  166. #endif /* CONFIG_X86_X32 */
  167. /* get the value type and count of the control */
  168. static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id,
  169. int *countp)
  170. {
  171. struct snd_kcontrol *kctl;
  172. struct snd_ctl_elem_info info;
  173. int err;
  174. down_read(&card->controls_rwsem);
  175. kctl = snd_ctl_find_id(card, id);
  176. if (! kctl) {
  177. up_read(&card->controls_rwsem);
  178. return -ENOENT;
  179. }
  180. info = (typeof(info)){ .id = *id };
  181. err = kctl->info(kctl, &info);
  182. up_read(&card->controls_rwsem);
  183. if (err >= 0) {
  184. err = info.type;
  185. *countp = info.count;
  186. }
  187. return err;
  188. }
  189. static int get_elem_size(int type, int count)
  190. {
  191. switch (type) {
  192. case SNDRV_CTL_ELEM_TYPE_INTEGER64:
  193. return sizeof(s64) * count;
  194. case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
  195. return sizeof(int) * count;
  196. case SNDRV_CTL_ELEM_TYPE_BYTES:
  197. return 512;
  198. case SNDRV_CTL_ELEM_TYPE_IEC958:
  199. return sizeof(struct snd_aes_iec958);
  200. default:
  201. return -1;
  202. }
  203. }
  204. static int copy_ctl_value_from_user(struct snd_card *card,
  205. struct snd_ctl_elem_value *data,
  206. void __user *userdata,
  207. void __user *valuep,
  208. int *typep, int *countp)
  209. {
  210. struct snd_ctl_elem_value32 __user *data32 = userdata;
  211. int i, type, size;
  212. int uninitialized_var(count);
  213. unsigned int indirect;
  214. if (copy_from_user(&data->id, &data32->id, sizeof(data->id)))
  215. return -EFAULT;
  216. if (get_user(indirect, &data32->indirect))
  217. return -EFAULT;
  218. if (indirect)
  219. return -EINVAL;
  220. type = get_ctl_type(card, &data->id, &count);
  221. if (type < 0)
  222. return type;
  223. if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
  224. type == SNDRV_CTL_ELEM_TYPE_INTEGER) {
  225. for (i = 0; i < count; i++) {
  226. s32 __user *intp = valuep;
  227. int val;
  228. if (get_user(val, &intp[i]))
  229. return -EFAULT;
  230. data->value.integer.value[i] = val;
  231. }
  232. } else {
  233. size = get_elem_size(type, count);
  234. if (size < 0) {
  235. dev_err(card->dev, "snd_ioctl32_ctl_elem_value: unknown type %d\n", type);
  236. return -EINVAL;
  237. }
  238. if (copy_from_user(data->value.bytes.data, valuep, size))
  239. return -EFAULT;
  240. }
  241. *typep = type;
  242. *countp = count;
  243. return 0;
  244. }
  245. /* restore the value to 32bit */
  246. static int copy_ctl_value_to_user(void __user *userdata,
  247. void __user *valuep,
  248. struct snd_ctl_elem_value *data,
  249. int type, int count)
  250. {
  251. int i, size;
  252. if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
  253. type == SNDRV_CTL_ELEM_TYPE_INTEGER) {
  254. for (i = 0; i < count; i++) {
  255. s32 __user *intp = valuep;
  256. int val;
  257. val = data->value.integer.value[i];
  258. if (put_user(val, &intp[i]))
  259. return -EFAULT;
  260. }
  261. } else {
  262. size = get_elem_size(type, count);
  263. if (copy_to_user(valuep, data->value.bytes.data, size))
  264. return -EFAULT;
  265. }
  266. return 0;
  267. }
  268. static int ctl_elem_read_user(struct snd_card *card,
  269. void __user *userdata, void __user *valuep)
  270. {
  271. struct snd_ctl_elem_value data;
  272. int err, type, count;
  273. memset(&data, 0, sizeof(data));
  274. err = copy_ctl_value_from_user(card, &data, userdata, valuep,
  275. &type, &count);
  276. if (err < 0)
  277. goto error;
  278. err = snd_power_wait(card, SNDRV_CTL_POWER_D0);
  279. if (err < 0)
  280. goto error;
  281. err = snd_ctl_elem_read(card, &data);
  282. if (err < 0)
  283. goto error;
  284. err = copy_ctl_value_to_user(userdata, valuep, &data, type, count);
  285. error:
  286. return err;
  287. }
  288. static int ctl_elem_write_user(struct snd_ctl_file *file,
  289. void __user *userdata, void __user *valuep)
  290. {
  291. struct snd_ctl_elem_value data;
  292. struct snd_card *card = file->card;
  293. int err, type, count;
  294. memset(&data, 0, sizeof(data));
  295. err = copy_ctl_value_from_user(card, &data, userdata, valuep,
  296. &type, &count);
  297. if (err < 0)
  298. goto error;
  299. err = snd_power_wait(card, SNDRV_CTL_POWER_D0);
  300. if (err < 0)
  301. goto error;
  302. err = snd_ctl_elem_write(card, file, &data);
  303. if (err < 0)
  304. goto error;
  305. err = copy_ctl_value_to_user(userdata, valuep, &data, type, count);
  306. error:
  307. return err;
  308. }
  309. static int snd_ctl_elem_read_user_compat(struct snd_card *card,
  310. struct snd_ctl_elem_value32 __user *data32)
  311. {
  312. return ctl_elem_read_user(card, data32, &data32->value);
  313. }
  314. static int snd_ctl_elem_write_user_compat(struct snd_ctl_file *file,
  315. struct snd_ctl_elem_value32 __user *data32)
  316. {
  317. return ctl_elem_write_user(file, data32, &data32->value);
  318. }
  319. #ifdef CONFIG_X86_X32
  320. static int snd_ctl_elem_read_user_x32(struct snd_card *card,
  321. struct snd_ctl_elem_value_x32 __user *data32)
  322. {
  323. return ctl_elem_read_user(card, data32, &data32->value);
  324. }
  325. static int snd_ctl_elem_write_user_x32(struct snd_ctl_file *file,
  326. struct snd_ctl_elem_value_x32 __user *data32)
  327. {
  328. return ctl_elem_write_user(file, data32, &data32->value);
  329. }
  330. #endif /* CONFIG_X86_X32 */
  331. /* add or replace a user control */
  332. static int snd_ctl_elem_add_compat(struct snd_ctl_file *file,
  333. struct snd_ctl_elem_info32 __user *data32,
  334. int replace)
  335. {
  336. struct snd_ctl_elem_info data;
  337. int err;
  338. memset(&data, 0, sizeof(data));
  339. err = -EFAULT;
  340. /* id, type, access, count */ \
  341. if (copy_from_user(&data.id, &data32->id, sizeof(data.id)) ||
  342. copy_from_user(&data.type, &data32->type, 3 * sizeof(u32)))
  343. goto error;
  344. if (get_user(data.owner, &data32->owner))
  345. goto error;
  346. switch (data.type) {
  347. case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
  348. case SNDRV_CTL_ELEM_TYPE_INTEGER:
  349. if (get_user(data.value.integer.min, &data32->value.integer.min) ||
  350. get_user(data.value.integer.max, &data32->value.integer.max) ||
  351. get_user(data.value.integer.step, &data32->value.integer.step))
  352. goto error;
  353. break;
  354. case SNDRV_CTL_ELEM_TYPE_INTEGER64:
  355. if (copy_from_user(&data.value.integer64,
  356. &data32->value.integer64,
  357. sizeof(data.value.integer64)))
  358. goto error;
  359. break;
  360. case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
  361. if (copy_from_user(&data.value.enumerated,
  362. &data32->value.enumerated,
  363. sizeof(data.value.enumerated)))
  364. goto error;
  365. data.value.enumerated.names_ptr =
  366. (uintptr_t)compat_ptr(data.value.enumerated.names_ptr);
  367. break;
  368. default:
  369. break;
  370. }
  371. err = snd_ctl_elem_add(file, &data, replace);
  372. error:
  373. return err;
  374. }
  375. enum {
  376. SNDRV_CTL_IOCTL_ELEM_LIST32 = _IOWR('U', 0x10, struct snd_ctl_elem_list32),
  377. SNDRV_CTL_IOCTL_ELEM_INFO32 = _IOWR('U', 0x11, struct snd_ctl_elem_info32),
  378. SNDRV_CTL_IOCTL_ELEM_READ32 = _IOWR('U', 0x12, struct snd_ctl_elem_value32),
  379. SNDRV_CTL_IOCTL_ELEM_WRITE32 = _IOWR('U', 0x13, struct snd_ctl_elem_value32),
  380. SNDRV_CTL_IOCTL_ELEM_ADD32 = _IOWR('U', 0x17, struct snd_ctl_elem_info32),
  381. SNDRV_CTL_IOCTL_ELEM_REPLACE32 = _IOWR('U', 0x18, struct snd_ctl_elem_info32),
  382. #ifdef CONFIG_X86_X32
  383. SNDRV_CTL_IOCTL_ELEM_READ_X32 = _IOWR('U', 0x12, struct snd_ctl_elem_value_x32),
  384. SNDRV_CTL_IOCTL_ELEM_WRITE_X32 = _IOWR('U', 0x13, struct snd_ctl_elem_value_x32),
  385. #endif /* CONFIG_X86_X32 */
  386. };
  387. static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
  388. {
  389. struct snd_ctl_file *ctl;
  390. struct snd_kctl_ioctl *p;
  391. void __user *argp = compat_ptr(arg);
  392. int err;
  393. ctl = file->private_data;
  394. if (snd_BUG_ON(!ctl || !ctl->card))
  395. return -ENXIO;
  396. switch (cmd) {
  397. case SNDRV_CTL_IOCTL_PVERSION:
  398. case SNDRV_CTL_IOCTL_CARD_INFO:
  399. case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
  400. case SNDRV_CTL_IOCTL_POWER:
  401. case SNDRV_CTL_IOCTL_POWER_STATE:
  402. case SNDRV_CTL_IOCTL_ELEM_LOCK:
  403. case SNDRV_CTL_IOCTL_ELEM_UNLOCK:
  404. case SNDRV_CTL_IOCTL_ELEM_REMOVE:
  405. case SNDRV_CTL_IOCTL_TLV_READ:
  406. case SNDRV_CTL_IOCTL_TLV_WRITE:
  407. case SNDRV_CTL_IOCTL_TLV_COMMAND:
  408. return snd_ctl_ioctl(file, cmd, (unsigned long)argp);
  409. case SNDRV_CTL_IOCTL_ELEM_LIST32:
  410. return snd_ctl_elem_list_compat(ctl->card, argp);
  411. case SNDRV_CTL_IOCTL_ELEM_INFO32:
  412. return snd_ctl_elem_info_compat(ctl, argp);
  413. case SNDRV_CTL_IOCTL_ELEM_READ32:
  414. return snd_ctl_elem_read_user_compat(ctl->card, argp);
  415. case SNDRV_CTL_IOCTL_ELEM_WRITE32:
  416. return snd_ctl_elem_write_user_compat(ctl, argp);
  417. case SNDRV_CTL_IOCTL_ELEM_ADD32:
  418. return snd_ctl_elem_add_compat(ctl, argp, 0);
  419. case SNDRV_CTL_IOCTL_ELEM_REPLACE32:
  420. return snd_ctl_elem_add_compat(ctl, argp, 1);
  421. #ifdef CONFIG_X86_X32
  422. case SNDRV_CTL_IOCTL_ELEM_READ_X32:
  423. return snd_ctl_elem_read_user_x32(ctl->card, argp);
  424. case SNDRV_CTL_IOCTL_ELEM_WRITE_X32:
  425. return snd_ctl_elem_write_user_x32(ctl, argp);
  426. #endif /* CONFIG_X86_X32 */
  427. }
  428. down_read(&snd_ioctl_rwsem);
  429. list_for_each_entry(p, &snd_control_compat_ioctls, list) {
  430. if (p->fioctl) {
  431. err = p->fioctl(ctl->card, ctl, cmd, arg);
  432. if (err != -ENOIOCTLCMD) {
  433. up_read(&snd_ioctl_rwsem);
  434. return err;
  435. }
  436. }
  437. }
  438. up_read(&snd_ioctl_rwsem);
  439. return -ENOIOCTLCMD;
  440. }