sound/drivers/serial-generic.c

Source file repositories/reference/linux-study-clean/sound/drivers/serial-generic.c

File Facts

System
Linux kernel
Corpus path
sound/drivers/serial-generic.c
Extension
.c
Size
10243 bytes
Lines
377
Domain
Driver Families
Bucket
sound/drivers
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct snd_serial_generic {
	struct serdev_device *serdev;

	struct snd_card *card;
	struct snd_rawmidi *rmidi;
	struct snd_rawmidi_substream *midi_output;
	struct snd_rawmidi_substream *midi_input;

	unsigned int baudrate;

	unsigned long filemode;		/* open status of file */
	struct work_struct tx_work;
	unsigned long tx_state;

	char tx_buf[INTERNAL_BUF_SIZE];
};

static void snd_serial_generic_tx_wakeup(struct snd_serial_generic *drvdata)
{
	if (test_and_set_bit(SERIAL_TX_STATE_ACTIVE, &drvdata->tx_state))
		set_bit(SERIAL_TX_STATE_WAKEUP, &drvdata->tx_state);

	schedule_work(&drvdata->tx_work);
}

static void snd_serial_generic_tx_work(struct work_struct *work)
{
	int num_bytes;
	struct snd_serial_generic *drvdata = container_of(work, struct snd_serial_generic,
						   tx_work);
	struct snd_rawmidi_substream *substream = drvdata->midi_output;

	clear_bit(SERIAL_TX_STATE_WAKEUP, &drvdata->tx_state);

	while (!snd_rawmidi_transmit_empty(substream)) {

		if (!test_bit(SERIAL_MODE_OUTPUT_OPEN, &drvdata->filemode))
			break;

		num_bytes = snd_rawmidi_transmit_peek(substream, drvdata->tx_buf,
						      INTERNAL_BUF_SIZE);
		num_bytes = serdev_device_write_buf(drvdata->serdev, drvdata->tx_buf,
						    num_bytes);

		if (!num_bytes)
			break;

		snd_rawmidi_transmit_ack(substream, num_bytes);

		if (!test_bit(SERIAL_TX_STATE_WAKEUP, &drvdata->tx_state))
			break;
	}

	clear_bit(SERIAL_TX_STATE_ACTIVE, &drvdata->tx_state);
}

static void snd_serial_generic_write_wakeup(struct serdev_device *serdev)
{
	struct snd_serial_generic *drvdata = serdev_device_get_drvdata(serdev);

	snd_serial_generic_tx_wakeup(drvdata);
}

static size_t snd_serial_generic_receive_buf(struct serdev_device *serdev,
					     const u8 *buf, size_t count)
{
	int ret;
	struct snd_serial_generic *drvdata = serdev_device_get_drvdata(serdev);

	if (!test_bit(SERIAL_MODE_INPUT_OPEN, &drvdata->filemode))
		return 0;

	ret = snd_rawmidi_receive(drvdata->midi_input, buf, count);
	return ret < 0 ? 0 : ret;
}

static const struct serdev_device_ops snd_serial_generic_serdev_device_ops = {
	.receive_buf = snd_serial_generic_receive_buf,
	.write_wakeup = snd_serial_generic_write_wakeup
};

static int snd_serial_generic_ensure_serdev_open(struct snd_serial_generic *drvdata)
{
	int err;
	unsigned int actual_baud;

	if (drvdata->filemode)
		return 0;

	dev_dbg(drvdata->card->dev, "Opening serial port for card %s\n",

Annotation

Implementation Notes