Commit | Line | Data |
---|---|---|
4834f4d1 AK |
1 | /* |
2 | * Driver for the MasterKit MA901 USB FM radio. This device plugs | |
3 | * into the USB port and an analog audio input or headphones, so this thing | |
4 | * only deals with initialization, frequency setting, volume. | |
5 | * | |
6 | * Copyright (c) 2012 Alexey Klimov <klimov.linux@gmail.com> | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License as published by | |
10 | * the Free Software Foundation; either version 2 of the License, or | |
11 | * (at your option) any later version. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 | */ | |
22 | ||
23 | #include <linux/kernel.h> | |
24 | #include <linux/module.h> | |
25 | #include <linux/init.h> | |
26 | #include <linux/slab.h> | |
27 | #include <linux/input.h> | |
28 | #include <linux/videodev2.h> | |
29 | #include <media/v4l2-device.h> | |
30 | #include <media/v4l2-ioctl.h> | |
31 | #include <media/v4l2-ctrls.h> | |
32 | #include <media/v4l2-event.h> | |
33 | #include <linux/usb.h> | |
34 | #include <linux/mutex.h> | |
35 | ||
36 | #define DRIVER_AUTHOR "Alexey Klimov <klimov.linux@gmail.com>" | |
37 | #define DRIVER_DESC "Masterkit MA901 USB FM radio driver" | |
38 | #define DRIVER_VERSION "0.0.1" | |
39 | ||
40 | MODULE_AUTHOR(DRIVER_AUTHOR); | |
41 | MODULE_DESCRIPTION(DRIVER_DESC); | |
42 | MODULE_LICENSE("GPL"); | |
43 | MODULE_VERSION(DRIVER_VERSION); | |
44 | ||
45 | #define USB_MA901_VENDOR 0x16c0 | |
46 | #define USB_MA901_PRODUCT 0x05df | |
47 | ||
48 | /* dev_warn macro with driver name */ | |
49 | #define MA901_DRIVER_NAME "radio-ma901" | |
50 | #define ma901radio_dev_warn(dev, fmt, arg...) \ | |
51 | dev_warn(dev, MA901_DRIVER_NAME " - " fmt, ##arg) | |
52 | ||
53 | #define ma901radio_dev_err(dev, fmt, arg...) \ | |
54 | dev_err(dev, MA901_DRIVER_NAME " - " fmt, ##arg) | |
55 | ||
56 | /* Probably USB_TIMEOUT should be modified in module parameter */ | |
57 | #define BUFFER_LENGTH 8 | |
58 | #define USB_TIMEOUT 500 | |
59 | ||
60 | #define FREQ_MIN 87.5 | |
61 | #define FREQ_MAX 108.0 | |
62 | #define FREQ_MUL 16000 | |
63 | ||
64 | #define MA901_VOLUME_MAX 16 | |
65 | #define MA901_VOLUME_MIN 0 | |
66 | ||
67 | /* Commands that device should understand | |
68 | * List isn't full and will be updated with implementation of new functions | |
69 | */ | |
70 | #define MA901_RADIO_SET_FREQ 0x03 | |
71 | #define MA901_RADIO_SET_VOLUME 0x04 | |
72 | #define MA901_RADIO_SET_MONO_STEREO 0x05 | |
73 | ||
74 | /* Comfortable defines for ma901radio_set_stereo */ | |
75 | #define MA901_WANT_STEREO 0x50 | |
76 | #define MA901_WANT_MONO 0xd0 | |
77 | ||
78 | /* module parameter */ | |
79 | static int radio_nr = -1; | |
80 | module_param(radio_nr, int, 0); | |
81 | MODULE_PARM_DESC(radio_nr, "Radio file number"); | |
82 | ||
83 | /* Data for one (physical) device */ | |
84 | struct ma901radio_device { | |
85 | /* reference to USB and video device */ | |
86 | struct usb_device *usbdev; | |
87 | struct usb_interface *intf; | |
88 | struct video_device vdev; | |
89 | struct v4l2_device v4l2_dev; | |
90 | struct v4l2_ctrl_handler hdl; | |
91 | ||
92 | u8 *buffer; | |
93 | struct mutex lock; /* buffer locking */ | |
94 | int curfreq; | |
95 | u16 volume; | |
96 | int stereo; | |
97 | bool muted; | |
98 | }; | |
99 | ||
100 | static inline struct ma901radio_device *to_ma901radio_dev(struct v4l2_device *v4l2_dev) | |
101 | { | |
102 | return container_of(v4l2_dev, struct ma901radio_device, v4l2_dev); | |
103 | } | |
104 | ||
105 | /* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */ | |
106 | static int ma901radio_set_freq(struct ma901radio_device *radio, int freq) | |
107 | { | |
108 | unsigned int freq_send = 0x300 + (freq >> 5) / 25; | |
109 | int retval; | |
110 | ||
111 | radio->buffer[0] = 0x0a; | |
112 | radio->buffer[1] = MA901_RADIO_SET_FREQ; | |
113 | radio->buffer[2] = ((freq_send >> 8) & 0xff) + 0x80; | |
114 | radio->buffer[3] = freq_send & 0xff; | |
115 | radio->buffer[4] = 0x00; | |
116 | radio->buffer[5] = 0x00; | |
117 | radio->buffer[6] = 0x00; | |
118 | radio->buffer[7] = 0x00; | |
119 | ||
120 | retval = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0), | |
121 | 9, 0x21, 0x0300, 0, | |
122 | radio->buffer, BUFFER_LENGTH, USB_TIMEOUT); | |
123 | if (retval < 0) | |
124 | return retval; | |
125 | ||
126 | radio->curfreq = freq; | |
127 | return 0; | |
128 | } | |
129 | ||
130 | static int ma901radio_set_volume(struct ma901radio_device *radio, u16 vol_to_set) | |
131 | { | |
132 | int retval; | |
133 | ||
134 | radio->buffer[0] = 0x0a; | |
135 | radio->buffer[1] = MA901_RADIO_SET_VOLUME; | |
136 | radio->buffer[2] = 0xc2; | |
137 | radio->buffer[3] = vol_to_set + 0x20; | |
138 | radio->buffer[4] = 0x00; | |
139 | radio->buffer[5] = 0x00; | |
140 | radio->buffer[6] = 0x00; | |
141 | radio->buffer[7] = 0x00; | |
142 | ||
143 | retval = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0), | |
144 | 9, 0x21, 0x0300, 0, | |
145 | radio->buffer, BUFFER_LENGTH, USB_TIMEOUT); | |
146 | if (retval < 0) | |
147 | return retval; | |
148 | ||
149 | radio->volume = vol_to_set; | |
150 | return retval; | |
151 | } | |
152 | ||
153 | static int ma901_set_stereo(struct ma901radio_device *radio, u8 stereo) | |
154 | { | |
155 | int retval; | |
156 | ||
157 | radio->buffer[0] = 0x0a; | |
158 | radio->buffer[1] = MA901_RADIO_SET_MONO_STEREO; | |
159 | radio->buffer[2] = stereo; | |
160 | radio->buffer[3] = 0x00; | |
161 | radio->buffer[4] = 0x00; | |
162 | radio->buffer[5] = 0x00; | |
163 | radio->buffer[6] = 0x00; | |
164 | radio->buffer[7] = 0x00; | |
165 | ||
166 | retval = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0), | |
167 | 9, 0x21, 0x0300, 0, | |
168 | radio->buffer, BUFFER_LENGTH, USB_TIMEOUT); | |
169 | ||
170 | if (retval < 0) | |
171 | return retval; | |
172 | ||
173 | if (stereo == MA901_WANT_STEREO) | |
174 | radio->stereo = V4L2_TUNER_MODE_STEREO; | |
175 | else | |
176 | radio->stereo = V4L2_TUNER_MODE_MONO; | |
177 | ||
178 | return retval; | |
179 | } | |
180 | ||
181 | /* Handle unplugging the device. | |
182 | * We call video_unregister_device in any case. | |
183 | * The last function called in this procedure is | |
184 | * usb_ma901radio_device_release. | |
185 | */ | |
186 | static void usb_ma901radio_disconnect(struct usb_interface *intf) | |
187 | { | |
188 | struct ma901radio_device *radio = to_ma901radio_dev(usb_get_intfdata(intf)); | |
189 | ||
190 | mutex_lock(&radio->lock); | |
191 | video_unregister_device(&radio->vdev); | |
192 | usb_set_intfdata(intf, NULL); | |
193 | v4l2_device_disconnect(&radio->v4l2_dev); | |
194 | mutex_unlock(&radio->lock); | |
195 | v4l2_device_put(&radio->v4l2_dev); | |
196 | } | |
197 | ||
198 | /* vidioc_querycap - query device capabilities */ | |
199 | static int vidioc_querycap(struct file *file, void *priv, | |
200 | struct v4l2_capability *v) | |
201 | { | |
202 | struct ma901radio_device *radio = video_drvdata(file); | |
203 | ||
204 | strlcpy(v->driver, "radio-ma901", sizeof(v->driver)); | |
205 | strlcpy(v->card, "Masterkit MA901 USB FM Radio", sizeof(v->card)); | |
206 | usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info)); | |
207 | v->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER; | |
208 | v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; | |
209 | return 0; | |
210 | } | |
211 | ||
212 | /* vidioc_g_tuner - get tuner attributes */ | |
213 | static int vidioc_g_tuner(struct file *file, void *priv, | |
214 | struct v4l2_tuner *v) | |
215 | { | |
216 | struct ma901radio_device *radio = video_drvdata(file); | |
217 | ||
218 | if (v->index > 0) | |
219 | return -EINVAL; | |
220 | ||
221 | v->signal = 0; | |
222 | ||
223 | /* TODO: the same words like in _probe() goes here. | |
224 | * When receiving of stats will be implemented then we can call | |
225 | * ma901radio_get_stat(). | |
226 | * retval = ma901radio_get_stat(radio, &is_stereo, &v->signal); | |
227 | */ | |
228 | ||
229 | strcpy(v->name, "FM"); | |
230 | v->type = V4L2_TUNER_RADIO; | |
231 | v->rangelow = FREQ_MIN * FREQ_MUL; | |
232 | v->rangehigh = FREQ_MAX * FREQ_MUL; | |
233 | v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; | |
234 | /* v->rxsubchans = is_stereo ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; */ | |
235 | v->audmode = radio->stereo ? | |
236 | V4L2_TUNER_MODE_STEREO : V4L2_TUNER_MODE_MONO; | |
237 | return 0; | |
238 | } | |
239 | ||
240 | /* vidioc_s_tuner - set tuner attributes */ | |
241 | static int vidioc_s_tuner(struct file *file, void *priv, | |
2f73c7c5 | 242 | const struct v4l2_tuner *v) |
4834f4d1 AK |
243 | { |
244 | struct ma901radio_device *radio = video_drvdata(file); | |
245 | ||
246 | if (v->index > 0) | |
247 | return -EINVAL; | |
248 | ||
249 | /* mono/stereo selector */ | |
250 | switch (v->audmode) { | |
251 | case V4L2_TUNER_MODE_MONO: | |
252 | return ma901_set_stereo(radio, MA901_WANT_MONO); | |
253 | default: | |
254 | return ma901_set_stereo(radio, MA901_WANT_STEREO); | |
255 | } | |
256 | } | |
257 | ||
258 | /* vidioc_s_frequency - set tuner radio frequency */ | |
259 | static int vidioc_s_frequency(struct file *file, void *priv, | |
b530a447 | 260 | const struct v4l2_frequency *f) |
4834f4d1 AK |
261 | { |
262 | struct ma901radio_device *radio = video_drvdata(file); | |
263 | ||
264 | if (f->tuner != 0) | |
265 | return -EINVAL; | |
266 | ||
267 | return ma901radio_set_freq(radio, clamp_t(unsigned, f->frequency, | |
268 | FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL)); | |
269 | } | |
270 | ||
271 | /* vidioc_g_frequency - get tuner radio frequency */ | |
272 | static int vidioc_g_frequency(struct file *file, void *priv, | |
273 | struct v4l2_frequency *f) | |
274 | { | |
275 | struct ma901radio_device *radio = video_drvdata(file); | |
276 | ||
277 | if (f->tuner != 0) | |
278 | return -EINVAL; | |
279 | f->frequency = radio->curfreq; | |
280 | ||
281 | return 0; | |
282 | } | |
283 | ||
284 | static int usb_ma901radio_s_ctrl(struct v4l2_ctrl *ctrl) | |
285 | { | |
286 | struct ma901radio_device *radio = | |
287 | container_of(ctrl->handler, struct ma901radio_device, hdl); | |
288 | ||
289 | switch (ctrl->id) { | |
290 | case V4L2_CID_AUDIO_VOLUME: /* set volume */ | |
291 | return ma901radio_set_volume(radio, (u16)ctrl->val); | |
292 | } | |
293 | ||
294 | return -EINVAL; | |
295 | } | |
296 | ||
297 | /* TODO: Should we really need to implement suspend and resume functions? | |
298 | * Radio has it's own memory and will continue playing if power is present | |
299 | * on usb port and on resume it will start to play again based on freq, volume | |
300 | * values in device memory. | |
301 | */ | |
302 | static int usb_ma901radio_suspend(struct usb_interface *intf, pm_message_t message) | |
303 | { | |
304 | return 0; | |
305 | } | |
306 | ||
307 | static int usb_ma901radio_resume(struct usb_interface *intf) | |
308 | { | |
309 | return 0; | |
310 | } | |
311 | ||
312 | static const struct v4l2_ctrl_ops usb_ma901radio_ctrl_ops = { | |
313 | .s_ctrl = usb_ma901radio_s_ctrl, | |
314 | }; | |
315 | ||
316 | /* File system interface */ | |
317 | static const struct v4l2_file_operations usb_ma901radio_fops = { | |
318 | .owner = THIS_MODULE, | |
319 | .open = v4l2_fh_open, | |
320 | .release = v4l2_fh_release, | |
321 | .poll = v4l2_ctrl_poll, | |
322 | .unlocked_ioctl = video_ioctl2, | |
323 | }; | |
324 | ||
325 | static const struct v4l2_ioctl_ops usb_ma901radio_ioctl_ops = { | |
326 | .vidioc_querycap = vidioc_querycap, | |
327 | .vidioc_g_tuner = vidioc_g_tuner, | |
328 | .vidioc_s_tuner = vidioc_s_tuner, | |
329 | .vidioc_g_frequency = vidioc_g_frequency, | |
330 | .vidioc_s_frequency = vidioc_s_frequency, | |
331 | .vidioc_log_status = v4l2_ctrl_log_status, | |
332 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, | |
333 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | |
334 | }; | |
335 | ||
336 | static void usb_ma901radio_release(struct v4l2_device *v4l2_dev) | |
337 | { | |
338 | struct ma901radio_device *radio = to_ma901radio_dev(v4l2_dev); | |
339 | ||
340 | v4l2_ctrl_handler_free(&radio->hdl); | |
341 | v4l2_device_unregister(&radio->v4l2_dev); | |
342 | kfree(radio->buffer); | |
343 | kfree(radio); | |
344 | } | |
345 | ||
346 | /* check if the device is present and register with v4l and usb if it is */ | |
347 | static int usb_ma901radio_probe(struct usb_interface *intf, | |
348 | const struct usb_device_id *id) | |
349 | { | |
30b29537 | 350 | struct usb_device *dev = interface_to_usbdev(intf); |
4834f4d1 AK |
351 | struct ma901radio_device *radio; |
352 | int retval = 0; | |
353 | ||
30b29537 AK |
354 | /* Masterkit MA901 usb radio has the same USB ID as many others |
355 | * Atmel V-USB devices. Let's make additional checks to be sure | |
356 | * that this is our device. | |
357 | */ | |
358 | ||
359 | if (dev->product && dev->manufacturer && | |
360 | (strncmp(dev->product, "MA901", 5) != 0 | |
361 | || strncmp(dev->manufacturer, "www.masterkit.ru", 16) != 0)) | |
362 | return -ENODEV; | |
363 | ||
4834f4d1 AK |
364 | radio = kzalloc(sizeof(struct ma901radio_device), GFP_KERNEL); |
365 | if (!radio) { | |
366 | dev_err(&intf->dev, "kzalloc for ma901radio_device failed\n"); | |
367 | retval = -ENOMEM; | |
368 | goto err; | |
369 | } | |
370 | ||
371 | radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL); | |
372 | if (!radio->buffer) { | |
373 | dev_err(&intf->dev, "kmalloc for radio->buffer failed\n"); | |
374 | retval = -ENOMEM; | |
375 | goto err_nobuf; | |
376 | } | |
377 | ||
378 | retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev); | |
379 | if (retval < 0) { | |
380 | dev_err(&intf->dev, "couldn't register v4l2_device\n"); | |
381 | goto err_v4l2; | |
382 | } | |
383 | ||
384 | v4l2_ctrl_handler_init(&radio->hdl, 1); | |
385 | ||
386 | /* TODO:It looks like this radio doesn't have mute/unmute control | |
387 | * and windows program just emulate it using volume control. | |
388 | * Let's plan to do the same in this driver. | |
389 | * | |
390 | * v4l2_ctrl_new_std(&radio->hdl, &usb_ma901radio_ctrl_ops, | |
391 | * V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); | |
392 | */ | |
393 | ||
394 | v4l2_ctrl_new_std(&radio->hdl, &usb_ma901radio_ctrl_ops, | |
395 | V4L2_CID_AUDIO_VOLUME, MA901_VOLUME_MIN, | |
396 | MA901_VOLUME_MAX, 1, MA901_VOLUME_MAX); | |
397 | ||
398 | if (radio->hdl.error) { | |
399 | retval = radio->hdl.error; | |
400 | dev_err(&intf->dev, "couldn't register control\n"); | |
401 | goto err_ctrl; | |
402 | } | |
403 | mutex_init(&radio->lock); | |
404 | ||
405 | radio->v4l2_dev.ctrl_handler = &radio->hdl; | |
406 | radio->v4l2_dev.release = usb_ma901radio_release; | |
407 | strlcpy(radio->vdev.name, radio->v4l2_dev.name, | |
408 | sizeof(radio->vdev.name)); | |
409 | radio->vdev.v4l2_dev = &radio->v4l2_dev; | |
410 | radio->vdev.fops = &usb_ma901radio_fops; | |
411 | radio->vdev.ioctl_ops = &usb_ma901radio_ioctl_ops; | |
412 | radio->vdev.release = video_device_release_empty; | |
413 | radio->vdev.lock = &radio->lock; | |
4834f4d1 AK |
414 | |
415 | radio->usbdev = interface_to_usbdev(intf); | |
416 | radio->intf = intf; | |
417 | usb_set_intfdata(intf, &radio->v4l2_dev); | |
418 | radio->curfreq = 95.21 * FREQ_MUL; | |
419 | ||
420 | video_set_drvdata(&radio->vdev, radio); | |
421 | ||
422 | /* TODO: we can get some statistics (freq, volume) from device | |
423 | * but it's not implemented yet. After insertion in usb-port radio | |
424 | * setups frequency and starts playing without any initialization. | |
425 | * So we don't call usb_ma901radio_init/get_stat() here. | |
426 | * retval = usb_ma901radio_init(radio); | |
427 | */ | |
428 | ||
429 | retval = video_register_device(&radio->vdev, VFL_TYPE_RADIO, | |
430 | radio_nr); | |
431 | if (retval < 0) { | |
432 | dev_err(&intf->dev, "could not register video device\n"); | |
433 | goto err_vdev; | |
434 | } | |
435 | ||
436 | return 0; | |
437 | ||
438 | err_vdev: | |
439 | v4l2_ctrl_handler_free(&radio->hdl); | |
440 | err_ctrl: | |
441 | v4l2_device_unregister(&radio->v4l2_dev); | |
442 | err_v4l2: | |
443 | kfree(radio->buffer); | |
444 | err_nobuf: | |
445 | kfree(radio); | |
446 | err: | |
447 | return retval; | |
448 | } | |
449 | ||
450 | /* USB Device ID List */ | |
451 | static struct usb_device_id usb_ma901radio_device_table[] = { | |
452 | { USB_DEVICE_AND_INTERFACE_INFO(USB_MA901_VENDOR, USB_MA901_PRODUCT, | |
453 | USB_CLASS_HID, 0, 0) }, | |
454 | { } /* Terminating entry */ | |
455 | }; | |
456 | ||
457 | MODULE_DEVICE_TABLE(usb, usb_ma901radio_device_table); | |
458 | ||
459 | /* USB subsystem interface */ | |
460 | static struct usb_driver usb_ma901radio_driver = { | |
461 | .name = MA901_DRIVER_NAME, | |
462 | .probe = usb_ma901radio_probe, | |
463 | .disconnect = usb_ma901radio_disconnect, | |
464 | .suspend = usb_ma901radio_suspend, | |
465 | .resume = usb_ma901radio_resume, | |
466 | .reset_resume = usb_ma901radio_resume, | |
467 | .id_table = usb_ma901radio_device_table, | |
468 | }; | |
469 | ||
470 | module_usb_driver(usb_ma901radio_driver); |