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