1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * ALSA Driver for Ego Systems Inc. (ESI) Miditerminal 4140 |
4 | * Copyright (c) 2006 by Matthias König <mk@phasorlab.de> |
5 | */ |
6 | |
7 | #include <linux/init.h> |
8 | #include <linux/platform_device.h> |
9 | #include <linux/parport.h> |
10 | #include <linux/spinlock.h> |
11 | #include <linux/module.h> |
12 | #include <linux/delay.h> |
13 | #include <linux/slab.h> |
14 | #include <sound/core.h> |
15 | #include <sound/initval.h> |
16 | #include <sound/rawmidi.h> |
17 | #include <sound/control.h> |
18 | |
19 | #define CARD_NAME "Miditerminal 4140" |
20 | #define DRIVER_NAME "MTS64" |
21 | #define PLATFORM_DRIVER "snd_mts64" |
22 | |
23 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; |
24 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; |
25 | static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; |
26 | |
27 | static struct platform_device *platform_devices[SNDRV_CARDS]; |
28 | static int device_count; |
29 | |
30 | module_param_array(index, int, NULL, 0444); |
31 | MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard." ); |
32 | module_param_array(id, charp, NULL, 0444); |
33 | MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard." ); |
34 | module_param_array(enable, bool, NULL, 0444); |
35 | MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard." ); |
36 | |
37 | MODULE_AUTHOR("Matthias Koenig <mk@phasorlab.de>" ); |
38 | MODULE_DESCRIPTION("ESI Miditerminal 4140" ); |
39 | MODULE_LICENSE("GPL" ); |
40 | |
41 | /********************************************************************* |
42 | * Chip specific |
43 | *********************************************************************/ |
44 | #define MTS64_NUM_INPUT_PORTS 5 |
45 | #define MTS64_NUM_OUTPUT_PORTS 4 |
46 | #define MTS64_SMPTE_SUBSTREAM 4 |
47 | |
48 | struct mts64 { |
49 | spinlock_t lock; |
50 | struct snd_card *card; |
51 | struct snd_rawmidi *rmidi; |
52 | struct pardevice *pardev; |
53 | int open_count; |
54 | int current_midi_output_port; |
55 | int current_midi_input_port; |
56 | u8 mode[MTS64_NUM_INPUT_PORTS]; |
57 | struct snd_rawmidi_substream *midi_input_substream[MTS64_NUM_INPUT_PORTS]; |
58 | int smpte_switch; |
59 | u8 time[4]; /* [0]=hh, [1]=mm, [2]=ss, [3]=ff */ |
60 | u8 fps; |
61 | }; |
62 | |
63 | static int snd_mts64_free(struct mts64 *mts) |
64 | { |
65 | kfree(objp: mts); |
66 | return 0; |
67 | } |
68 | |
69 | static int snd_mts64_create(struct snd_card *card, |
70 | struct pardevice *pardev, |
71 | struct mts64 **rchip) |
72 | { |
73 | struct mts64 *mts; |
74 | |
75 | *rchip = NULL; |
76 | |
77 | mts = kzalloc(size: sizeof(struct mts64), GFP_KERNEL); |
78 | if (mts == NULL) |
79 | return -ENOMEM; |
80 | |
81 | /* Init chip specific data */ |
82 | spin_lock_init(&mts->lock); |
83 | mts->card = card; |
84 | mts->pardev = pardev; |
85 | mts->current_midi_output_port = -1; |
86 | mts->current_midi_input_port = -1; |
87 | |
88 | *rchip = mts; |
89 | |
90 | return 0; |
91 | } |
92 | |
93 | /********************************************************************* |
94 | * HW register related constants |
95 | *********************************************************************/ |
96 | |
97 | /* Status Bits */ |
98 | #define MTS64_STAT_BSY 0x80 |
99 | #define MTS64_STAT_BIT_SET 0x20 /* readout process, bit is set */ |
100 | #define MTS64_STAT_PORT 0x10 /* read byte is a port number */ |
101 | |
102 | /* Control Bits */ |
103 | #define MTS64_CTL_READOUT 0x08 /* enable readout */ |
104 | #define MTS64_CTL_WRITE_CMD 0x06 |
105 | #define MTS64_CTL_WRITE_DATA 0x02 |
106 | #define MTS64_CTL_STROBE 0x01 |
107 | |
108 | /* Command */ |
109 | #define MTS64_CMD_RESET 0xfe |
110 | #define MTS64_CMD_PROBE 0x8f /* Used in probing procedure */ |
111 | #define MTS64_CMD_SMPTE_SET_TIME 0xe8 |
112 | #define MTS64_CMD_SMPTE_SET_FPS 0xee |
113 | #define MTS64_CMD_SMPTE_STOP 0xef |
114 | #define MTS64_CMD_SMPTE_FPS_24 0xe3 |
115 | #define MTS64_CMD_SMPTE_FPS_25 0xe2 |
116 | #define MTS64_CMD_SMPTE_FPS_2997 0xe4 |
117 | #define MTS64_CMD_SMPTE_FPS_30D 0xe1 |
118 | #define MTS64_CMD_SMPTE_FPS_30 0xe0 |
119 | #define MTS64_CMD_COM_OPEN 0xf8 /* setting the communication mode */ |
120 | #define MTS64_CMD_COM_CLOSE1 0xff /* clearing communication mode */ |
121 | #define MTS64_CMD_COM_CLOSE2 0xf5 |
122 | |
123 | /********************************************************************* |
124 | * Hardware specific functions |
125 | *********************************************************************/ |
126 | static void mts64_enable_readout(struct parport *p); |
127 | static void mts64_disable_readout(struct parport *p); |
128 | static int mts64_device_ready(struct parport *p); |
129 | static int mts64_device_init(struct parport *p); |
130 | static int mts64_device_open(struct mts64 *mts); |
131 | static int mts64_device_close(struct mts64 *mts); |
132 | static u8 mts64_map_midi_input(u8 c); |
133 | static int mts64_probe(struct parport *p); |
134 | static u16 mts64_read(struct parport *p); |
135 | static u8 mts64_read_char(struct parport *p); |
136 | static void mts64_smpte_start(struct parport *p, |
137 | u8 hours, u8 minutes, |
138 | u8 seconds, u8 frames, |
139 | u8 idx); |
140 | static void mts64_smpte_stop(struct parport *p); |
141 | static void mts64_write_command(struct parport *p, u8 c); |
142 | static void mts64_write_data(struct parport *p, u8 c); |
143 | static void mts64_write_midi(struct mts64 *mts, u8 c, int midiport); |
144 | |
145 | |
146 | /* Enables the readout procedure |
147 | * |
148 | * Before we can read a midi byte from the device, we have to set |
149 | * bit 3 of control port. |
150 | */ |
151 | static void mts64_enable_readout(struct parport *p) |
152 | { |
153 | u8 c; |
154 | |
155 | c = parport_read_control(p); |
156 | c |= MTS64_CTL_READOUT; |
157 | parport_write_control(p, c); |
158 | } |
159 | |
160 | /* Disables readout |
161 | * |
162 | * Readout is disabled by clearing bit 3 of control |
163 | */ |
164 | static void mts64_disable_readout(struct parport *p) |
165 | { |
166 | u8 c; |
167 | |
168 | c = parport_read_control(p); |
169 | c &= ~MTS64_CTL_READOUT; |
170 | parport_write_control(p, c); |
171 | } |
172 | |
173 | /* waits for device ready |
174 | * |
175 | * Checks if BUSY (Bit 7 of status) is clear |
176 | * 1 device ready |
177 | * 0 failure |
178 | */ |
179 | static int mts64_device_ready(struct parport *p) |
180 | { |
181 | int i; |
182 | u8 c; |
183 | |
184 | for (i = 0; i < 0xffff; ++i) { |
185 | c = parport_read_status(p); |
186 | c &= MTS64_STAT_BSY; |
187 | if (c != 0) |
188 | return 1; |
189 | } |
190 | |
191 | return 0; |
192 | } |
193 | |
194 | /* Init device (LED blinking startup magic) |
195 | * |
196 | * Returns: |
197 | * 0 init ok |
198 | * -EIO failure |
199 | */ |
200 | static int mts64_device_init(struct parport *p) |
201 | { |
202 | int i; |
203 | |
204 | mts64_write_command(p, MTS64_CMD_RESET); |
205 | |
206 | for (i = 0; i < 64; ++i) { |
207 | msleep(msecs: 100); |
208 | |
209 | if (mts64_probe(p) == 0) { |
210 | /* success */ |
211 | mts64_disable_readout(p); |
212 | return 0; |
213 | } |
214 | } |
215 | mts64_disable_readout(p); |
216 | |
217 | return -EIO; |
218 | } |
219 | |
220 | /* |
221 | * Opens the device (set communication mode) |
222 | */ |
223 | static int mts64_device_open(struct mts64 *mts) |
224 | { |
225 | int i; |
226 | struct parport *p = mts->pardev->port; |
227 | |
228 | for (i = 0; i < 5; ++i) |
229 | mts64_write_command(p, MTS64_CMD_COM_OPEN); |
230 | |
231 | return 0; |
232 | } |
233 | |
234 | /* |
235 | * Close device (clear communication mode) |
236 | */ |
237 | static int mts64_device_close(struct mts64 *mts) |
238 | { |
239 | int i; |
240 | struct parport *p = mts->pardev->port; |
241 | |
242 | for (i = 0; i < 5; ++i) { |
243 | mts64_write_command(p, MTS64_CMD_COM_CLOSE1); |
244 | mts64_write_command(p, MTS64_CMD_COM_CLOSE2); |
245 | } |
246 | |
247 | return 0; |
248 | } |
249 | |
250 | /* map hardware port to substream number |
251 | * |
252 | * When reading a byte from the device, the device tells us |
253 | * on what port the byte is. This HW port has to be mapped to |
254 | * the midiport (substream number). |
255 | * substream 0-3 are Midiports 1-4 |
256 | * substream 4 is SMPTE Timecode |
257 | * The mapping is done by the table: |
258 | * HW | 0 | 1 | 2 | 3 | 4 |
259 | * SW | 0 | 1 | 4 | 2 | 3 |
260 | */ |
261 | static u8 mts64_map_midi_input(u8 c) |
262 | { |
263 | static const u8 map[] = { 0, 1, 4, 2, 3 }; |
264 | |
265 | return map[c]; |
266 | } |
267 | |
268 | |
269 | /* Probe parport for device |
270 | * |
271 | * Do we have a Miditerminal 4140 on parport? |
272 | * Returns: |
273 | * 0 device found |
274 | * -ENODEV no device |
275 | */ |
276 | static int mts64_probe(struct parport *p) |
277 | { |
278 | u8 c; |
279 | |
280 | mts64_smpte_stop(p); |
281 | mts64_write_command(p, MTS64_CMD_PROBE); |
282 | |
283 | msleep(msecs: 50); |
284 | |
285 | c = mts64_read(p); |
286 | |
287 | c &= 0x00ff; |
288 | if (c != MTS64_CMD_PROBE) |
289 | return -ENODEV; |
290 | else |
291 | return 0; |
292 | |
293 | } |
294 | |
295 | /* Read byte incl. status from device |
296 | * |
297 | * Returns: |
298 | * data in lower 8 bits and status in upper 8 bits |
299 | */ |
300 | static u16 mts64_read(struct parport *p) |
301 | { |
302 | u8 data, status; |
303 | |
304 | mts64_device_ready(p); |
305 | mts64_enable_readout(p); |
306 | status = parport_read_status(p); |
307 | data = mts64_read_char(p); |
308 | mts64_disable_readout(p); |
309 | |
310 | return (status << 8) | data; |
311 | } |
312 | |
313 | /* Read a byte from device |
314 | * |
315 | * Note, that readout mode has to be enabled. |
316 | * readout procedure is as follows: |
317 | * - Write number of the Bit to read to DATA |
318 | * - Read STATUS |
319 | * - Bit 5 of STATUS indicates if Bit is set |
320 | * |
321 | * Returns: |
322 | * Byte read from device |
323 | */ |
324 | static u8 mts64_read_char(struct parport *p) |
325 | { |
326 | u8 c = 0; |
327 | u8 status; |
328 | u8 i; |
329 | |
330 | for (i = 0; i < 8; ++i) { |
331 | parport_write_data(p, i); |
332 | c >>= 1; |
333 | status = parport_read_status(p); |
334 | if (status & MTS64_STAT_BIT_SET) |
335 | c |= 0x80; |
336 | } |
337 | |
338 | return c; |
339 | } |
340 | |
341 | /* Starts SMPTE Timecode generation |
342 | * |
343 | * The device creates SMPTE Timecode by hardware. |
344 | * 0 24 fps |
345 | * 1 25 fps |
346 | * 2 29.97 fps |
347 | * 3 30 fps (Drop-frame) |
348 | * 4 30 fps |
349 | */ |
350 | static void mts64_smpte_start(struct parport *p, |
351 | u8 hours, u8 minutes, |
352 | u8 seconds, u8 frames, |
353 | u8 idx) |
354 | { |
355 | static const u8 fps[5] = { MTS64_CMD_SMPTE_FPS_24, |
356 | MTS64_CMD_SMPTE_FPS_25, |
357 | MTS64_CMD_SMPTE_FPS_2997, |
358 | MTS64_CMD_SMPTE_FPS_30D, |
359 | MTS64_CMD_SMPTE_FPS_30 }; |
360 | |
361 | mts64_write_command(p, MTS64_CMD_SMPTE_SET_TIME); |
362 | mts64_write_command(p, c: frames); |
363 | mts64_write_command(p, c: seconds); |
364 | mts64_write_command(p, c: minutes); |
365 | mts64_write_command(p, c: hours); |
366 | |
367 | mts64_write_command(p, MTS64_CMD_SMPTE_SET_FPS); |
368 | mts64_write_command(p, c: fps[idx]); |
369 | } |
370 | |
371 | /* Stops SMPTE Timecode generation |
372 | */ |
373 | static void mts64_smpte_stop(struct parport *p) |
374 | { |
375 | mts64_write_command(p, MTS64_CMD_SMPTE_STOP); |
376 | } |
377 | |
378 | /* Write a command byte to device |
379 | */ |
380 | static void mts64_write_command(struct parport *p, u8 c) |
381 | { |
382 | mts64_device_ready(p); |
383 | |
384 | parport_write_data(p, c); |
385 | |
386 | parport_write_control(p, MTS64_CTL_WRITE_CMD); |
387 | parport_write_control(p, MTS64_CTL_WRITE_CMD | MTS64_CTL_STROBE); |
388 | parport_write_control(p, MTS64_CTL_WRITE_CMD); |
389 | } |
390 | |
391 | /* Write a data byte to device |
392 | */ |
393 | static void mts64_write_data(struct parport *p, u8 c) |
394 | { |
395 | mts64_device_ready(p); |
396 | |
397 | parport_write_data(p, c); |
398 | |
399 | parport_write_control(p, MTS64_CTL_WRITE_DATA); |
400 | parport_write_control(p, MTS64_CTL_WRITE_DATA | MTS64_CTL_STROBE); |
401 | parport_write_control(p, MTS64_CTL_WRITE_DATA); |
402 | } |
403 | |
404 | /* Write a MIDI byte to midiport |
405 | * |
406 | * midiport ranges from 0-3 and maps to Ports 1-4 |
407 | * assumptions: communication mode is on |
408 | */ |
409 | static void mts64_write_midi(struct mts64 *mts, u8 c, |
410 | int midiport) |
411 | { |
412 | struct parport *p = mts->pardev->port; |
413 | |
414 | /* check current midiport */ |
415 | if (mts->current_midi_output_port != midiport) |
416 | mts64_write_command(p, c: midiport); |
417 | |
418 | /* write midi byte */ |
419 | mts64_write_data(p, c); |
420 | } |
421 | |
422 | /********************************************************************* |
423 | * Control elements |
424 | *********************************************************************/ |
425 | |
426 | /* SMPTE Switch */ |
427 | #define snd_mts64_ctl_smpte_switch_info snd_ctl_boolean_mono_info |
428 | |
429 | static int snd_mts64_ctl_smpte_switch_get(struct snd_kcontrol* kctl, |
430 | struct snd_ctl_elem_value *uctl) |
431 | { |
432 | struct mts64 *mts = snd_kcontrol_chip(kctl); |
433 | |
434 | spin_lock_irq(lock: &mts->lock); |
435 | uctl->value.integer.value[0] = mts->smpte_switch; |
436 | spin_unlock_irq(lock: &mts->lock); |
437 | |
438 | return 0; |
439 | } |
440 | |
441 | /* smpte_switch is not accessed from IRQ handler, so we just need |
442 | to protect the HW access */ |
443 | static int snd_mts64_ctl_smpte_switch_put(struct snd_kcontrol* kctl, |
444 | struct snd_ctl_elem_value *uctl) |
445 | { |
446 | struct mts64 *mts = snd_kcontrol_chip(kctl); |
447 | int changed = 0; |
448 | int val = !!uctl->value.integer.value[0]; |
449 | |
450 | spin_lock_irq(lock: &mts->lock); |
451 | if (mts->smpte_switch == val) |
452 | goto __out; |
453 | |
454 | changed = 1; |
455 | mts->smpte_switch = val; |
456 | if (mts->smpte_switch) { |
457 | mts64_smpte_start(p: mts->pardev->port, |
458 | hours: mts->time[0], minutes: mts->time[1], |
459 | seconds: mts->time[2], frames: mts->time[3], |
460 | idx: mts->fps); |
461 | } else { |
462 | mts64_smpte_stop(p: mts->pardev->port); |
463 | } |
464 | __out: |
465 | spin_unlock_irq(lock: &mts->lock); |
466 | return changed; |
467 | } |
468 | |
469 | static const struct snd_kcontrol_new mts64_ctl_smpte_switch = { |
470 | .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI, |
471 | .name = "SMPTE Playback Switch" , |
472 | .index = 0, |
473 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, |
474 | .private_value = 0, |
475 | .info = snd_mts64_ctl_smpte_switch_info, |
476 | .get = snd_mts64_ctl_smpte_switch_get, |
477 | .put = snd_mts64_ctl_smpte_switch_put |
478 | }; |
479 | |
480 | /* Time */ |
481 | static int snd_mts64_ctl_smpte_time_h_info(struct snd_kcontrol *kctl, |
482 | struct snd_ctl_elem_info *uinfo) |
483 | { |
484 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
485 | uinfo->count = 1; |
486 | uinfo->value.integer.min = 0; |
487 | uinfo->value.integer.max = 23; |
488 | return 0; |
489 | } |
490 | |
491 | static int snd_mts64_ctl_smpte_time_f_info(struct snd_kcontrol *kctl, |
492 | struct snd_ctl_elem_info *uinfo) |
493 | { |
494 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
495 | uinfo->count = 1; |
496 | uinfo->value.integer.min = 0; |
497 | uinfo->value.integer.max = 99; |
498 | return 0; |
499 | } |
500 | |
501 | static int snd_mts64_ctl_smpte_time_info(struct snd_kcontrol *kctl, |
502 | struct snd_ctl_elem_info *uinfo) |
503 | { |
504 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
505 | uinfo->count = 1; |
506 | uinfo->value.integer.min = 0; |
507 | uinfo->value.integer.max = 59; |
508 | return 0; |
509 | } |
510 | |
511 | static int snd_mts64_ctl_smpte_time_get(struct snd_kcontrol *kctl, |
512 | struct snd_ctl_elem_value *uctl) |
513 | { |
514 | struct mts64 *mts = snd_kcontrol_chip(kctl); |
515 | int idx = kctl->private_value; |
516 | |
517 | spin_lock_irq(lock: &mts->lock); |
518 | uctl->value.integer.value[0] = mts->time[idx]; |
519 | spin_unlock_irq(lock: &mts->lock); |
520 | |
521 | return 0; |
522 | } |
523 | |
524 | static int snd_mts64_ctl_smpte_time_put(struct snd_kcontrol *kctl, |
525 | struct snd_ctl_elem_value *uctl) |
526 | { |
527 | struct mts64 *mts = snd_kcontrol_chip(kctl); |
528 | int idx = kctl->private_value; |
529 | unsigned int time = uctl->value.integer.value[0] % 60; |
530 | int changed = 0; |
531 | |
532 | spin_lock_irq(lock: &mts->lock); |
533 | if (mts->time[idx] != time) { |
534 | changed = 1; |
535 | mts->time[idx] = time; |
536 | } |
537 | spin_unlock_irq(lock: &mts->lock); |
538 | |
539 | return changed; |
540 | } |
541 | |
542 | static const struct snd_kcontrol_new mts64_ctl_smpte_time_hours = { |
543 | .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI, |
544 | .name = "SMPTE Time Hours" , |
545 | .index = 0, |
546 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, |
547 | .private_value = 0, |
548 | .info = snd_mts64_ctl_smpte_time_h_info, |
549 | .get = snd_mts64_ctl_smpte_time_get, |
550 | .put = snd_mts64_ctl_smpte_time_put |
551 | }; |
552 | |
553 | static const struct snd_kcontrol_new mts64_ctl_smpte_time_minutes = { |
554 | .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI, |
555 | .name = "SMPTE Time Minutes" , |
556 | .index = 0, |
557 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, |
558 | .private_value = 1, |
559 | .info = snd_mts64_ctl_smpte_time_info, |
560 | .get = snd_mts64_ctl_smpte_time_get, |
561 | .put = snd_mts64_ctl_smpte_time_put |
562 | }; |
563 | |
564 | static const struct snd_kcontrol_new mts64_ctl_smpte_time_seconds = { |
565 | .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI, |
566 | .name = "SMPTE Time Seconds" , |
567 | .index = 0, |
568 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, |
569 | .private_value = 2, |
570 | .info = snd_mts64_ctl_smpte_time_info, |
571 | .get = snd_mts64_ctl_smpte_time_get, |
572 | .put = snd_mts64_ctl_smpte_time_put |
573 | }; |
574 | |
575 | static const struct snd_kcontrol_new mts64_ctl_smpte_time_frames = { |
576 | .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI, |
577 | .name = "SMPTE Time Frames" , |
578 | .index = 0, |
579 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, |
580 | .private_value = 3, |
581 | .info = snd_mts64_ctl_smpte_time_f_info, |
582 | .get = snd_mts64_ctl_smpte_time_get, |
583 | .put = snd_mts64_ctl_smpte_time_put |
584 | }; |
585 | |
586 | /* FPS */ |
587 | static int snd_mts64_ctl_smpte_fps_info(struct snd_kcontrol *kctl, |
588 | struct snd_ctl_elem_info *uinfo) |
589 | { |
590 | static const char * const texts[5] = { |
591 | "24" , "25" , "29.97" , "30D" , "30" |
592 | }; |
593 | |
594 | return snd_ctl_enum_info(info: uinfo, channels: 1, items: 5, names: texts); |
595 | } |
596 | |
597 | static int snd_mts64_ctl_smpte_fps_get(struct snd_kcontrol *kctl, |
598 | struct snd_ctl_elem_value *uctl) |
599 | { |
600 | struct mts64 *mts = snd_kcontrol_chip(kctl); |
601 | |
602 | spin_lock_irq(lock: &mts->lock); |
603 | uctl->value.enumerated.item[0] = mts->fps; |
604 | spin_unlock_irq(lock: &mts->lock); |
605 | |
606 | return 0; |
607 | } |
608 | |
609 | static int snd_mts64_ctl_smpte_fps_put(struct snd_kcontrol *kctl, |
610 | struct snd_ctl_elem_value *uctl) |
611 | { |
612 | struct mts64 *mts = snd_kcontrol_chip(kctl); |
613 | int changed = 0; |
614 | |
615 | if (uctl->value.enumerated.item[0] >= 5) |
616 | return -EINVAL; |
617 | spin_lock_irq(lock: &mts->lock); |
618 | if (mts->fps != uctl->value.enumerated.item[0]) { |
619 | changed = 1; |
620 | mts->fps = uctl->value.enumerated.item[0]; |
621 | } |
622 | spin_unlock_irq(lock: &mts->lock); |
623 | |
624 | return changed; |
625 | } |
626 | |
627 | static const struct snd_kcontrol_new mts64_ctl_smpte_fps = { |
628 | .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI, |
629 | .name = "SMPTE Fps" , |
630 | .index = 0, |
631 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, |
632 | .private_value = 0, |
633 | .info = snd_mts64_ctl_smpte_fps_info, |
634 | .get = snd_mts64_ctl_smpte_fps_get, |
635 | .put = snd_mts64_ctl_smpte_fps_put |
636 | }; |
637 | |
638 | |
639 | static int snd_mts64_ctl_create(struct snd_card *card, |
640 | struct mts64 *mts) |
641 | { |
642 | int err, i; |
643 | static const struct snd_kcontrol_new *control[] = { |
644 | &mts64_ctl_smpte_switch, |
645 | &mts64_ctl_smpte_time_hours, |
646 | &mts64_ctl_smpte_time_minutes, |
647 | &mts64_ctl_smpte_time_seconds, |
648 | &mts64_ctl_smpte_time_frames, |
649 | &mts64_ctl_smpte_fps, |
650 | NULL }; |
651 | |
652 | for (i = 0; control[i]; ++i) { |
653 | err = snd_ctl_add(card, kcontrol: snd_ctl_new1(kcontrolnew: control[i], private_data: mts)); |
654 | if (err < 0) { |
655 | snd_printd("Cannot create control: %s\n" , |
656 | control[i]->name); |
657 | return err; |
658 | } |
659 | } |
660 | |
661 | return 0; |
662 | } |
663 | |
664 | /********************************************************************* |
665 | * Rawmidi |
666 | *********************************************************************/ |
667 | #define MTS64_MODE_INPUT_TRIGGERED 0x01 |
668 | |
669 | static int snd_mts64_rawmidi_open(struct snd_rawmidi_substream *substream) |
670 | { |
671 | struct mts64 *mts = substream->rmidi->private_data; |
672 | |
673 | if (mts->open_count == 0) { |
674 | /* We don't need a spinlock here, because this is just called |
675 | if the device has not been opened before. |
676 | So there aren't any IRQs from the device */ |
677 | mts64_device_open(mts); |
678 | |
679 | msleep(msecs: 50); |
680 | } |
681 | ++(mts->open_count); |
682 | |
683 | return 0; |
684 | } |
685 | |
686 | static int snd_mts64_rawmidi_close(struct snd_rawmidi_substream *substream) |
687 | { |
688 | struct mts64 *mts = substream->rmidi->private_data; |
689 | unsigned long flags; |
690 | |
691 | --(mts->open_count); |
692 | if (mts->open_count == 0) { |
693 | /* We need the spinlock_irqsave here because we can still |
694 | have IRQs at this point */ |
695 | spin_lock_irqsave(&mts->lock, flags); |
696 | mts64_device_close(mts); |
697 | spin_unlock_irqrestore(lock: &mts->lock, flags); |
698 | |
699 | msleep(msecs: 500); |
700 | |
701 | } else if (mts->open_count < 0) |
702 | mts->open_count = 0; |
703 | |
704 | return 0; |
705 | } |
706 | |
707 | static void snd_mts64_rawmidi_output_trigger(struct snd_rawmidi_substream *substream, |
708 | int up) |
709 | { |
710 | struct mts64 *mts = substream->rmidi->private_data; |
711 | u8 data; |
712 | unsigned long flags; |
713 | |
714 | spin_lock_irqsave(&mts->lock, flags); |
715 | while (snd_rawmidi_transmit_peek(substream, buffer: &data, count: 1) == 1) { |
716 | mts64_write_midi(mts, c: data, midiport: substream->number+1); |
717 | snd_rawmidi_transmit_ack(substream, count: 1); |
718 | } |
719 | spin_unlock_irqrestore(lock: &mts->lock, flags); |
720 | } |
721 | |
722 | static void snd_mts64_rawmidi_input_trigger(struct snd_rawmidi_substream *substream, |
723 | int up) |
724 | { |
725 | struct mts64 *mts = substream->rmidi->private_data; |
726 | unsigned long flags; |
727 | |
728 | spin_lock_irqsave(&mts->lock, flags); |
729 | if (up) |
730 | mts->mode[substream->number] |= MTS64_MODE_INPUT_TRIGGERED; |
731 | else |
732 | mts->mode[substream->number] &= ~MTS64_MODE_INPUT_TRIGGERED; |
733 | |
734 | spin_unlock_irqrestore(lock: &mts->lock, flags); |
735 | } |
736 | |
737 | static const struct snd_rawmidi_ops snd_mts64_rawmidi_output_ops = { |
738 | .open = snd_mts64_rawmidi_open, |
739 | .close = snd_mts64_rawmidi_close, |
740 | .trigger = snd_mts64_rawmidi_output_trigger |
741 | }; |
742 | |
743 | static const struct snd_rawmidi_ops snd_mts64_rawmidi_input_ops = { |
744 | .open = snd_mts64_rawmidi_open, |
745 | .close = snd_mts64_rawmidi_close, |
746 | .trigger = snd_mts64_rawmidi_input_trigger |
747 | }; |
748 | |
749 | /* Create and initialize the rawmidi component */ |
750 | static int snd_mts64_rawmidi_create(struct snd_card *card) |
751 | { |
752 | struct mts64 *mts = card->private_data; |
753 | struct snd_rawmidi *rmidi; |
754 | struct snd_rawmidi_substream *substream; |
755 | struct list_head *list; |
756 | int err; |
757 | |
758 | err = snd_rawmidi_new(card, CARD_NAME, device: 0, |
759 | MTS64_NUM_OUTPUT_PORTS, |
760 | MTS64_NUM_INPUT_PORTS, |
761 | rmidi: &rmidi); |
762 | if (err < 0) |
763 | return err; |
764 | |
765 | rmidi->private_data = mts; |
766 | strcpy(p: rmidi->name, CARD_NAME); |
767 | rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | |
768 | SNDRV_RAWMIDI_INFO_INPUT | |
769 | SNDRV_RAWMIDI_INFO_DUPLEX; |
770 | |
771 | mts->rmidi = rmidi; |
772 | |
773 | /* register rawmidi ops */ |
774 | snd_rawmidi_set_ops(rmidi, stream: SNDRV_RAWMIDI_STREAM_OUTPUT, |
775 | ops: &snd_mts64_rawmidi_output_ops); |
776 | snd_rawmidi_set_ops(rmidi, stream: SNDRV_RAWMIDI_STREAM_INPUT, |
777 | ops: &snd_mts64_rawmidi_input_ops); |
778 | |
779 | /* name substreams */ |
780 | /* output */ |
781 | list_for_each(list, |
782 | &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams) { |
783 | substream = list_entry(list, struct snd_rawmidi_substream, list); |
784 | sprintf(buf: substream->name, |
785 | fmt: "Miditerminal %d" , substream->number+1); |
786 | } |
787 | /* input */ |
788 | list_for_each(list, |
789 | &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams) { |
790 | substream = list_entry(list, struct snd_rawmidi_substream, list); |
791 | mts->midi_input_substream[substream->number] = substream; |
792 | switch(substream->number) { |
793 | case MTS64_SMPTE_SUBSTREAM: |
794 | strcpy(p: substream->name, q: "Miditerminal SMPTE" ); |
795 | break; |
796 | default: |
797 | sprintf(buf: substream->name, |
798 | fmt: "Miditerminal %d" , substream->number+1); |
799 | } |
800 | } |
801 | |
802 | /* controls */ |
803 | err = snd_mts64_ctl_create(card, mts); |
804 | |
805 | return err; |
806 | } |
807 | |
808 | /********************************************************************* |
809 | * parport stuff |
810 | *********************************************************************/ |
811 | static void snd_mts64_interrupt(void *private) |
812 | { |
813 | struct mts64 *mts = ((struct snd_card*)private)->private_data; |
814 | u16 ret; |
815 | u8 status, data; |
816 | struct snd_rawmidi_substream *substream; |
817 | |
818 | if (!mts) |
819 | return; |
820 | |
821 | spin_lock(lock: &mts->lock); |
822 | ret = mts64_read(p: mts->pardev->port); |
823 | data = ret & 0x00ff; |
824 | status = ret >> 8; |
825 | |
826 | if (status & MTS64_STAT_PORT) { |
827 | mts->current_midi_input_port = mts64_map_midi_input(c: data); |
828 | } else { |
829 | if (mts->current_midi_input_port == -1) |
830 | goto __out; |
831 | substream = mts->midi_input_substream[mts->current_midi_input_port]; |
832 | if (mts->mode[substream->number] & MTS64_MODE_INPUT_TRIGGERED) |
833 | snd_rawmidi_receive(substream, buffer: &data, count: 1); |
834 | } |
835 | __out: |
836 | spin_unlock(lock: &mts->lock); |
837 | } |
838 | |
839 | static void snd_mts64_attach(struct parport *p) |
840 | { |
841 | struct platform_device *device; |
842 | |
843 | device = platform_device_alloc(PLATFORM_DRIVER, id: device_count); |
844 | if (!device) |
845 | return; |
846 | |
847 | /* Temporary assignment to forward the parport */ |
848 | platform_set_drvdata(pdev: device, data: p); |
849 | |
850 | if (platform_device_add(pdev: device) < 0) { |
851 | platform_device_put(pdev: device); |
852 | return; |
853 | } |
854 | |
855 | /* Since we dont get the return value of probe |
856 | * We need to check if device probing succeeded or not */ |
857 | if (!platform_get_drvdata(pdev: device)) { |
858 | platform_device_unregister(device); |
859 | return; |
860 | } |
861 | |
862 | /* register device in global table */ |
863 | platform_devices[device_count] = device; |
864 | device_count++; |
865 | } |
866 | |
867 | static void snd_mts64_detach(struct parport *p) |
868 | { |
869 | /* nothing to do here */ |
870 | } |
871 | |
872 | static int snd_mts64_dev_probe(struct pardevice *pardev) |
873 | { |
874 | if (strcmp(pardev->name, DRIVER_NAME)) |
875 | return -ENODEV; |
876 | |
877 | return 0; |
878 | } |
879 | |
880 | static struct parport_driver mts64_parport_driver = { |
881 | .name = "mts64" , |
882 | .probe = snd_mts64_dev_probe, |
883 | .match_port = snd_mts64_attach, |
884 | .detach = snd_mts64_detach, |
885 | .devmodel = true, |
886 | }; |
887 | |
888 | /********************************************************************* |
889 | * platform stuff |
890 | *********************************************************************/ |
891 | static void snd_mts64_card_private_free(struct snd_card *card) |
892 | { |
893 | struct mts64 *mts = card->private_data; |
894 | struct pardevice *pardev = mts->pardev; |
895 | |
896 | if (pardev) { |
897 | parport_release(dev: pardev); |
898 | parport_unregister_device(dev: pardev); |
899 | } |
900 | |
901 | snd_mts64_free(mts); |
902 | } |
903 | |
904 | static int snd_mts64_probe(struct platform_device *pdev) |
905 | { |
906 | struct pardevice *pardev; |
907 | struct parport *p; |
908 | int dev = pdev->id; |
909 | struct snd_card *card = NULL; |
910 | struct mts64 *mts = NULL; |
911 | int err; |
912 | struct pardev_cb mts64_cb = { |
913 | .preempt = NULL, |
914 | .wakeup = NULL, |
915 | .irq_func = snd_mts64_interrupt, /* ISR */ |
916 | .flags = PARPORT_DEV_EXCL, /* flags */ |
917 | }; |
918 | |
919 | p = platform_get_drvdata(pdev); |
920 | platform_set_drvdata(pdev, NULL); |
921 | |
922 | if (dev >= SNDRV_CARDS) |
923 | return -ENODEV; |
924 | if (!enable[dev]) |
925 | return -ENOENT; |
926 | |
927 | err = snd_card_new(parent: &pdev->dev, idx: index[dev], xid: id[dev], THIS_MODULE, |
928 | extra_size: 0, card_ret: &card); |
929 | if (err < 0) { |
930 | snd_printd("Cannot create card\n" ); |
931 | return err; |
932 | } |
933 | strcpy(p: card->driver, DRIVER_NAME); |
934 | strcpy(p: card->shortname, q: "ESI " CARD_NAME); |
935 | sprintf(buf: card->longname, fmt: "%s at 0x%lx, irq %i" , |
936 | card->shortname, p->base, p->irq); |
937 | |
938 | mts64_cb.private = card; /* private */ |
939 | pardev = parport_register_dev_model(port: p, /* port */ |
940 | DRIVER_NAME, /* name */ |
941 | par_dev_cb: &mts64_cb, /* callbacks */ |
942 | cnt: pdev->id); /* device number */ |
943 | if (!pardev) { |
944 | snd_printd("Cannot register pardevice\n" ); |
945 | err = -EIO; |
946 | goto __err; |
947 | } |
948 | |
949 | /* claim parport */ |
950 | if (parport_claim(dev: pardev)) { |
951 | snd_printd("Cannot claim parport 0x%lx\n" , pardev->port->base); |
952 | err = -EIO; |
953 | goto free_pardev; |
954 | } |
955 | |
956 | err = snd_mts64_create(card, pardev, rchip: &mts); |
957 | if (err < 0) { |
958 | snd_printd("Cannot create main component\n" ); |
959 | goto release_pardev; |
960 | } |
961 | card->private_data = mts; |
962 | card->private_free = snd_mts64_card_private_free; |
963 | |
964 | err = mts64_probe(p); |
965 | if (err) { |
966 | err = -EIO; |
967 | goto __err; |
968 | } |
969 | |
970 | err = snd_mts64_rawmidi_create(card); |
971 | if (err < 0) { |
972 | snd_printd("Creating Rawmidi component failed\n" ); |
973 | goto __err; |
974 | } |
975 | |
976 | /* init device */ |
977 | err = mts64_device_init(p); |
978 | if (err < 0) |
979 | goto __err; |
980 | |
981 | platform_set_drvdata(pdev, data: card); |
982 | |
983 | /* At this point card will be usable */ |
984 | err = snd_card_register(card); |
985 | if (err < 0) { |
986 | snd_printd("Cannot register card\n" ); |
987 | goto __err; |
988 | } |
989 | |
990 | snd_printk(KERN_INFO "ESI Miditerminal 4140 on 0x%lx\n" , p->base); |
991 | return 0; |
992 | |
993 | release_pardev: |
994 | parport_release(dev: pardev); |
995 | free_pardev: |
996 | parport_unregister_device(dev: pardev); |
997 | __err: |
998 | snd_card_free(card); |
999 | return err; |
1000 | } |
1001 | |
1002 | static void snd_mts64_remove(struct platform_device *pdev) |
1003 | { |
1004 | struct snd_card *card = platform_get_drvdata(pdev); |
1005 | |
1006 | if (card) |
1007 | snd_card_free(card); |
1008 | } |
1009 | |
1010 | static struct platform_driver snd_mts64_driver = { |
1011 | .probe = snd_mts64_probe, |
1012 | .remove_new = snd_mts64_remove, |
1013 | .driver = { |
1014 | .name = PLATFORM_DRIVER, |
1015 | } |
1016 | }; |
1017 | |
1018 | /********************************************************************* |
1019 | * module init stuff |
1020 | *********************************************************************/ |
1021 | static void snd_mts64_unregister_all(void) |
1022 | { |
1023 | int i; |
1024 | |
1025 | for (i = 0; i < SNDRV_CARDS; ++i) { |
1026 | if (platform_devices[i]) { |
1027 | platform_device_unregister(platform_devices[i]); |
1028 | platform_devices[i] = NULL; |
1029 | } |
1030 | } |
1031 | platform_driver_unregister(&snd_mts64_driver); |
1032 | parport_unregister_driver(&mts64_parport_driver); |
1033 | } |
1034 | |
1035 | static int __init snd_mts64_module_init(void) |
1036 | { |
1037 | int err; |
1038 | |
1039 | err = platform_driver_register(&snd_mts64_driver); |
1040 | if (err < 0) |
1041 | return err; |
1042 | |
1043 | if (parport_register_driver(&mts64_parport_driver) != 0) { |
1044 | platform_driver_unregister(&snd_mts64_driver); |
1045 | return -EIO; |
1046 | } |
1047 | |
1048 | if (device_count == 0) { |
1049 | snd_mts64_unregister_all(); |
1050 | return -ENODEV; |
1051 | } |
1052 | |
1053 | return 0; |
1054 | } |
1055 | |
1056 | static void __exit snd_mts64_module_exit(void) |
1057 | { |
1058 | snd_mts64_unregister_all(); |
1059 | } |
1060 | |
1061 | module_init(snd_mts64_module_init); |
1062 | module_exit(snd_mts64_module_exit); |
1063 | |