Recieved a message in kernel space
This commit is contained in:
parent
7d45dde84e
commit
c725e2bb94
101
aes67.c
101
aes67.c
|
@ -5,6 +5,7 @@
|
||||||
* */
|
* */
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/socket.h>
|
#include <linux/socket.h>
|
||||||
#include <linux/net.h>
|
#include <linux/net.h>
|
||||||
|
@ -22,6 +23,9 @@ static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
|
||||||
static int pcm_devs[SNDRV_CARDS] = { [0 ...(SNDRV_CARDS - 1)] = 1 };
|
static int pcm_devs[SNDRV_CARDS] = { [0 ...(SNDRV_CARDS - 1)] = 1 };
|
||||||
static int pcm_substreams[SNDRV_CARDS] = { [0 ...(SNDRV_CARDS - 1)] = 8 };
|
static int pcm_substreams[SNDRV_CARDS] = { [0 ...(SNDRV_CARDS - 1)] = 8 };
|
||||||
|
|
||||||
|
/* work for the network streams */
|
||||||
|
static struct workqueue_struct *io_workqueue;
|
||||||
|
|
||||||
static struct platform_device *devices[SNDRV_CARDS];
|
static struct platform_device *devices[SNDRV_CARDS];
|
||||||
|
|
||||||
#define CARD_NAME "AES67 Virtual Soundcard"
|
#define CARD_NAME "AES67 Virtual Soundcard"
|
||||||
|
@ -55,12 +59,19 @@ struct aes67 {
|
||||||
struct socket *socket;
|
struct socket *socket;
|
||||||
|
|
||||||
/* Receiving Work Queue */
|
/* Receiving Work Queue */
|
||||||
|
spinlock_t rlock;
|
||||||
struct work_struct receive_work;
|
struct work_struct receive_work;
|
||||||
|
bool rx_on;
|
||||||
};
|
};
|
||||||
|
|
||||||
//Forward declarations
|
//Forward declarations
|
||||||
static int snd_aes67_new_pcm(struct aes67 *virtcard);
|
static int snd_aes67_new_pcm(struct aes67 *virtcard);
|
||||||
|
|
||||||
|
static int work_start(void);
|
||||||
|
static void work_stop(void);
|
||||||
|
|
||||||
|
static void aes67_rx_net(struct work_struct *rwork);
|
||||||
|
|
||||||
/* Destructor */
|
/* Destructor */
|
||||||
static int snd_aes67_free(struct aes67 *virtcard)
|
static int snd_aes67_free(struct aes67 *virtcard)
|
||||||
{
|
{
|
||||||
|
@ -136,6 +147,11 @@ static int snd_aes67_create(struct snd_card *card, struct aes67 **rvirtcard)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Spin lock for receiving */
|
||||||
|
spin_lock_init(&virtcard->rlock);
|
||||||
|
/* Init work for card */
|
||||||
|
INIT_WORK(&virtcard->receive_work, aes67_rx_net);
|
||||||
|
|
||||||
/* Add PCM */
|
/* Add PCM */
|
||||||
err = snd_aes67_new_pcm(virtcard);
|
err = snd_aes67_new_pcm(virtcard);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
|
@ -194,6 +210,27 @@ error:
|
||||||
snd_card_free(card);
|
snd_card_free(card);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
/* Work queue Management */
|
||||||
|
static void work_stop(void)
|
||||||
|
{
|
||||||
|
if (io_workqueue) {
|
||||||
|
destroy_workqueue(io_workqueue);
|
||||||
|
io_workqueue = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int work_start(void)
|
||||||
|
{
|
||||||
|
io_workqueue = alloc_workqueue("aes67_io", WQ_HIGHPRI | WQ_MEM_RECLAIM |
|
||||||
|
WQ_UNBOUND, 0);
|
||||||
|
|
||||||
|
if (!io_workqueue) {
|
||||||
|
snd_printk(KERN_ERR "Failed to start io workqueue struct\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Network functions */
|
/* Network functions */
|
||||||
|
|
||||||
static void aes67_rx_net(struct work_struct *work)
|
static void aes67_rx_net(struct work_struct *work)
|
||||||
|
@ -202,9 +239,8 @@ static void aes67_rx_net(struct work_struct *work)
|
||||||
struct kvec iv;
|
struct kvec iv;
|
||||||
struct msghdr msg = {};
|
struct msghdr msg = {};
|
||||||
size_t recv_buf_size = 4096;
|
size_t recv_buf_size = 4096;
|
||||||
int ret, buflen;
|
ssize_t msglen;
|
||||||
void *recv_buf;
|
unsigned char *recv_buf;
|
||||||
/* Read lock socket */
|
|
||||||
|
|
||||||
/* Loop Receive */
|
/* Loop Receive */
|
||||||
recv_buf = kzalloc(recv_buf_size, GFP_KERNEL);
|
recv_buf = kzalloc(recv_buf_size, GFP_KERNEL);
|
||||||
|
@ -214,14 +250,35 @@ static void aes67_rx_net(struct work_struct *work)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
msg.msg_flags = MSG_PEEK | MSG_DONTWAIT;
|
||||||
|
|
||||||
|
snd_printk(KERN_INFO "Starting network receive loop\n");
|
||||||
|
for (;;) {
|
||||||
iv.iov_base = recv_buf;
|
iv.iov_base = recv_buf;
|
||||||
iv.iov_len = recv_buf_size;
|
iv.iov_len = recv_buf_size;
|
||||||
|
|
||||||
msglen = kernel_recvmsg(virtcard->socket, &msg, &iv, 1, iv.iov_len, MSG_DONTWAIT);
|
msglen = kernel_recvmsg(virtcard->socket, &msg, &iv, 1,
|
||||||
|
iv.iov_len, msg.msg_flags);
|
||||||
|
|
||||||
} while (ret == AES67_NET_SUCCESS);
|
if (msglen == -EAGAIN) {
|
||||||
|
snd_printk(
|
||||||
|
KERN_WARNING
|
||||||
|
"Failed to receive message. With EAGAIN, Sleeping and trying again\n");
|
||||||
|
msleep(1000);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msglen < 0) {
|
||||||
|
snd_printk(KERN_ERR "error receiving packet: %zd\n",
|
||||||
|
msglen);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msglen > 0) {
|
||||||
|
snd_printk(KERN_INFO "Received Buffer: %ph", recv_buf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
/* Handle stream end */
|
/* Handle stream end */
|
||||||
snd_printk(KERN_INFO "Finished Receiving work queue\n");
|
snd_printk(KERN_INFO "Finished Receiving work queue\n");
|
||||||
|
|
||||||
|
@ -265,8 +322,16 @@ static struct snd_pcm_hardware snd_aes67_capture_hw = {
|
||||||
|
|
||||||
static int snd_aes67_playback_open(struct snd_pcm_substream *substream)
|
static int snd_aes67_playback_open(struct snd_pcm_substream *substream)
|
||||||
{
|
{
|
||||||
struct aes67 *virtcard = snd_pcm_substream_chip(substream);
|
|
||||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||||
|
struct aes67 *chip = snd_pcm_substream_chip(substream);
|
||||||
|
|
||||||
|
spin_lock_irq(&chip->rlock);
|
||||||
|
if (!chip->rx_on) {
|
||||||
|
snd_printk(KERN_INFO "Starting receive work queue\n");
|
||||||
|
queue_work(io_workqueue, &chip->receive_work);
|
||||||
|
chip->rx_on = true;
|
||||||
|
}
|
||||||
|
spin_unlock_irq(&chip->rlock);
|
||||||
|
|
||||||
runtime->hw = snd_aes67_playback_hw;
|
runtime->hw = snd_aes67_playback_hw;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -274,13 +339,11 @@ static int snd_aes67_playback_open(struct snd_pcm_substream *substream)
|
||||||
|
|
||||||
static int snd_aes67_playback_close(struct snd_pcm_substream *substream)
|
static int snd_aes67_playback_close(struct snd_pcm_substream *substream)
|
||||||
{
|
{
|
||||||
struct aes67 *virtcard = snd_pcm_substream_chip(substream);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_aes67_capture_open(struct snd_pcm_substream *substream)
|
static int snd_aes67_capture_open(struct snd_pcm_substream *substream)
|
||||||
{
|
{
|
||||||
struct aes67 *virtcard = snd_pcm_substream_chip(substream);
|
|
||||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||||
|
|
||||||
runtime->hw = snd_aes67_capture_hw;
|
runtime->hw = snd_aes67_capture_hw;
|
||||||
|
@ -289,7 +352,6 @@ static int snd_aes67_capture_open(struct snd_pcm_substream *substream)
|
||||||
|
|
||||||
static int snd_aes67_capture_close(struct snd_pcm_substream *substream)
|
static int snd_aes67_capture_close(struct snd_pcm_substream *substream)
|
||||||
{
|
{
|
||||||
struct aes67 *virtcard = snd_pcm_substream_chip(substream);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,9 +371,6 @@ static int snd_aes67_pcm_hw_free(struct snd_pcm_substream *substream)
|
||||||
|
|
||||||
static int snd_aes67_pcm_prepare(struct snd_pcm_substream *substream)
|
static int snd_aes67_pcm_prepare(struct snd_pcm_substream *substream)
|
||||||
{
|
{
|
||||||
struct aes67 *chip = snd_pcm_substream_chip(substream);
|
|
||||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
|
||||||
|
|
||||||
/* set up the hardware with the current configuration
|
/* set up the hardware with the current configuration
|
||||||
* for example...
|
* for example...
|
||||||
*/
|
*/
|
||||||
|
@ -320,13 +379,8 @@ static int snd_aes67_pcm_prepare(struct snd_pcm_substream *substream)
|
||||||
|
|
||||||
static int snd_aes67_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
static int snd_aes67_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||||
{
|
{
|
||||||
struct aes67 *chip = snd_pcm_substream_chip(substream);
|
|
||||||
|
|
||||||
int err;
|
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case SNDRV_PCM_TRIGGER_START:
|
case SNDRV_PCM_TRIGGER_START:
|
||||||
INIT_WORK(&chip->receive_work, aes67_rx_net);
|
|
||||||
break;
|
break;
|
||||||
case SNDRV_PCM_TRIGGER_STOP:
|
case SNDRV_PCM_TRIGGER_STOP:
|
||||||
/* do something to stop the PCM engine */
|
/* do something to stop the PCM engine */
|
||||||
|
@ -402,7 +456,7 @@ static int snd_aes67_new_pcm(struct aes67 *virtcard)
|
||||||
/*Da buffers*/
|
/*Da buffers*/
|
||||||
snd_printk(KERN_INFO "Settig PCM managed buffer");
|
snd_printk(KERN_INFO "Settig PCM managed buffer");
|
||||||
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DEV_LOWLEVEL, virtcard->dev,
|
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DEV_LOWLEVEL, virtcard->dev,
|
||||||
64 * 1024, 64 * 1024);
|
32 * 1024, 32 * 1024);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -449,6 +503,13 @@ static int __init alsa_card_aes67_init(void)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Start work queue */
|
||||||
|
err = work_start();
|
||||||
|
if (err < 0) {
|
||||||
|
snd_printk(KERN_ERR "FAILED to start workqueue for AES67\n");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
//register a card in the kernel
|
//register a card in the kernel
|
||||||
struct platform_device *device;
|
struct platform_device *device;
|
||||||
device = platform_device_register_simple(SND_AES67_DRIVER, 0, NULL, 0);
|
device = platform_device_register_simple(SND_AES67_DRIVER, 0, NULL, 0);
|
||||||
|
@ -468,6 +529,8 @@ static int __init alsa_card_aes67_init(void)
|
||||||
|
|
||||||
static void __exit alsa_card_aes67_exit(void)
|
static void __exit alsa_card_aes67_exit(void)
|
||||||
{
|
{
|
||||||
|
snd_printk(KERN_INFO "Attempting to stop workqueue for AES67\n");
|
||||||
|
work_stop();
|
||||||
snd_printk(KERN_INFO "Attempting to unregister card for AES67\n");
|
snd_printk(KERN_INFO "Attempting to unregister card for AES67\n");
|
||||||
platform_device_unregister(devices[0]);
|
platform_device_unregister(devices[0]);
|
||||||
snd_printk(KERN_INFO "Attempting to unregistered driver for AES67\n");
|
snd_printk(KERN_INFO "Attempting to unregistered driver for AES67\n");
|
||||||
|
|
Loading…
Reference in New Issue