tvmixer.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. /*
  2. */
  3. #include <linux/module.h>
  4. #include <linux/moduleparam.h>
  5. #include <linux/kernel.h>
  6. #include <linux/sched.h>
  7. #include <linux/string.h>
  8. #include <linux/timer.h>
  9. #include <linux/delay.h>
  10. #include <linux/errno.h>
  11. #include <linux/slab.h>
  12. #include <linux/i2c.h>
  13. #include <linux/videodev.h>
  14. #include <linux/init.h>
  15. #include <linux/kdev_t.h>
  16. #include <linux/sound.h>
  17. #include <linux/soundcard.h>
  18. #include <asm/semaphore.h>
  19. #include <asm/uaccess.h>
  20. #define DEV_MAX 4
  21. static int devnr = -1;
  22. module_param(devnr, int, 0644);
  23. MODULE_AUTHOR("Gerd Knorr");
  24. MODULE_LICENSE("GPL");
  25. /* ----------------------------------------------------------------------- */
  26. struct TVMIXER {
  27. struct i2c_client *dev;
  28. int minor;
  29. int count;
  30. };
  31. static struct TVMIXER devices[DEV_MAX];
  32. static int tvmixer_adapters(struct i2c_adapter *adap);
  33. static int tvmixer_clients(struct i2c_client *client);
  34. /* ----------------------------------------------------------------------- */
  35. static int mix_to_v4l(int i)
  36. {
  37. int r;
  38. r = ((i & 0xff) * 65536 + 50) / 100;
  39. if (r > 65535) r = 65535;
  40. if (r < 0) r = 0;
  41. return r;
  42. }
  43. static int v4l_to_mix(int i)
  44. {
  45. int r;
  46. r = (i * 100 + 32768) / 65536;
  47. if (r > 100) r = 100;
  48. if (r < 0) r = 0;
  49. return r | (r << 8);
  50. }
  51. static int v4l_to_mix2(int l, int r)
  52. {
  53. r = (r * 100 + 32768) / 65536;
  54. if (r > 100) r = 100;
  55. if (r < 0) r = 0;
  56. l = (l * 100 + 32768) / 65536;
  57. if (l > 100) l = 100;
  58. if (l < 0) l = 0;
  59. return (r << 8) | l;
  60. }
  61. static int tvmixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
  62. {
  63. struct video_audio va;
  64. int left,right,ret,val = 0;
  65. struct TVMIXER *mix = file->private_data;
  66. struct i2c_client *client = mix->dev;
  67. void __user *argp = (void __user *)arg;
  68. int __user *p = argp;
  69. if (NULL == client)
  70. return -ENODEV;
  71. if (cmd == SOUND_MIXER_INFO) {
  72. mixer_info info;
  73. strlcpy(info.id, "tv card", sizeof(info.id));
  74. strlcpy(info.name, client->name, sizeof(info.name));
  75. info.modify_counter = 42 /* FIXME */;
  76. if (copy_to_user(argp, &info, sizeof(info)))
  77. return -EFAULT;
  78. return 0;
  79. }
  80. if (cmd == SOUND_OLD_MIXER_INFO) {
  81. _old_mixer_info info;
  82. strlcpy(info.id, "tv card", sizeof(info.id));
  83. strlcpy(info.name, client->name, sizeof(info.name));
  84. if (copy_to_user(argp, &info, sizeof(info)))
  85. return -EFAULT;
  86. return 0;
  87. }
  88. if (cmd == OSS_GETVERSION)
  89. return put_user(SOUND_VERSION, p);
  90. if (_SIOC_DIR(cmd) & _SIOC_WRITE)
  91. if (get_user(val, p))
  92. return -EFAULT;
  93. /* read state */
  94. memset(&va,0,sizeof(va));
  95. client->driver->command(client,VIDIOCGAUDIO,&va);
  96. switch (cmd) {
  97. case MIXER_READ(SOUND_MIXER_RECMASK):
  98. case MIXER_READ(SOUND_MIXER_CAPS):
  99. case MIXER_READ(SOUND_MIXER_RECSRC):
  100. case MIXER_WRITE(SOUND_MIXER_RECSRC):
  101. ret = 0;
  102. break;
  103. case MIXER_READ(SOUND_MIXER_STEREODEVS):
  104. ret = SOUND_MASK_VOLUME;
  105. break;
  106. case MIXER_READ(SOUND_MIXER_DEVMASK):
  107. ret = SOUND_MASK_VOLUME;
  108. if (va.flags & VIDEO_AUDIO_BASS)
  109. ret |= SOUND_MASK_BASS;
  110. if (va.flags & VIDEO_AUDIO_TREBLE)
  111. ret |= SOUND_MASK_TREBLE;
  112. break;
  113. case MIXER_WRITE(SOUND_MIXER_VOLUME):
  114. left = mix_to_v4l(val);
  115. right = mix_to_v4l(val >> 8);
  116. va.volume = max(left,right);
  117. va.balance = (32768*min(left,right)) / (va.volume ? va.volume : 1);
  118. va.balance = (left<right) ? (65535-va.balance) : va.balance;
  119. if (va.volume)
  120. va.flags &= ~VIDEO_AUDIO_MUTE;
  121. client->driver->command(client,VIDIOCSAUDIO,&va);
  122. client->driver->command(client,VIDIOCGAUDIO,&va);
  123. /* fall throuth */
  124. case MIXER_READ(SOUND_MIXER_VOLUME):
  125. left = (min(65536 - va.balance,32768) *
  126. va.volume) / 32768;
  127. right = (min(va.balance,(u16)32768) *
  128. va.volume) / 32768;
  129. ret = v4l_to_mix2(left,right);
  130. break;
  131. case MIXER_WRITE(SOUND_MIXER_BASS):
  132. va.bass = mix_to_v4l(val);
  133. client->driver->command(client,VIDIOCSAUDIO,&va);
  134. client->driver->command(client,VIDIOCGAUDIO,&va);
  135. /* fall throuth */
  136. case MIXER_READ(SOUND_MIXER_BASS):
  137. ret = v4l_to_mix(va.bass);
  138. break;
  139. case MIXER_WRITE(SOUND_MIXER_TREBLE):
  140. va.treble = mix_to_v4l(val);
  141. client->driver->command(client,VIDIOCSAUDIO,&va);
  142. client->driver->command(client,VIDIOCGAUDIO,&va);
  143. /* fall throuth */
  144. case MIXER_READ(SOUND_MIXER_TREBLE):
  145. ret = v4l_to_mix(va.treble);
  146. break;
  147. default:
  148. return -EINVAL;
  149. }
  150. if (put_user(ret, p))
  151. return -EFAULT;
  152. return 0;
  153. }
  154. static int tvmixer_open(struct inode *inode, struct file *file)
  155. {
  156. int i, minor = iminor(inode);
  157. struct TVMIXER *mix = NULL;
  158. struct i2c_client *client = NULL;
  159. for (i = 0; i < DEV_MAX; i++) {
  160. if (devices[i].minor == minor) {
  161. mix = devices+i;
  162. client = mix->dev;
  163. break;
  164. }
  165. }
  166. if (NULL == client)
  167. return -ENODEV;
  168. /* lock bttv in memory while the mixer is in use */
  169. file->private_data = mix;
  170. #ifndef I2C_PEC
  171. if (client->adapter->inc_use)
  172. client->adapter->inc_use(client->adapter);
  173. #endif
  174. if (client->adapter->owner)
  175. try_module_get(client->adapter->owner);
  176. return 0;
  177. }
  178. static int tvmixer_release(struct inode *inode, struct file *file)
  179. {
  180. struct TVMIXER *mix = file->private_data;
  181. struct i2c_client *client;
  182. client = mix->dev;
  183. if (NULL == client) {
  184. return -ENODEV;
  185. }
  186. #ifndef I2C_PEC
  187. if (client->adapter->dec_use)
  188. client->adapter->dec_use(client->adapter);
  189. #endif
  190. if (client->adapter->owner)
  191. module_put(client->adapter->owner);
  192. return 0;
  193. }
  194. static struct i2c_driver driver = {
  195. .driver = {
  196. .name = "tvmixer",
  197. },
  198. .id = I2C_DRIVERID_TVMIXER,
  199. .detach_adapter = tvmixer_adapters,
  200. .attach_adapter = tvmixer_adapters,
  201. .detach_client = tvmixer_clients,
  202. };
  203. static struct file_operations tvmixer_fops = {
  204. .owner = THIS_MODULE,
  205. .llseek = no_llseek,
  206. .ioctl = tvmixer_ioctl,
  207. .open = tvmixer_open,
  208. .release = tvmixer_release,
  209. };
  210. /* ----------------------------------------------------------------------- */
  211. static int tvmixer_adapters(struct i2c_adapter *adap)
  212. {
  213. struct list_head *item;
  214. struct i2c_client *client;
  215. list_for_each(item,&adap->clients) {
  216. client = list_entry(item, struct i2c_client, list);
  217. tvmixer_clients(client);
  218. }
  219. return 0;
  220. }
  221. static int tvmixer_clients(struct i2c_client *client)
  222. {
  223. struct video_audio va;
  224. int i,minor;
  225. if (!(client->adapter->class & I2C_CLASS_TV_ANALOG))
  226. return -1;
  227. /* unregister ?? */
  228. for (i = 0; i < DEV_MAX; i++) {
  229. if (devices[i].dev == client) {
  230. /* unregister */
  231. unregister_sound_mixer(devices[i].minor);
  232. devices[i].dev = NULL;
  233. devices[i].minor = -1;
  234. printk("tvmixer: %s unregistered (#1)\n",
  235. client->name);
  236. return 0;
  237. }
  238. }
  239. /* look for a free slot */
  240. for (i = 0; i < DEV_MAX; i++)
  241. if (NULL == devices[i].dev)
  242. break;
  243. if (i == DEV_MAX) {
  244. printk(KERN_WARNING "tvmixer: DEV_MAX too small\n");
  245. return -1;
  246. }
  247. /* audio chip with mixer ??? */
  248. if (NULL == client->driver->command)
  249. return -1;
  250. memset(&va,0,sizeof(va));
  251. if (0 != client->driver->command(client,VIDIOCGAUDIO,&va))
  252. return -1;
  253. if (0 == (va.flags & VIDEO_AUDIO_VOLUME))
  254. return -1;
  255. /* everything is fine, register */
  256. if ((minor = register_sound_mixer(&tvmixer_fops,devnr)) < 0) {
  257. printk(KERN_ERR "tvmixer: cannot allocate mixer device\n");
  258. return -1;
  259. }
  260. devices[i].minor = minor;
  261. devices[i].count = 0;
  262. devices[i].dev = client;
  263. printk("tvmixer: %s (%s) registered with minor %d\n",
  264. client->name,client->adapter->name,minor);
  265. return 0;
  266. }
  267. /* ----------------------------------------------------------------------- */
  268. static int __init tvmixer_init_module(void)
  269. {
  270. int i;
  271. for (i = 0; i < DEV_MAX; i++)
  272. devices[i].minor = -1;
  273. return i2c_add_driver(&driver);
  274. }
  275. static void __exit tvmixer_cleanup_module(void)
  276. {
  277. int i;
  278. i2c_del_driver(&driver);
  279. for (i = 0; i < DEV_MAX; i++) {
  280. if (devices[i].minor != -1) {
  281. unregister_sound_mixer(devices[i].minor);
  282. printk("tvmixer: %s unregistered (#2)\n",
  283. devices[i].dev->name);
  284. }
  285. }
  286. }
  287. module_init(tvmixer_init_module);
  288. module_exit(tvmixer_cleanup_module);
  289. /*
  290. * Overrides for Emacs so that we follow Linus's tabbing style.
  291. * ---------------------------------------------------------------------------
  292. * Local variables:
  293. * c-basic-offset: 8
  294. * End:
  295. */