Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *   serial-generic.c
0004  *   Copyright (c) by Daniel Kaehn <kaehndan@gmail.com
0005  *   Based on serial-u16550.c by Jaroslav Kysela <perex@perex.cz>,
0006  *                       Isaku Yamahata <yamahata@private.email.ne.jp>,
0007  *                       George Hansper <ghansper@apana.org.au>,
0008  *                       Hannu Savolainen
0009  *
0010  * Generic serial MIDI driver using the serdev serial bus API for hardware interaction
0011  */
0012 
0013 #include <linux/err.h>
0014 #include <linux/init.h>
0015 #include <linux/interrupt.h>
0016 #include <linux/io.h>
0017 #include <linux/ioport.h>
0018 #include <linux/module.h>
0019 #include <linux/of_device.h>
0020 #include <linux/serdev.h>
0021 #include <linux/serial_reg.h>
0022 #include <linux/slab.h>
0023 #include <linux/dev_printk.h>
0024 
0025 #include <sound/core.h>
0026 #include <sound/rawmidi.h>
0027 #include <sound/initval.h>
0028 
0029 MODULE_DESCRIPTION("Generic serial MIDI driver");
0030 MODULE_LICENSE("GPL");
0031 
0032 #define SERIAL_MODE_INPUT_OPEN      1
0033 #define SERIAL_MODE_OUTPUT_OPEN 2
0034 #define SERIAL_MODE_INPUT_TRIGGERED 3
0035 #define SERIAL_MODE_OUTPUT_TRIGGERED    4
0036 
0037 #define SERIAL_TX_STATE_ACTIVE  1
0038 #define SERIAL_TX_STATE_WAKEUP  2
0039 
0040 struct snd_serial_generic {
0041     struct serdev_device *serdev;
0042 
0043     struct snd_card *card;
0044     struct snd_rawmidi *rmidi;
0045     struct snd_rawmidi_substream *midi_output;
0046     struct snd_rawmidi_substream *midi_input;
0047 
0048     unsigned int baudrate;
0049 
0050     unsigned long filemode;     /* open status of file */
0051     struct work_struct tx_work;
0052     unsigned long tx_state;
0053 
0054 };
0055 
0056 static void snd_serial_generic_tx_wakeup(struct snd_serial_generic *drvdata)
0057 {
0058     if (test_and_set_bit(SERIAL_TX_STATE_ACTIVE, &drvdata->tx_state))
0059         set_bit(SERIAL_TX_STATE_WAKEUP, &drvdata->tx_state);
0060 
0061     schedule_work(&drvdata->tx_work);
0062 }
0063 
0064 #define INTERNAL_BUF_SIZE 256
0065 
0066 static void snd_serial_generic_tx_work(struct work_struct *work)
0067 {
0068     static char buf[INTERNAL_BUF_SIZE];
0069     int num_bytes;
0070     struct snd_serial_generic *drvdata = container_of(work, struct snd_serial_generic,
0071                            tx_work);
0072     struct snd_rawmidi_substream *substream = drvdata->midi_output;
0073 
0074     clear_bit(SERIAL_TX_STATE_WAKEUP, &drvdata->tx_state);
0075 
0076     while (!snd_rawmidi_transmit_empty(substream)) {
0077 
0078         if (!test_bit(SERIAL_MODE_OUTPUT_OPEN, &drvdata->filemode))
0079             break;
0080 
0081         num_bytes = snd_rawmidi_transmit_peek(substream, buf, INTERNAL_BUF_SIZE);
0082         num_bytes = serdev_device_write_buf(drvdata->serdev, buf, num_bytes);
0083 
0084         if (!num_bytes)
0085             break;
0086 
0087         snd_rawmidi_transmit_ack(substream, num_bytes);
0088 
0089         if (!test_bit(SERIAL_TX_STATE_WAKEUP, &drvdata->tx_state))
0090             break;
0091     }
0092 
0093     clear_bit(SERIAL_TX_STATE_ACTIVE, &drvdata->tx_state);
0094 }
0095 
0096 static void snd_serial_generic_write_wakeup(struct serdev_device *serdev)
0097 {
0098     struct snd_serial_generic *drvdata = serdev_device_get_drvdata(serdev);
0099 
0100     snd_serial_generic_tx_wakeup(drvdata);
0101 }
0102 
0103 static int snd_serial_generic_receive_buf(struct serdev_device *serdev,
0104                 const unsigned char *buf, size_t count)
0105 {
0106     int ret;
0107     struct snd_serial_generic *drvdata = serdev_device_get_drvdata(serdev);
0108 
0109     if (!test_bit(SERIAL_MODE_INPUT_OPEN, &drvdata->filemode))
0110         return 0;
0111 
0112     ret = snd_rawmidi_receive(drvdata->midi_input, buf, count);
0113     return ret < 0 ? 0 : ret;
0114 }
0115 
0116 static const struct serdev_device_ops snd_serial_generic_serdev_device_ops = {
0117     .receive_buf = snd_serial_generic_receive_buf,
0118     .write_wakeup = snd_serial_generic_write_wakeup
0119 };
0120 
0121 static int snd_serial_generic_ensure_serdev_open(struct snd_serial_generic *drvdata)
0122 {
0123     int err;
0124     unsigned int actual_baud;
0125 
0126     if (drvdata->filemode)
0127         return 0;
0128 
0129     dev_dbg(drvdata->card->dev, "Opening serial port for card %s\n",
0130         drvdata->card->shortname);
0131     err = serdev_device_open(drvdata->serdev);
0132     if (err < 0)
0133         return err;
0134 
0135     actual_baud = serdev_device_set_baudrate(drvdata->serdev,
0136         drvdata->baudrate);
0137     if (actual_baud != drvdata->baudrate) {
0138         dev_warn(drvdata->card->dev, "requested %d baud for card %s but it was actually set to %d\n",
0139             drvdata->baudrate, drvdata->card->shortname, actual_baud);
0140     }
0141 
0142     return 0;
0143 }
0144 
0145 static int snd_serial_generic_input_open(struct snd_rawmidi_substream *substream)
0146 {
0147     int err;
0148     struct snd_serial_generic *drvdata = substream->rmidi->card->private_data;
0149 
0150     dev_dbg(drvdata->card->dev, "Opening input for card %s\n",
0151         drvdata->card->shortname);
0152 
0153     err = snd_serial_generic_ensure_serdev_open(drvdata);
0154     if (err < 0)
0155         return err;
0156 
0157     set_bit(SERIAL_MODE_INPUT_OPEN, &drvdata->filemode);
0158     drvdata->midi_input = substream;
0159     return 0;
0160 }
0161 
0162 static int snd_serial_generic_input_close(struct snd_rawmidi_substream *substream)
0163 {
0164     struct snd_serial_generic *drvdata = substream->rmidi->card->private_data;
0165 
0166     dev_dbg(drvdata->card->dev, "Closing input for card %s\n",
0167         drvdata->card->shortname);
0168 
0169     clear_bit(SERIAL_MODE_INPUT_OPEN, &drvdata->filemode);
0170     clear_bit(SERIAL_MODE_INPUT_TRIGGERED, &drvdata->filemode);
0171 
0172     drvdata->midi_input = NULL;
0173 
0174     if (!drvdata->filemode)
0175         serdev_device_close(drvdata->serdev);
0176     return 0;
0177 }
0178 
0179 static void snd_serial_generic_input_trigger(struct snd_rawmidi_substream *substream,
0180                     int up)
0181 {
0182     struct snd_serial_generic *drvdata = substream->rmidi->card->private_data;
0183 
0184     if (up)
0185         set_bit(SERIAL_MODE_INPUT_TRIGGERED, &drvdata->filemode);
0186     else
0187         clear_bit(SERIAL_MODE_INPUT_TRIGGERED, &drvdata->filemode);
0188 }
0189 
0190 static int snd_serial_generic_output_open(struct snd_rawmidi_substream *substream)
0191 {
0192     struct snd_serial_generic *drvdata = substream->rmidi->card->private_data;
0193     int err;
0194 
0195     dev_dbg(drvdata->card->dev, "Opening output for card %s\n",
0196         drvdata->card->shortname);
0197 
0198     err = snd_serial_generic_ensure_serdev_open(drvdata);
0199     if (err < 0)
0200         return err;
0201 
0202     set_bit(SERIAL_MODE_OUTPUT_OPEN, &drvdata->filemode);
0203 
0204     drvdata->midi_output = substream;
0205     return 0;
0206 };
0207 
0208 static int snd_serial_generic_output_close(struct snd_rawmidi_substream *substream)
0209 {
0210     struct snd_serial_generic *drvdata = substream->rmidi->card->private_data;
0211 
0212     dev_dbg(drvdata->card->dev, "Closing output for card %s\n",
0213         drvdata->card->shortname);
0214 
0215     clear_bit(SERIAL_MODE_OUTPUT_OPEN, &drvdata->filemode);
0216     clear_bit(SERIAL_MODE_OUTPUT_TRIGGERED, &drvdata->filemode);
0217 
0218     if (!drvdata->filemode)
0219         serdev_device_close(drvdata->serdev);
0220 
0221     drvdata->midi_output = NULL;
0222 
0223     return 0;
0224 };
0225 
0226 static void snd_serial_generic_output_trigger(struct snd_rawmidi_substream *substream,
0227                      int up)
0228 {
0229     struct snd_serial_generic *drvdata = substream->rmidi->card->private_data;
0230 
0231     if (up)
0232         set_bit(SERIAL_MODE_OUTPUT_TRIGGERED, &drvdata->filemode);
0233     else
0234         clear_bit(SERIAL_MODE_OUTPUT_TRIGGERED, &drvdata->filemode);
0235 
0236     if (up)
0237         snd_serial_generic_tx_wakeup(drvdata);
0238 }
0239 
0240 static void snd_serial_generic_output_drain(struct snd_rawmidi_substream *substream)
0241 {
0242     struct snd_serial_generic *drvdata = substream->rmidi->card->private_data;
0243 
0244     /* Flush any pending characters */
0245     serdev_device_write_flush(drvdata->serdev);
0246     cancel_work_sync(&drvdata->tx_work);
0247 }
0248 
0249 static const struct snd_rawmidi_ops snd_serial_generic_output = {
0250     .open =     snd_serial_generic_output_open,
0251     .close =    snd_serial_generic_output_close,
0252     .trigger =  snd_serial_generic_output_trigger,
0253     .drain =    snd_serial_generic_output_drain,
0254 };
0255 
0256 static const struct snd_rawmidi_ops snd_serial_generic_input = {
0257     .open =     snd_serial_generic_input_open,
0258     .close =    snd_serial_generic_input_close,
0259     .trigger =  snd_serial_generic_input_trigger,
0260 };
0261 
0262 static void snd_serial_generic_parse_dt(struct serdev_device *serdev,
0263                 struct snd_serial_generic *drvdata)
0264 {
0265     int err;
0266 
0267     err = of_property_read_u32(serdev->dev.of_node, "current-speed",
0268         &drvdata->baudrate);
0269     if (err < 0) {
0270         dev_dbg(drvdata->card->dev,
0271             "MIDI device reading of current-speed DT param failed with error %d, using default of 38400\n",
0272             err);
0273         drvdata->baudrate = 38400;
0274     }
0275 
0276 }
0277 
0278 static void snd_serial_generic_substreams(struct snd_rawmidi_str *stream, int dev_num)
0279 {
0280     struct snd_rawmidi_substream *substream;
0281 
0282     list_for_each_entry(substream, &stream->substreams, list) {
0283         sprintf(substream->name, "Serial MIDI %d-%d", dev_num, substream->number);
0284     }
0285 }
0286 
0287 static int snd_serial_generic_rmidi(struct snd_serial_generic *drvdata,
0288                 int outs, int ins, struct snd_rawmidi **rmidi)
0289 {
0290     struct snd_rawmidi *rrawmidi;
0291     int err;
0292 
0293     err = snd_rawmidi_new(drvdata->card, drvdata->card->driver, 0,
0294                 outs, ins, &rrawmidi);
0295 
0296     if (err < 0)
0297         return err;
0298 
0299     snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_INPUT,
0300                 &snd_serial_generic_input);
0301     snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
0302                 &snd_serial_generic_output);
0303     strcpy(rrawmidi->name, drvdata->card->shortname);
0304 
0305     snd_serial_generic_substreams(&rrawmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT],
0306                     drvdata->serdev->ctrl->nr);
0307     snd_serial_generic_substreams(&rrawmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT],
0308                     drvdata->serdev->ctrl->nr);
0309 
0310     rrawmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
0311                    SNDRV_RAWMIDI_INFO_INPUT |
0312                    SNDRV_RAWMIDI_INFO_DUPLEX;
0313 
0314     if (rmidi)
0315         *rmidi = rrawmidi;
0316     return 0;
0317 }
0318 
0319 static int snd_serial_generic_probe(struct serdev_device *serdev)
0320 {
0321     struct snd_card *card;
0322     struct snd_serial_generic *drvdata;
0323     int err;
0324 
0325     err  = snd_devm_card_new(&serdev->dev, SNDRV_DEFAULT_IDX1,
0326                 SNDRV_DEFAULT_STR1, THIS_MODULE,
0327                 sizeof(struct snd_serial_generic), &card);
0328 
0329     if (err < 0)
0330         return err;
0331 
0332     strcpy(card->driver, "SerialMIDI");
0333     sprintf(card->shortname, "SerialMIDI-%d", serdev->ctrl->nr);
0334     sprintf(card->longname, "Serial MIDI device at serial%d", serdev->ctrl->nr);
0335 
0336     drvdata = card->private_data;
0337 
0338     drvdata->serdev = serdev;
0339     drvdata->card = card;
0340 
0341     snd_serial_generic_parse_dt(serdev, drvdata);
0342 
0343     INIT_WORK(&drvdata->tx_work, snd_serial_generic_tx_work);
0344 
0345     err = snd_serial_generic_rmidi(drvdata, 1, 1, &drvdata->rmidi);
0346     if (err < 0)
0347         return err;
0348 
0349     serdev_device_set_client_ops(serdev, &snd_serial_generic_serdev_device_ops);
0350     serdev_device_set_drvdata(drvdata->serdev, drvdata);
0351 
0352     err = snd_card_register(card);
0353     if (err < 0)
0354         return err;
0355 
0356     return 0;
0357 }
0358 
0359 static const struct of_device_id snd_serial_generic_dt_ids[] = {
0360     { .compatible = "serial-midi" },
0361     {},
0362 };
0363 
0364 MODULE_DEVICE_TABLE(of, snd_serial_generic_dt_ids);
0365 
0366 static struct serdev_device_driver snd_serial_generic_driver = {
0367     .driver = {
0368         .name       = "snd-serial-generic",
0369         .of_match_table = of_match_ptr(snd_serial_generic_dt_ids),
0370     },
0371     .probe  = snd_serial_generic_probe,
0372 };
0373 
0374 module_serdev_device_driver(snd_serial_generic_driver);