diff options
Diffstat (limited to 'drivers/staging/most')
-rw-r--r-- | drivers/staging/most/Documentation/ABI/sysfs-class-most.txt | 2 | ||||
-rw-r--r-- | drivers/staging/most/aim-cdev/cdev.c | 68 | ||||
-rw-r--r-- | drivers/staging/most/aim-network/networking.c | 53 | ||||
-rw-r--r-- | drivers/staging/most/aim-sound/sound.c | 114 | ||||
-rw-r--r-- | drivers/staging/most/aim-v4l2/Makefile | 1 | ||||
-rw-r--r-- | drivers/staging/most/aim-v4l2/video.c | 50 | ||||
-rw-r--r-- | drivers/staging/most/hdm-dim2/Kconfig | 2 | ||||
-rw-r--r-- | drivers/staging/most/hdm-dim2/dim2_hal.c | 62 | ||||
-rw-r--r-- | drivers/staging/most/hdm-dim2/dim2_hal.h | 5 | ||||
-rw-r--r-- | drivers/staging/most/hdm-dim2/dim2_hdm.c | 79 | ||||
-rw-r--r-- | drivers/staging/most/hdm-dim2/dim2_hdm.h | 3 | ||||
-rw-r--r-- | drivers/staging/most/hdm-dim2/dim2_sysfs.c | 3 | ||||
-rw-r--r-- | drivers/staging/most/hdm-i2c/hdm_i2c.c | 45 | ||||
-rw-r--r-- | drivers/staging/most/hdm-usb/hdm_usb.c | 162 | ||||
-rw-r--r-- | drivers/staging/most/mostcore/core.c | 230 | ||||
-rw-r--r-- | drivers/staging/most/mostcore/mostcore.h | 13 |
16 files changed, 438 insertions, 454 deletions
diff --git a/drivers/staging/most/Documentation/ABI/sysfs-class-most.txt b/drivers/staging/most/Documentation/ABI/sysfs-class-most.txt index 380c13708..42ff0d8b2 100644 --- a/drivers/staging/most/Documentation/ABI/sysfs-class-most.txt +++ b/drivers/staging/most/Documentation/ABI/sysfs-class-most.txt @@ -47,7 +47,7 @@ Date: June 2015 KernelVersion: 4.3 Contact: Christian Gromm <christian.gromm@microchip.com> Description: - Indicates the type of peripherial interface the current device + Indicates the type of peripheral interface the current device uses. Users: diff --git a/drivers/staging/most/aim-cdev/cdev.c b/drivers/staging/most/aim-cdev/cdev.c index 0a13d8d0f..dc3fb25b5 100644 --- a/drivers/staging/most/aim-cdev/cdev.c +++ b/drivers/staging/most/aim-cdev/cdev.c @@ -18,6 +18,7 @@ #include <linux/slab.h> #include <linux/device.h> #include <linux/cdev.h> +#include <linux/poll.h> #include <linux/kfifo.h> #include <linux/uaccess.h> #include <linux/idr.h> @@ -27,6 +28,7 @@ static dev_t aim_devno; static struct class *aim_class; static struct ida minor_id; static unsigned int major; +static struct most_aim cdev_aim; struct aim_channel { wait_queue_head_t wq; @@ -44,11 +46,11 @@ struct aim_channel { atomic_t access_ref; struct list_head list; }; + #define to_channel(d) container_of(d, struct aim_channel, cdev) static struct list_head channel_list; static spinlock_t ch_list_lock; - static struct aim_channel *get_channel(struct most_interface *iface, int id) { struct aim_channel *channel, *tmp; @@ -85,8 +87,8 @@ static int aim_open(struct inode *inode, struct file *filp) filp->private_data = channel; if (((channel->cfg->direction == MOST_CH_RX) && - ((filp->f_flags & O_ACCMODE) != O_RDONLY)) - || ((channel->cfg->direction == MOST_CH_TX) && + ((filp->f_flags & O_ACCMODE) != O_RDONLY)) || + ((channel->cfg->direction == MOST_CH_TX) && ((filp->f_flags & O_ACCMODE) != O_WRONLY))) { pr_info("WARN: Access flags mismatch\n"); return -EACCES; @@ -97,7 +99,8 @@ static int aim_open(struct inode *inode, struct file *filp) return -EBUSY; } - ret = most_start_channel(channel->iface, channel->channel_id); + ret = most_start_channel(channel->iface, channel->channel_id, + &cdev_aim); if (ret) atomic_dec(&channel->access_ref); return ret; @@ -131,11 +134,11 @@ static int aim_close(struct inode *inode, struct file *filp) } mutex_unlock(&channel->io_mutex); - while (0 != kfifo_out((struct kfifo *)&channel->fifo, &mbo, 1)) + while (kfifo_out((struct kfifo *)&channel->fifo, &mbo, 1)) most_put_mbo(mbo); - if (channel->keep_mbo == true) + if (channel->keep_mbo) most_put_mbo(channel->stacked_mbo); - ret = most_stop_channel(channel->iface, channel->channel_id); + ret = most_stop_channel(channel->iface, channel->channel_id, &cdev_aim); atomic_dec(&channel->access_ref); wake_up_interruptible(&channel->wq); return ret; @@ -165,16 +168,17 @@ static ssize_t aim_write(struct file *filp, const char __user *buf, } mutex_unlock(&channel->io_mutex); - mbo = most_get_mbo(channel->iface, channel->channel_id); + mbo = most_get_mbo(channel->iface, channel->channel_id, &cdev_aim); - if (!mbo && channel->dev) { + if (!mbo) { if ((filp->f_flags & O_NONBLOCK)) return -EAGAIN; if (wait_event_interruptible( channel->wq, (mbo = most_get_mbo(channel->iface, - channel->channel_id)) || - (channel->dev == NULL))) + channel->channel_id, + &cdev_aim)) || + (!channel->dev))) return -ERESTARTSYS; } @@ -204,8 +208,7 @@ static ssize_t aim_write(struct file *filp, const char __user *buf, } return actual_len - retval; error: - if (mbo) - most_put_mbo(mbo); + most_put_mbo(mbo); return err; } @@ -224,18 +227,17 @@ aim_read(struct file *filp, char __user *buf, size_t count, loff_t *offset) struct mbo *mbo; struct aim_channel *channel = filp->private_data; - if (channel->keep_mbo == true) { + if (channel->keep_mbo) { mbo = channel->stacked_mbo; channel->keep_mbo = false; goto start_copy; } - while ((0 == kfifo_out(&channel->fifo, &mbo, 1)) - && (channel->dev != NULL)) { + while ((!kfifo_out(&channel->fifo, &mbo, 1)) && (channel->dev)) { if (filp->f_flags & O_NONBLOCK) return -EAGAIN; if (wait_event_interruptible(channel->wq, (!kfifo_is_empty(&channel->fifo) || - (channel->dev == NULL)))) + (!channel->dev)))) return -ERESTARTSYS; } @@ -259,7 +261,7 @@ start_copy: retval = not_copied ? proc_len - not_copied : proc_len; - if (channel->keep_mbo == true) { + if (channel->keep_mbo) { channel->mbo_offs = retval; channel->stacked_mbo = mbo; } else { @@ -270,6 +272,28 @@ start_copy: return retval; } +static inline bool __must_check IS_ERR_OR_FALSE(int x) +{ + return x <= 0; +} + +static unsigned int aim_poll(struct file *filp, poll_table *wait) +{ + struct aim_channel *c = filp->private_data; + unsigned int mask = 0; + + poll_wait(filp, &c->wq, wait); + + if (c->cfg->direction == MOST_CH_RX) { + if (!kfifo_is_empty(&c->fifo)) + mask |= POLLIN | POLLRDNORM; + } else { + if (!IS_ERR_OR_FALSE(channel_has_mbo(c->iface, c->channel_id))) + mask |= POLLOUT | POLLWRNORM; + } + return mask; +} + /** * Initialization of struct file_operations */ @@ -279,6 +303,7 @@ static const struct file_operations channel_fops = { .write = aim_write, .open = aim_open, .release = aim_close, + .poll = aim_poll, }; /** @@ -300,7 +325,7 @@ static int aim_disconnect_channel(struct most_interface *iface, int channel_id) } channel = get_channel(iface, channel_id); - if (channel == NULL) + if (!channel) return -ENXIO; mutex_lock(&channel->io_mutex); @@ -337,7 +362,7 @@ static int aim_rx_completion(struct mbo *mbo) return -EINVAL; channel = get_channel(mbo->ifp, mbo->hdm_channel_id); - if (channel == NULL) + if (!channel) return -ENXIO; kfifo_in(&channel->fifo, &mbo, 1); @@ -370,7 +395,7 @@ static int aim_tx_completion(struct most_interface *iface, int channel_id) } channel = get_channel(iface, channel_id); - if (channel == NULL) + if (!channel) return -ENXIO; wake_up_interruptible(&channel->wq); return 0; @@ -413,7 +438,6 @@ static int aim_probe(struct most_interface *iface, int channel_id, channel = kzalloc(sizeof(*channel), GFP_KERNEL); if (!channel) { - pr_info("failed to alloc channel object\n"); retval = -ENOMEM; goto error_alloc_channel; } diff --git a/drivers/staging/most/aim-network/networking.c b/drivers/staging/most/aim-network/networking.c index c8ab2399f..3c7beb038 100644 --- a/drivers/staging/most/aim-network/networking.c +++ b/drivers/staging/most/aim-network/networking.c @@ -24,7 +24,6 @@ #include "mostcore.h" #include "networking.h" - #define MEP_HDR_LEN 8 #define MDP_HDR_LEN 16 #define MAMAC_DATA_LEN (1024 - MDP_HDR_LEN) @@ -47,8 +46,6 @@ #define HB(value) ((u8)((u16)(value) >> 8)) #define LB(value) ((u8)(value)) - - #define EXTRACT_BIT_SET(bitset_name, value) \ (((value) >> bitset_name##_SHIFT) & bitset_name##_MASK) @@ -81,7 +78,6 @@ static struct list_head net_devices = LIST_HEAD_INIT(net_devices); static struct spinlock list_lock; static struct most_aim aim; - static int skb_to_mamac(const struct sk_buff *skb, struct mbo *mbo) { u8 *buff = mbo->virt_address; @@ -186,7 +182,7 @@ static int most_nd_open(struct net_device *dev) { struct net_dev_context *nd = dev->ml_priv; - pr_info("open net device %s\n", dev->name); + netdev_info(dev, "open net device\n"); BUG_ON(nd->dev != dev); @@ -195,14 +191,14 @@ static int most_nd_open(struct net_device *dev) BUG_ON(!nd->tx.linked || !nd->rx.linked); - if (most_start_channel(nd->iface, nd->rx.ch_id)) { - pr_err("most_start_channel() failed\n"); + if (most_start_channel(nd->iface, nd->rx.ch_id, &aim)) { + netdev_err(dev, "most_start_channel() failed\n"); return -EBUSY; } - if (most_start_channel(nd->iface, nd->tx.ch_id)) { - pr_err("most_start_channel() failed\n"); - most_stop_channel(nd->iface, nd->rx.ch_id); + if (most_start_channel(nd->iface, nd->tx.ch_id, &aim)) { + netdev_err(dev, "most_start_channel() failed\n"); + most_stop_channel(nd->iface, nd->rx.ch_id, &aim); return -EBUSY; } @@ -222,14 +218,14 @@ static int most_nd_stop(struct net_device *dev) { struct net_dev_context *nd = dev->ml_priv; - pr_info("stop net device %s\n", dev->name); + netdev_info(dev, "stop net device\n"); BUG_ON(nd->dev != dev); netif_stop_queue(dev); if (nd->channels_opened) { - most_stop_channel(nd->iface, nd->rx.ch_id); - most_stop_channel(nd->iface, nd->tx.ch_id); + most_stop_channel(nd->iface, nd->rx.ch_id, &aim); + most_stop_channel(nd->iface, nd->tx.ch_id, &aim); nd->channels_opened = false; } @@ -245,7 +241,7 @@ static netdev_tx_t most_nd_start_xmit(struct sk_buff *skb, BUG_ON(nd->dev != dev); - mbo = most_get_mbo(nd->iface, nd->tx.ch_id); + mbo = most_get_mbo(nd->iface, nd->tx.ch_id, &aim); if (!mbo) { netif_stop_queue(dev); @@ -281,7 +277,7 @@ static const struct net_device_ops most_nd_ops = { static void most_nd_setup(struct net_device *dev) { - pr_info("setup net device %s\n", dev->name); + netdev_info(dev, "setup net device\n"); ether_setup(dev); dev->netdev_ops = &most_nd_ops; } @@ -295,7 +291,7 @@ static void most_net_rm_netdev_safe(struct net_dev_context *nd) unregister_netdev(nd->dev); free_netdev(nd->dev); - nd->dev = 0; + nd->dev = NULL; } static struct net_dev_context *get_net_dev_context( @@ -349,7 +345,8 @@ static int aim_probe_channel(struct most_interface *iface, int channel_idx, if (nd->tx.linked || nd->rx.linked) { struct net_device *dev = - alloc_netdev(0, "meth%d", NET_NAME_UNKNOWN, most_nd_setup); + alloc_netdev(0, "meth%d", NET_NAME_UNKNOWN, + most_nd_setup); if (!dev) { pr_err("no memory for net_device\n"); @@ -357,10 +354,13 @@ static int aim_probe_channel(struct most_interface *iface, int channel_idx, } nd->dev = dev; + ch->ch_id = channel_idx; + ch->linked = true; dev->ml_priv = nd; if (register_netdev(dev)) { pr_err("registering net device failed\n"); + ch->linked = false; free_netdev(dev); return -EINVAL; } @@ -428,7 +428,7 @@ static int aim_rx_data(struct mbo *mbo) const u32 zero = 0; struct net_dev_context *nd; char *buf = mbo->virt_address; - uint32_t len = mbo->processed_length; + u32 len = mbo->processed_length; struct sk_buff *skb; struct net_device *dev; @@ -464,7 +464,7 @@ static int aim_rx_data(struct mbo *mbo) if (nd->is_mamac) { /* dest */ - memcpy(skb_put(skb, ETH_ALEN), dev->dev_addr, ETH_ALEN); + ether_addr_copy(skb_put(skb, ETH_ALEN), dev->dev_addr); /* src */ memcpy(skb_put(skb, 4), &zero, 4); @@ -491,15 +491,18 @@ out: return 0; } +static struct most_aim aim = { + .name = "networking", + .probe_channel = aim_probe_channel, + .disconnect_channel = aim_disconnect_channel, + .tx_completion = aim_resume_tx_channel, + .rx_completion = aim_rx_data, +}; + static int __init most_net_init(void) { pr_info("most_net_init()\n"); spin_lock_init(&list_lock); - aim.name = "networking"; - aim.probe_channel = aim_probe_channel; - aim.disconnect_channel = aim_disconnect_channel; - aim.tx_completion = aim_resume_tx_channel; - aim.rx_completion = aim_rx_data; return most_register_aim(&aim); } @@ -548,7 +551,7 @@ void most_deliver_netinfo(struct most_interface *iface, return; if (mac_addr) - memcpy(dev->dev_addr, mac_addr, ETH_ALEN); + ether_addr_copy(dev->dev_addr, mac_addr); if (nd->link_stat != link_stat) { nd->link_stat = link_stat; diff --git a/drivers/staging/most/aim-sound/sound.c b/drivers/staging/most/aim-sound/sound.c index 860302eeb..9c645801c 100644 --- a/drivers/staging/most/aim-sound/sound.c +++ b/drivers/staging/most/aim-sound/sound.c @@ -19,6 +19,7 @@ #include <linux/init.h> #include <sound/core.h> #include <sound/pcm.h> +#include <sound/pcm_params.h> #include <linux/sched.h> #include <linux/kthread.h> #include <mostcore.h> @@ -26,6 +27,7 @@ #define DRIVER_NAME "sound" static struct list_head dev_list; +static struct most_aim audio_aim; /** * struct channel - private structure to keep channel specific data @@ -44,6 +46,7 @@ static struct list_head dev_list; */ struct channel { struct snd_pcm_substream *substream; + struct snd_pcm_hardware pcm_hardware; struct most_interface *iface; struct most_channel_config *cfg; struct snd_card *card; @@ -65,18 +68,6 @@ struct channel { SNDRV_PCM_INFO_INTERLEAVED | \ SNDRV_PCM_INFO_BLOCK_TRANSFER) -/** - * Initialization of struct snd_pcm_hardware - */ -static struct snd_pcm_hardware pcm_hardware_template = { - .info = MOST_PCM_INFO, - .rates = SNDRV_PCM_RATE_48000, - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 1, - .channels_max = 8, -}; - #define swap16(val) ( \ (((u16)(val) << 8) & (u16)0xFF00) | \ (((u16)(val) >> 8) & (u16)0x00FF)) @@ -240,8 +231,6 @@ static int playback_thread(void *data) { struct channel *const channel = data; - pr_info("playback thread started\n"); - while (!kthread_should_stop()) { struct mbo *mbo = NULL; bool period_elapsed = false; @@ -250,8 +239,9 @@ static int playback_thread(void *data) wait_event_interruptible( channel->playback_waitq, kthread_should_stop() || - (mbo = most_get_mbo(channel->iface, channel->id))); - + (channel->is_stream_running && + (mbo = most_get_mbo(channel->iface, channel->id, + &audio_aim)))); if (!mbo) continue; @@ -286,32 +276,25 @@ static int pcm_open(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct most_channel_config *cfg = channel->cfg; - pr_info("pcm_open(), %s\n", substream->name); - channel->substream = substream; if (cfg->direction == MOST_CH_TX) { - init_waitqueue_head(&channel->playback_waitq); - channel->playback_task = kthread_run(&playback_thread, channel, + channel->playback_task = kthread_run(playback_thread, channel, "most_audio_playback"); - if (IS_ERR(channel->playback_task)) + if (IS_ERR(channel->playback_task)) { + pr_err("Couldn't start thread\n"); return PTR_ERR(channel->playback_task); + } } - if (most_start_channel(channel->iface, channel->id)) { + if (most_start_channel(channel->iface, channel->id, &audio_aim)) { pr_err("most_start_channel() failed!\n"); if (cfg->direction == MOST_CH_TX) kthread_stop(channel->playback_task); return -EBUSY; } - runtime->hw = pcm_hardware_template; - runtime->hw.buffer_bytes_max = cfg->num_buffers * cfg->buffer_size; - runtime->hw.period_bytes_min = cfg->buffer_size; - runtime->hw.period_bytes_max = cfg->buffer_size; - runtime->hw.periods_min = 1; - runtime->hw.periods_max = cfg->num_buffers; - + runtime->hw = channel->pcm_hardware; return 0; } @@ -329,11 +312,9 @@ static int pcm_close(struct snd_pcm_substream *substream) { struct channel *channel = substream->private_data; - pr_info("pcm_close(), %s\n", substream->name); - if (channel->cfg->direction == MOST_CH_TX) kthread_stop(channel->playback_task); - most_stop_channel(channel->iface, channel->id); + most_stop_channel(channel->iface, channel->id, &audio_aim); return 0; } @@ -353,8 +334,13 @@ static int pcm_close(struct snd_pcm_substream *substream) static int pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { - pr_info("pcm_hw_params()\n"); + struct channel *channel = substream->private_data; + if ((params_channels(hw_params) > channel->pcm_hardware.channels_max) || + (params_channels(hw_params) < channel->pcm_hardware.channels_min)) { + pr_err("Requested number of channels not supported.\n"); + return -EINVAL; + } return snd_pcm_lib_alloc_vmalloc_buffer(substream, params_buffer_bytes(hw_params)); } @@ -370,8 +356,6 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, */ static int pcm_hw_free(struct snd_pcm_substream *substream) { - pr_info("pcm_hw_free()\n"); - return snd_pcm_lib_free_vmalloc_buffer(substream); } @@ -441,6 +425,7 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd) switch (cmd) { case SNDRV_PCM_TRIGGER_START: channel->is_stream_running = true; + wake_up_interruptible(&channel->playback_waitq); return 0; case SNDRV_PCM_TRIGGER_STOP: @@ -485,8 +470,7 @@ static struct snd_pcm_ops pcm_ops = { .mmap = snd_pcm_lib_mmap_vmalloc, }; - -int split_arg_list(char *buf, char **card_name, char **pcm_format) +static int split_arg_list(char *buf, char **card_name, char **pcm_format) { *card_name = strsep(&buf, "."); if (!*card_name) @@ -497,31 +481,59 @@ int split_arg_list(char *buf, char **card_name, char **pcm_format) return 0; } -int audio_set_pcm_format(char *pcm_format, struct most_channel_config *cfg) +static int audio_set_hw_params(struct snd_pcm_hardware *pcm_hw, + char *pcm_format, + struct most_channel_config *cfg) { + pcm_hw->info = MOST_PCM_INFO; + pcm_hw->rates = SNDRV_PCM_RATE_48000; + pcm_hw->rate_min = 48000; + pcm_hw->rate_max = 48000; + pcm_hw->buffer_bytes_max = cfg->num_buffers * cfg->buffer_size; + pcm_hw->period_bytes_min = cfg->buffer_size; + pcm_hw->period_bytes_max = cfg->buffer_size; + pcm_hw->periods_min = 1; + pcm_hw->periods_max = cfg->num_buffers; + if (!strcmp(pcm_format, "1x8")) { if (cfg->subbuffer_size != 1) goto error; pr_info("PCM format is 8-bit mono\n"); - pcm_hardware_template.formats = SNDRV_PCM_FMTBIT_S8; + pcm_hw->channels_min = 1; + pcm_hw->channels_max = 1; + pcm_hw->formats = SNDRV_PCM_FMTBIT_S8; } else if (!strcmp(pcm_format, "2x16")) { if (cfg->subbuffer_size != 4) goto error; pr_info("PCM format is 16-bit stereo\n"); - pcm_hardware_template.formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S16_BE; + pcm_hw->channels_min = 2; + pcm_hw->channels_max = 2; + pcm_hw->formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S16_BE; } else if (!strcmp(pcm_format, "2x24")) { if (cfg->subbuffer_size != 6) goto error; pr_info("PCM format is 24-bit stereo\n"); - pcm_hardware_template.formats = SNDRV_PCM_FMTBIT_S24_3LE | - SNDRV_PCM_FMTBIT_S24_3BE; + pcm_hw->channels_min = 2; + pcm_hw->channels_max = 2; + pcm_hw->formats = SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S24_3BE; } else if (!strcmp(pcm_format, "2x32")) { if (cfg->subbuffer_size != 8) goto error; pr_info("PCM format is 32-bit stereo\n"); - pcm_hardware_template.formats = SNDRV_PCM_FMTBIT_S32_LE | - SNDRV_PCM_FMTBIT_S32_BE; + pcm_hw->channels_min = 2; + pcm_hw->channels_max = 2; + pcm_hw->formats = SNDRV_PCM_FMTBIT_S32_LE | + SNDRV_PCM_FMTBIT_S32_BE; + } else if (!strcmp(pcm_format, "6x16")) { + if (cfg->subbuffer_size != 12) + goto error; + pr_info("PCM format is 16-bit 5.1 multi channel\n"); + pcm_hw->channels_min = 6; + pcm_hw->channels_max = 6; + pcm_hw->formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S16_BE; } else { pr_err("PCM format %s not supported\n", pcm_format); return -EIO; @@ -559,8 +571,6 @@ static int audio_probe_channel(struct most_interface *iface, int channel_id, char *card_name; char *pcm_format; - pr_info("sound_probe_channel()\n"); - if (!iface) return -EINVAL; @@ -588,8 +598,6 @@ static int audio_probe_channel(struct most_interface *iface, int channel_id, pr_info("PCM format missing\n"); return ret; } - if (audio_set_pcm_format(pcm_format, cfg)) - return ret; ret = snd_card_new(NULL, -1, card_name, THIS_MODULE, sizeof(*channel), &card); @@ -601,9 +609,13 @@ static int audio_probe_channel(struct most_interface *iface, int channel_id, channel->cfg = cfg; channel->iface = iface; channel->id = channel_id; + init_waitqueue_head(&channel->playback_waitq); + + if (audio_set_hw_params(&channel->pcm_hardware, pcm_format, cfg)) + goto err_free_card; snprintf(card->driver, sizeof(card->driver), "%s", DRIVER_NAME); - snprintf(card->shortname, sizeof(card->shortname), "MOST:%d", + snprintf(card->shortname, sizeof(card->shortname), "Microchip MOST:%d", card->number); snprintf(card->longname, sizeof(card->longname), "%s at %s, ch %d", card->shortname, iface->description, channel_id); @@ -644,8 +656,6 @@ static int audio_disconnect_channel(struct most_interface *iface, { struct channel *channel; - pr_info("sound_disconnect_channel()\n"); - channel = get_channel(iface, channel_id); if (!channel) { pr_err("sound_disconnect_channel(), invalid channel %d\n", diff --git a/drivers/staging/most/aim-v4l2/Makefile b/drivers/staging/most/aim-v4l2/Makefile index 28aa948d6..69a7524b4 100644 --- a/drivers/staging/most/aim-v4l2/Makefile +++ b/drivers/staging/most/aim-v4l2/Makefile @@ -3,4 +3,3 @@ obj-$(CONFIG_AIM_V4L2) += aim_v4l2.o aim_v4l2-objs := video.o ccflags-y += -Idrivers/staging/most/mostcore/ -ccflags-y += -Idrivers/media/video diff --git a/drivers/staging/most/aim-v4l2/video.c b/drivers/staging/most/aim-v4l2/video.c index d9687910e..13abf7c27 100644 --- a/drivers/staging/most/aim-v4l2/video.c +++ b/drivers/staging/most/aim-v4l2/video.c @@ -29,9 +29,9 @@ #include "mostcore.h" - #define V4L2_AIM_MAX_INPUT 1 +static struct most_aim aim_info; struct most_video_dev { struct most_interface *iface; @@ -59,11 +59,8 @@ struct aim_fh { u32 offs; }; - static struct list_head video_devices = LIST_HEAD_INIT(video_devices); static struct spinlock list_lock; -static struct most_aim aim_info; - static inline bool data_ready(struct most_video_dev *mdev) { @@ -75,7 +72,6 @@ static inline struct mbo *get_top_mbo(struct most_video_dev *mdev) return list_first_entry(&mdev->pending_mbos, struct mbo, list); } - static int aim_vdev_open(struct file *filp) { int ret; @@ -92,7 +88,7 @@ static int aim_vdev_open(struct file *filp) return -EINVAL; } - fh = kzalloc(sizeof(struct aim_fh), GFP_KERNEL); + fh = kzalloc(sizeof(*fh), GFP_KERNEL); if (!fh) return -ENOMEM; @@ -108,7 +104,7 @@ static int aim_vdev_open(struct file *filp) v4l2_fh_add(&fh->fh); - ret = most_start_channel(mdev->iface, mdev->ch_idx); + ret = most_start_channel(mdev->iface, mdev->ch_idx, &aim_info); if (ret) { pr_err("most_start_channel() failed\n"); goto err_rm; @@ -152,7 +148,7 @@ static int aim_vdev_close(struct file *filp) spin_lock(&mdev->list_lock); } spin_unlock(&mdev->list_lock); - most_stop_channel(mdev->iface, mdev->ch_idx); + most_stop_channel(mdev->iface, mdev->ch_idx, &aim_info); mdev->mute = false; v4l2_fh_del(&fh->fh); @@ -243,28 +239,6 @@ static void aim_set_format_struct(struct v4l2_format *f) static int aim_set_format(struct most_video_dev *mdev, unsigned int cmd, struct v4l2_format *format) { -#if 0 - u32 const pixfmt = format->fmt.pix.pixelformat; - const char *fmt; - - if (pixfmt != V4L2_PIX_FMT_MPEG) { - if (cmd == VIDIOC_TRY_FMT) - fmt = KERN_ERR "try %c%c%c%c failed\n"; - else - fmt = KERN_ERR "set %c%c%c%c failed\n"; - } else { - if (cmd == VIDIOC_TRY_FMT) - fmt = KERN_ERR "try %c%c%c%c\n"; - else - fmt = KERN_ERR "set %c%c%c%c\n"; - } - printk(fmt, - (pixfmt) & 255, - (pixfmt >> 8) & 255, - (pixfmt >> 16) & 255, - (pixfmt >> 24) & 255); -#endif - if (format->fmt.pix.pixelformat != V4L2_PIX_FMT_MPEG) return -EINVAL; @@ -276,7 +250,6 @@ static int aim_set_format(struct most_video_dev *mdev, unsigned int cmd, return 0; } - static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { @@ -430,7 +403,7 @@ static struct most_video_dev *get_aim_dev( } } spin_unlock(&list_lock); - return 0; + return NULL; } static int aim_rx_data(struct mbo *mbo) @@ -496,7 +469,6 @@ static void aim_unregister_videodev(struct most_video_dev *mdev) video_unregister_device(mdev->vdev); } - static void aim_v4l2_dev_release(struct v4l2_device *v4l2_dev) { struct most_video_dev *mdev = @@ -590,14 +562,16 @@ static int aim_disconnect_channel(struct most_interface *iface, return 0; } +static struct most_aim aim_info = { + .name = "v4l", + .probe_channel = aim_probe_channel, + .disconnect_channel = aim_disconnect_channel, + .rx_completion = aim_rx_data, +}; + static int __init aim_init(void) { spin_lock_init(&list_lock); - - aim_info.name = "v4l"; - aim_info.probe_channel = aim_probe_channel; - aim_info.disconnect_channel = aim_disconnect_channel; - aim_info.rx_completion = aim_rx_data; return most_register_aim(&aim_info); } diff --git a/drivers/staging/most/hdm-dim2/Kconfig b/drivers/staging/most/hdm-dim2/Kconfig index fc5487694..28a0e1791 100644 --- a/drivers/staging/most/hdm-dim2/Kconfig +++ b/drivers/staging/most/hdm-dim2/Kconfig @@ -9,7 +9,7 @@ config HDM_DIM2 ---help--- Say Y here if you want to connect via MediaLB to network transceiver. - This device driver is platform dependent and needs an addtional + This device driver is platform dependent and needs an additional platform driver to be installed. For more information contact maintainer of this driver. diff --git a/drivers/staging/most/hdm-dim2/dim2_hal.c b/drivers/staging/most/hdm-dim2/dim2_hal.c index a54cf2ced..c915c44f0 100644 --- a/drivers/staging/most/hdm-dim2/dim2_hal.c +++ b/drivers/staging/most/hdm-dim2/dim2_hal.c @@ -19,7 +19,6 @@ #include "dim2_reg.h" #include <linux/stddef.h> - /* * The number of frames per sub-buffer for synchronous channels. * Allowed values: 1, 2, 4, 8, 16, 32, 64. @@ -51,7 +50,6 @@ */ #define DBR_MAP_SIZE 2 - /* -------------------------------------------------------------------------- */ /* not configurable area */ @@ -60,10 +58,9 @@ #define MLB_CAT 0x80 #define AHB_CAT 0x88 -#define DBR_SIZE (16*1024) /* specified by IP */ +#define DBR_SIZE (16 * 1024) /* specified by IP */ #define DBR_BLOCK_SIZE (DBR_SIZE / 32 / DBR_MAP_SIZE) - /* -------------------------------------------------------------------------- */ /* generic helper functions and macros */ @@ -81,7 +78,6 @@ static inline bool dim_on_error(u8 error_id, const char *error_message) return false; } - /* -------------------------------------------------------------------------- */ /* types and local variables */ @@ -94,7 +90,6 @@ struct lld_global_vars_t { static struct lld_global_vars_t g = { false }; - /* -------------------------------------------------------------------------- */ static int dbr_get_mask_size(u16 size) @@ -134,7 +129,7 @@ static int alloc_dbr(u16 size) return block_idx * DBR_BLOCK_SIZE; } block_idx += mask_size; - /* do shift left with 2 steps for case mask_size == 32 */ + /* do shift left with 2 steps in case mask_size == 32 */ mask <<= mask_size - 1; } while ((mask <<= 1) != 0); } @@ -327,7 +322,6 @@ static void dim2_start_isoc_sync(u8 ch_addr, u8 idx, u32 buf_addr, dim2_write_ctr_mask(ADT + ch_addr, mask, adt); } - static void dim2_clear_ctram(void) { u32 ctr_addr; @@ -499,22 +493,6 @@ static void dim2_initialize(bool enable_6pin, u8 mlb_clock) DIMCB_IoWrite(&g.dim2->ACTL, ACTL_DMA_MODE_VAL_DMA_MODE_1 << ACTL_DMA_MODE_BIT | true << ACTL_SCE_BIT); - -#if 0 - DIMCB_IoWrite(&g.dim2->MIEN, - bit_mask(MIEN_CTX_BREAK_BIT) | - bit_mask(MIEN_CTX_PE_BIT) | - bit_mask(MIEN_CTX_DONE_BIT) | - bit_mask(MIEN_CRX_BREAK_BIT) | - bit_mask(MIEN_CRX_PE_BIT) | - bit_mask(MIEN_CRX_DONE_BIT) | - bit_mask(MIEN_ATX_BREAK_BIT) | - bit_mask(MIEN_ATX_PE_BIT) | - bit_mask(MIEN_ATX_DONE_BIT) | - bit_mask(MIEN_ARX_BREAK_BIT) | - bit_mask(MIEN_ARX_PE_BIT) | - bit_mask(MIEN_ARX_DONE_BIT)); -#endif } static bool dim2_is_mlb_locked(void) @@ -530,7 +508,6 @@ static bool dim2_is_mlb_locked(void) (DIMCB_IoRead(&g.dim2->MLBC0) & mask0) != 0; } - /* -------------------------------------------------------------------------- */ /* channel help routines */ @@ -559,7 +536,6 @@ static inline bool service_channel(u8 ch_addr, u8 idx) return true; } - /* -------------------------------------------------------------------------- */ /* channel init routines */ @@ -639,7 +615,8 @@ static bool channel_start(struct dim_channel *ch, u32 buf_addr, u16 buf_size) if (ch->packet_length || ch->bytes_per_frame) dim2_start_isoc_sync(ch->addr, state->idx1, buf_addr, buf_size); else - dim2_start_ctrl_async(ch->addr, state->idx1, buf_addr, buf_size); + dim2_start_ctrl_async(ch->addr, state->idx1, buf_addr, + buf_size); state->idx1 ^= 1; return true; @@ -670,7 +647,6 @@ static bool channel_detach_buffers(struct dim_channel *ch, u16 buffers_number) return true; } - /* -------------------------------------------------------------------------- */ /* API */ @@ -687,7 +663,8 @@ u8 DIM_Startup(void *dim_base_address, u32 mlb_clock) return DIM_INIT_ERR_MLB_CLOCK; g.dim2 = dim_base_address; - g.dbr_map[0] = g.dbr_map[1] = 0; + g.dbr_map[0] = 0; + g.dbr_map[1] = 0; dim2_initialize(mlb_clock >= 3, mlb_clock); @@ -766,14 +743,14 @@ u8 DIM_InitControl(struct dim_channel *ch, u8 is_tx, u16 ch_address, u16 max_buffer_size) { return init_ctrl_async(ch, CAT_CT_VAL_CONTROL, is_tx, ch_address, - max_buffer_size * 2); + max_buffer_size); } u8 DIM_InitAsync(struct dim_channel *ch, u8 is_tx, u16 ch_address, u16 max_buffer_size) { return init_ctrl_async(ch, CAT_CT_VAL_ASYNC, is_tx, ch_address, - max_buffer_size * 2); + max_buffer_size); } u8 DIM_InitIsoc(struct dim_channel *ch, u8 is_tx, u16 ch_address, @@ -855,11 +832,11 @@ void DIM_ServiceIrq(struct dim_channel *const *channels) } /* - * Use while-loop and a flag to make sure the age is changed back at least once, - * otherwise the interrupt may never come if CPU generates interrupt on changing age. - * - * This cycle runs not more than number of channels, because service_interrupts - * routine doesn't start the channel again. + * Use while-loop and a flag to make sure the age is changed back at + * least once, otherwise the interrupt may never come if CPU generates + * interrupt on changing age. + * This cycle runs not more than number of channels, because + * channel_service_interrupt() routine doesn't start the channel again. */ do { struct dim_channel *const *ch = channels; @@ -886,7 +863,7 @@ u8 DIM_ServiceChannel(struct dim_channel *ch) } struct dim_ch_state_t *DIM_GetChannelState(struct dim_channel *ch, - struct dim_ch_state_t *state_ptr) + struct dim_ch_state_t *state_ptr) { if (!ch || !state_ptr) return NULL; @@ -900,7 +877,8 @@ struct dim_ch_state_t *DIM_GetChannelState(struct dim_channel *ch, bool DIM_EnqueueBuffer(struct dim_channel *ch, u32 buffer_addr, u16 buffer_size) { if (!ch) - return dim_on_error(DIM_ERR_DRIVER_NOT_INITIALIZED, "Bad channel"); + return dim_on_error(DIM_ERR_DRIVER_NOT_INITIALIZED, + "Bad channel"); return channel_start(ch, buffer_addr, buffer_size); } @@ -908,12 +886,8 @@ bool DIM_EnqueueBuffer(struct dim_channel *ch, u32 buffer_addr, u16 buffer_size) bool DIM_DetachBuffers(struct dim_channel *ch, u16 buffers_number) { if (!ch) - return dim_on_error(DIM_ERR_DRIVER_NOT_INITIALIZED, "Bad channel"); + return dim_on_error(DIM_ERR_DRIVER_NOT_INITIALIZED, + "Bad channel"); return channel_detach_buffers(ch, buffers_number); } - -u32 DIM_ReadRegister(u8 register_index) -{ - return DIMCB_IoRead((u32 *)g.dim2 + register_index); -} diff --git a/drivers/staging/most/hdm-dim2/dim2_hal.h b/drivers/staging/most/hdm-dim2/dim2_hal.h index 8929af971..ebb7d87a4 100644 --- a/drivers/staging/most/hdm-dim2/dim2_hal.h +++ b/drivers/staging/most/hdm-dim2/dim2_hal.h @@ -105,17 +105,12 @@ bool DIM_EnqueueBuffer(struct dim_channel *ch, u32 buffer_addr, bool DIM_DetachBuffers(struct dim_channel *ch, u16 buffers_number); -u32 DIM_ReadRegister(u8 register_index); - - u32 DIMCB_IoRead(u32 *ptr32); void DIMCB_IoWrite(u32 *ptr32, u32 value); void DIMCB_OnError(u8 error_id, const char *error_message); -void DIMCB_OnFail(const char *filename, int linenum); - #ifdef __cplusplus } diff --git a/drivers/staging/most/hdm-dim2/dim2_hdm.c b/drivers/staging/most/hdm-dim2/dim2_hdm.c index 6a5a3a277..b6fe346f7 100644 --- a/drivers/staging/most/hdm-dim2/dim2_hdm.c +++ b/drivers/staging/most/hdm-dim2/dim2_hdm.c @@ -37,7 +37,7 @@ #define MAX_BUFFERS_PACKET 32 #define MAX_BUFFERS_STREAMING 32 #define MAX_BUF_SIZE_PACKET 2048 -#define MAX_BUF_SIZE_STREAMING (8*1024) +#define MAX_BUF_SIZE_STREAMING (8 * 1024) /* command line parameter to select clock speed */ static char *clock_speed; @@ -166,16 +166,6 @@ void DIMCB_OnError(u8 error_id, const char *error_message) } /** - * DIMCB_OnFail - callback from HAL to report unrecoverable errors - * @filename: Source file where the error happened - * @linenum: Line number of the file where the error happened - */ -void DIMCB_OnFail(const char *filename, int linenum) -{ - pr_err("DIMCB_OnFail: file - %s, line no. - %d\n", filename, linenum); -} - -/** * startup_dim - initialize the dim2 interface * @pdev: platform device * @@ -210,12 +200,11 @@ static int startup_dim(struct platform_device *pdev) } if (dev->clk_speed == -1) { - pr_info("Bad or missing clock speed parameter," - " using default value: 3072fs\n"); + pr_info("Bad or missing clock speed parameter, using default value: 3072fs\n"); dev->clk_speed = CLK_3072FS; - } else + } else { pr_info("Selected clock speed: %s\n", clock_speed); - + } if (pdata && pdata->init) { int ret = pdata->init(pdata, dev->io_base, dev->clk_speed); @@ -248,7 +237,7 @@ static int try_start_dim_transfer(struct hdm_channel *hdm_ch) unsigned long flags; struct dim_ch_state_t st; - BUG_ON(hdm_ch == 0); + BUG_ON(!hdm_ch); BUG_ON(!hdm_ch->is_initialized); spin_lock_irqsave(&dim_lock, flags); @@ -289,7 +278,7 @@ static int try_start_dim_transfer(struct hdm_channel *hdm_ch) */ static int deliver_netinfo_thread(void *data) { - struct dim2_hdm *dev = (struct dim2_hdm *)data; + struct dim2_hdm *dev = data; while (!kthread_should_stop()) { wait_event_interruptible(dev->netinfo_waitq, @@ -346,7 +335,7 @@ static void service_done_flag(struct dim2_hdm *dev, int ch_idx) unsigned long flags; u8 *data; - BUG_ON(hdm_ch == 0); + BUG_ON(!hdm_ch); BUG_ON(!hdm_ch->is_initialized); spin_lock_irqsave(&dim_lock, flags); @@ -369,8 +358,7 @@ static void service_done_flag(struct dim2_hdm *dev, int ch_idx) spin_lock_irqsave(&dim_lock, flags); if (list_empty(head)) { spin_unlock_irqrestore(&dim_lock, flags); - pr_crit("hard error: started_mbo list is empty " - "whereas DIM2 has sent buffers\n"); + pr_crit("hard error: started_mbo list is empty whereas DIM2 has sent buffers\n"); break; } @@ -397,7 +385,8 @@ static void service_done_flag(struct dim2_hdm *dev, int ch_idx) (u32)data[0] * 256 + data[1] + 2; mbo->processed_length = - min(data_size, (u32)mbo->buffer_length); + min_t(u32, data_size, + mbo->buffer_length); } else { mbo->processed_length = mbo->buffer_length; } @@ -410,7 +399,7 @@ static void service_done_flag(struct dim2_hdm *dev, int ch_idx) } static struct dim_channel **get_active_channels(struct dim2_hdm *dev, - struct dim_channel **buffer) + struct dim_channel **buffer) { int idx = 0; int ch_idx; @@ -419,7 +408,7 @@ static struct dim_channel **get_active_channels(struct dim2_hdm *dev, if (dev->hch[ch_idx].is_initialized) buffer[idx++] = &dev->hch[ch_idx].ch; } - buffer[idx++] = 0; + buffer[idx++] = NULL; return buffer; } @@ -441,7 +430,7 @@ static void dim2_tasklet_fn(unsigned long data) continue; spin_lock_irqsave(&dim_lock, flags); - DIM_ServiceChannel(&(dev->hch[ch_idx].ch)); + DIM_ServiceChannel(&dev->hch[ch_idx].ch); spin_unlock_irqrestore(&dim_lock, flags); service_done_flag(dev, ch_idx); @@ -460,7 +449,7 @@ static void dim2_tasklet_fn(unsigned long data) */ static irqreturn_t dim2_ahb_isr(int irq, void *_dev) { - struct dim2_hdm *dev = (struct dim2_hdm *)_dev; + struct dim2_hdm *dev = _dev; struct dim_channel *buffer[DMA_CHANNELS + 1]; unsigned long flags; @@ -557,7 +546,8 @@ static int configure_channel(struct most_interface *most_iface, int ch_idx, pr_warn("%s: fixed buffer size (%d -> %d)\n", hdm_ch->name, buf_size, new_size); spin_lock_irqsave(&dim_lock, flags); - hal_ret = DIM_InitControl(&hdm_ch->ch, is_tx, ch_addr, buf_size); + hal_ret = DIM_InitControl(&hdm_ch->ch, is_tx, ch_addr, + buf_size); break; case MOST_CH_ASYNC: new_size = DIM_NormCtrlAsyncBufferSize(buf_size); @@ -575,8 +565,8 @@ static int configure_channel(struct most_interface *most_iface, int ch_idx, case MOST_CH_ISOC_AVP: new_size = DIM_NormIsocBufferSize(buf_size, sub_size); if (new_size == 0) { - pr_err("%s: invalid sub-buffer size or " - "too small buffer size\n", hdm_ch->name); + pr_err("%s: invalid sub-buffer size or too small buffer size\n", + hdm_ch->name); return -EINVAL; } ccfg->buffer_size = new_size; @@ -589,8 +579,8 @@ static int configure_channel(struct most_interface *most_iface, int ch_idx, case MOST_CH_SYNC: new_size = DIM_NormSyncBufferSize(buf_size, sub_size); if (new_size == 0) { - pr_err("%s: invalid sub-buffer size or " - "too small buffer size\n", hdm_ch->name); + pr_err("%s: invalid sub-buffer size or too small buffer size\n", + hdm_ch->name); return -EINVAL; } ccfg->buffer_size = new_size; @@ -679,7 +669,7 @@ static void request_netinfo(struct most_interface *most_iface, int ch_idx) return; } - mbo = most_get_mbo(&dev->most_iface, dev->atx_idx); + mbo = most_get_mbo(&dev->most_iface, dev->atx_idx, NULL); if (!mbo) return; @@ -787,7 +777,8 @@ static int dim2_probe(struct platform_device *pdev) ret = request_irq(dev->irq_ahb0, dim2_ahb_isr, 0, "mlb_ahb0", dev); if (ret) { - pr_err("failed to request IRQ: %d, err: %d\n", dev->irq_ahb0, ret); + pr_err("failed to request IRQ: %d, err: %d\n", + dev->irq_ahb0, ret); goto err_unmap_io; } #endif @@ -915,7 +906,7 @@ static int dim2_remove(struct platform_device *pdev) * break link to local platform_device_id struct * to prevent crash by unload platform device module */ - pdev->id_entry = 0; + pdev->id_entry = NULL; return 0; } @@ -933,30 +924,10 @@ static struct platform_driver dim2_driver = { .id_table = dim2_id, .driver = { .name = "hdm_dim2", - .owner = THIS_MODULE, }, }; -/** - * dim2_hdm_init - Driver Registration Routine - */ -static int __init dim2_hdm_init(void) -{ - pr_info("dim2_hdm_init()\n"); - return platform_driver_register(&dim2_driver); -} - -/** - * dim2_hdm_exit - Driver Cleanup Routine - **/ -static void __exit dim2_hdm_exit(void) -{ - pr_info("dim2_hdm_exit()\n"); - platform_driver_unregister(&dim2_driver); -} - -module_init(dim2_hdm_init); -module_exit(dim2_hdm_exit); +module_platform_driver(dim2_driver); MODULE_AUTHOR("Jain Roy Ambi <JainRoy.Ambi@microchip.com>"); MODULE_AUTHOR("Andrey Shvetsov <andrey.shvetsov@k2l.de>"); diff --git a/drivers/staging/most/hdm-dim2/dim2_hdm.h b/drivers/staging/most/hdm-dim2/dim2_hdm.h index 6e6883232..1c94e3355 100644 --- a/drivers/staging/most/hdm-dim2/dim2_hdm.h +++ b/drivers/staging/most/hdm-dim2/dim2_hdm.h @@ -18,7 +18,8 @@ struct device; /* platform dependent data for dim2 interface */ struct dim2_platform_data { - int (*init)(struct dim2_platform_data *pd, void *io_base, int clk_speed); + int (*init)(struct dim2_platform_data *pd, void *io_base, + int clk_speed); void (*destroy)(struct dim2_platform_data *pd); void *priv; }; diff --git a/drivers/staging/most/hdm-dim2/dim2_sysfs.c b/drivers/staging/most/hdm-dim2/dim2_sysfs.c index 8e331a286..c5b10c7d2 100644 --- a/drivers/staging/most/hdm-dim2/dim2_sysfs.c +++ b/drivers/staging/most/hdm-dim2/dim2_sysfs.c @@ -21,7 +21,8 @@ struct bus_attr { struct attribute attr; ssize_t (*show)(struct medialb_bus *bus, char *buf); - ssize_t (*store)(struct medialb_bus *bus, const char *buf, size_t count); + ssize_t (*store)(struct medialb_bus *bus, const char *buf, + size_t count); }; static ssize_t state_show(struct medialb_bus *bus, char *buf) diff --git a/drivers/staging/most/hdm-i2c/hdm_i2c.c b/drivers/staging/most/hdm-i2c/hdm_i2c.c index 029ded3f2..ba0263bb3 100644 --- a/drivers/staging/most/hdm-i2c/hdm_i2c.c +++ b/drivers/staging/most/hdm-i2c/hdm_i2c.c @@ -35,7 +35,6 @@ enum { CH_RX, CH_TX, NUM_CHANNELS }; #define list_first_mbo(ptr) \ list_first_entry(ptr, struct mbo, list) - /* IRQ / Polling option */ static bool polling_req; module_param(polling_req, bool, S_IRUGO); @@ -93,10 +92,9 @@ static int configure_channel(struct most_interface *most_iface, return -EPERM; } - if (channel_config->direction == MOST_CH_RX) { - if (dev->polling_mode) - schedule_delayed_work(&dev->rx.dwork, - msecs_to_jiffies(MSEC_PER_SEC / 4)); + if ((channel_config->direction == MOST_CH_RX) && (dev->polling_mode)) { + schedule_delayed_work(&dev->rx.dwork, + msecs_to_jiffies(MSEC_PER_SEC / 4)); } dev->is_open[ch_idx] = true; @@ -198,7 +196,7 @@ static void do_rx_work(struct hdm_i2c *dev) struct mbo *mbo; unsigned char msg[MAX_BUF_SIZE_CONTROL]; int ret, ch_idx = CH_RX; - uint16_t pml, data_size; + u16 pml, data_size; /* Read PML (2 bytes) */ ret = i2c_master_recv(dev->client, msg, 2); @@ -222,7 +220,8 @@ static void do_rx_work(struct hdm_i2c *dev) for (;;) { /* Conditions to wait for: poisoned channel or free buffer - available for reading */ + * available for reading + */ if (wait_event_interruptible(dev->rx.waitq, !dev->is_open[ch_idx] || !list_empty(&dev->rx.list))) { @@ -269,8 +268,9 @@ static void pending_rx_work(struct work_struct *work) schedule_delayed_work(&dev->rx.dwork, msecs_to_jiffies(MSEC_PER_SEC / scan_rate)); - } else + } else { enable_irq(dev->client->irq); + } } /* @@ -364,11 +364,11 @@ static int i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) dev->polling_mode = polling_req || client->irq <= 0; if (!dev->polling_mode) { pr_info("Requesting IRQ: %d\n", client->irq); - ret = request_irq(client->irq, most_irq_handler, IRQF_SHARED, + ret = request_irq(client->irq, most_irq_handler, 0, client->name, dev); if (ret) { - pr_info("IRQ request failed: %d, " - "falling back to polling\n", ret); + pr_info("IRQ request failed: %d, falling back to polling\n", + ret); dev->polling_mode = true; } } @@ -416,34 +416,13 @@ MODULE_DEVICE_TABLE(i2c, i2c_id); static struct i2c_driver i2c_driver = { .driver = { .name = "hdm_i2c", - .owner = THIS_MODULE, }, .probe = i2c_probe, .remove = i2c_remove, .id_table = i2c_id, }; -/** - * hdm_i2c_init - Driver Registration Routine - */ -static int __init hdm_i2c_init(void) -{ - pr_info("hdm_i2c_init()\n"); - - return i2c_add_driver(&i2c_driver); -} - -/** - * hdm_i2c_exit - Driver Cleanup Routine - **/ -static void __exit hdm_i2c_exit(void) -{ - i2c_del_driver(&i2c_driver); - pr_info("hdm_i2c_exit()\n"); -} - -module_init(hdm_i2c_init); -module_exit(hdm_i2c_exit); +module_i2c_driver(i2c_driver); MODULE_AUTHOR("Jain Roy Ambi <JainRoy.Ambi@microchip.com>"); MODULE_AUTHOR("Andrey Shvetsov <andrey.shvetsov@k2l.de>"); diff --git a/drivers/staging/most/hdm-usb/hdm_usb.c b/drivers/staging/most/hdm-usb/hdm_usb.c index 305303f2f..41690f801 100644 --- a/drivers/staging/most/hdm-usb/hdm_usb.c +++ b/drivers/staging/most/hdm-usb/hdm_usb.c @@ -59,6 +59,8 @@ #define DRCI_REG_HW_ADDR_HI 0x0145 #define DRCI_REG_HW_ADDR_MI 0x0146 #define DRCI_REG_HW_ADDR_LO 0x0147 +#define DRCI_REG_BASE 0x1100 +#define DRCI_COMMAND 0x02 #define DRCI_READ_REQ 0xA0 #define DRCI_WRITE_REQ 0xA1 @@ -75,6 +77,7 @@ struct buf_anchor { struct list_head list; struct completion urb_compl; }; + #define to_buf_anchor(w) container_of(w, struct buf_anchor, clear_work_obj) /** @@ -86,6 +89,7 @@ struct most_dci_obj { struct kobject kobj; struct usb_device *usb_device; }; + #define to_dci_obj(p) container_of(p, struct most_dci_obj, kobj) /** @@ -129,6 +133,7 @@ struct most_dev { struct timer_list link_stat_timer; struct work_struct poll_work_obj; }; + #define to_mdev(d) container_of(d, struct most_dev, iface) #define to_mdev_from_work(w) container_of(w, struct most_dev, poll_work_obj) @@ -137,36 +142,6 @@ static void wq_clear_halt(struct work_struct *wq_obj); static void wq_netinfo(struct work_struct *wq_obj); /** - * trigger_resync_vr - Vendor request to trigger HW re-sync mechanism - * @dev: usb device - * - */ -static void trigger_resync_vr(struct usb_device *dev) -{ - int retval; - u8 request_type = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT; - int *data = kzalloc(sizeof(*data), GFP_KERNEL); - - if (!data) - goto error; - *data = HW_RESYNC; - retval = usb_control_msg(dev, - usb_sndctrlpipe(dev, 0), - 0, - request_type, - 0, - 0, - data, - 0, - 5 * HZ); - kfree(data); - if (retval >= 0) - return; -error: - dev_err(&dev->dev, "Vendor request \"stall\" failed\n"); -} - -/** * drci_rd_reg - read a DCI register * @dev: usb device * @reg: register address @@ -174,17 +149,23 @@ error: * * This is reads data from INIC's direct register communication interface */ -static inline int drci_rd_reg(struct usb_device *dev, u16 reg, void *buf) +static inline int drci_rd_reg(struct usb_device *dev, u16 reg, u16 *buf) { - return usb_control_msg(dev, - usb_rcvctrlpipe(dev, 0), - DRCI_READ_REQ, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x0000, - reg, - buf, - 2, - 5 * HZ); + int retval; + u16 *dma_buf = kzalloc(sizeof(u16), GFP_KERNEL); + u8 req_type = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE; + + if (!dma_buf) + return -ENOMEM; + + retval = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + DRCI_READ_REQ, req_type, + 0x0000, + reg, dma_buf, sizeof(u16), 5 * HZ); + *buf = le16_to_cpu(*dma_buf); + kfree(dma_buf); + + return retval; } /** @@ -220,7 +201,8 @@ static void free_anchored_buffers(struct most_dev *mdev, unsigned int channel) unsigned long flags; spin_lock_irqsave(&mdev->anchor_list_lock[channel], flags); - list_for_each_entry_safe(anchor, tmp, &mdev->anchor_list[channel], list) { + list_for_each_entry_safe(anchor, tmp, &mdev->anchor_list[channel], + list) { struct urb *urb = anchor->urb; spin_unlock_irqrestore(&mdev->anchor_list_lock[channel], flags); @@ -267,10 +249,11 @@ static unsigned int get_stream_frame_size(struct most_channel_config *cfg) if (cfg->packets_per_xact == 0) { pr_warn("Misconfig: Packets per XACT zero\n"); frame_size = 0; - } else if (cfg->packets_per_xact == 0xFF) + } else if (cfg->packets_per_xact == 0xFF) { frame_size = (USB_MTU / sub_size) * sub_size; - else + } else { frame_size = cfg->packets_per_xact * sub_size; + } break; default: pr_warn("Query frame size of non-streaming channel\n"); @@ -308,7 +291,7 @@ static int hdm_poison_channel(struct most_interface *iface, int channel) mutex_lock(&mdev->io_mutex); free_anchored_buffers(mdev, channel); - if (mdev->padding_active[channel] == true) + if (mdev->padding_active[channel]) mdev->padding_active[channel] = false; if (mdev->conf[channel].data_type == MOST_CH_ASYNC) { @@ -365,7 +348,8 @@ static int hdm_add_padding(struct most_dev *mdev, int channel, struct mbo *mbo) * This takes the INIC hardware specific padding bytes off a streaming * channel's buffer. */ -static int hdm_remove_padding(struct most_dev *mdev, int channel, struct mbo *mbo) +static int hdm_remove_padding(struct most_dev *mdev, int channel, + struct mbo *mbo) { unsigned int j, num_frames, frame_size; struct most_channel_config *const conf = &mdev->conf[channel]; @@ -411,7 +395,7 @@ static void hdm_write_completion(struct urb *urb) dev = &mdev->usb_device->dev; if ((urb->status == -ENOENT) || (urb->status == -ECONNRESET) || - (mdev->is_channel_healthy[channel] == false)) { + (!mdev->is_channel_healthy[channel])) { complete(&anchor->urb_compl); return; } @@ -453,7 +437,7 @@ static void hdm_write_completion(struct urb *urb) } /** - * hdm_read_completion - completion funciton for submitted Rx URBs + * hdm_read_completion - completion function for submitted Rx URBs * @urb: the URB that has been completed * * This checks the status of the completed URB. In case the URB has been @@ -568,7 +552,6 @@ static void hdm_read_completion(struct urb *urb) struct device *dev; unsigned long flags; unsigned int channel; - struct most_channel_config *conf; mbo = urb->context; anchor = mbo->priv; @@ -577,13 +560,11 @@ static void hdm_read_completion(struct urb *urb) dev = &mdev->usb_device->dev; if ((urb->status == -ENOENT) || (urb->status == -ECONNRESET) || - (mdev->is_channel_healthy[channel] == false)) { + (!mdev->is_channel_healthy[channel])) { complete(&anchor->urb_compl); return; } - conf = &mdev->conf[channel]; - if (unlikely(urb->status && !(urb->status == -ENOENT || urb->status == -ECONNRESET || urb->status == -ESHUTDOWN))) { @@ -608,7 +589,7 @@ static void hdm_read_completion(struct urb *urb) } } else { mbo->processed_length = urb->actual_length; - if (mdev->padding_active[channel] == false) { + if (!mdev->padding_active[channel]) { mbo->status = MBO_SUCCESS; } else { if (hdm_remove_padding(mdev, channel, mbo)) { @@ -644,7 +625,8 @@ static void hdm_read_completion(struct urb *urb) * * Context: Could in _some_ cases be interrupt! */ -static int hdm_enqueue(struct most_interface *iface, int channel, struct mbo *mbo) +static int hdm_enqueue(struct most_interface *iface, int channel, + struct mbo *mbo) { struct most_dev *mdev; struct buf_anchor *anchor; @@ -688,7 +670,7 @@ static int hdm_enqueue(struct most_interface *iface, int channel, struct mbo *mb list_add_tail(&anchor->list, &mdev->anchor_list[channel]); spin_unlock_irqrestore(&mdev->anchor_list_lock[channel], flags); - if ((mdev->padding_active[channel] == true) && + if ((mdev->padding_active[channel]) && (conf->direction & MOST_CH_TX)) if (hdm_add_padding(mdev, channel, mbo)) { retval = -EIO; @@ -714,7 +696,7 @@ static int hdm_enqueue(struct most_interface *iface, int channel, struct mbo *mb usb_rcvbulkpipe(mdev->usb_device, mdev->ep_address[channel]), virt_address, - length, + length + conf->extra_len, hdm_read_completion, mbo); } @@ -780,12 +762,6 @@ static int hdm_configure_channel(struct most_interface *iface, int channel, mdev->padding_active[channel] = true; temp_size = conf->buffer_size; - if ((conf->data_type != MOST_CH_SYNC) && - (conf->data_type != MOST_CH_ISOC_AVP)) { - dev_warn(dev, "Unsupported data type\n"); - return -EINVAL; - } - frame_size = get_stream_frame_size(conf); if ((frame_size == 0) || (frame_size > USB_MTU)) { dev_warn(dev, "Misconfig: frame size wrong\n"); @@ -798,8 +774,7 @@ static int hdm_configure_channel(struct most_interface *iface, int channel, tmp_val = conf->buffer_size / frame_size; conf->buffer_size = tmp_val * frame_size; dev_notice(dev, - "Channel %d - rouding buffer size to %d bytes, " - "channel config says %d bytes\n", + "Channel %d - rounding buffer size to %d bytes, channel config says %d bytes\n", channel, conf->buffer_size, temp_size); @@ -826,38 +801,41 @@ exit: */ static int hdm_update_netinfo(struct most_dev *mdev) { - struct device *dev = &mdev->usb_device->dev; - int i; - u16 link; - u8 addr[6]; + struct usb_device *usb_device = mdev->usb_device; + struct device *dev = &usb_device->dev; + u16 hi, mi, lo, link; if (!is_valid_ether_addr(mdev->hw_addr)) { - if (0 > drci_rd_reg(mdev->usb_device, - DRCI_REG_HW_ADDR_HI, addr)) { + if (drci_rd_reg(usb_device, DRCI_REG_HW_ADDR_HI, &hi) < 0) { dev_err(dev, "Vendor request \"hw_addr_hi\" failed\n"); return -1; } - if (0 > drci_rd_reg(mdev->usb_device, - DRCI_REG_HW_ADDR_MI, addr + 2)) { + + if (drci_rd_reg(usb_device, DRCI_REG_HW_ADDR_MI, &mi) < 0) { dev_err(dev, "Vendor request \"hw_addr_mid\" failed\n"); return -1; } - if (0 > drci_rd_reg(mdev->usb_device, - DRCI_REG_HW_ADDR_LO, addr + 4)) { + + if (drci_rd_reg(usb_device, DRCI_REG_HW_ADDR_LO, &lo) < 0) { dev_err(dev, "Vendor request \"hw_addr_low\" failed\n"); return -1; } + mutex_lock(&mdev->io_mutex); - for (i = 0; i < 6; i++) - mdev->hw_addr[i] = addr[i]; + mdev->hw_addr[0] = hi >> 8; + mdev->hw_addr[1] = hi; + mdev->hw_addr[2] = mi >> 8; + mdev->hw_addr[3] = mi; + mdev->hw_addr[4] = lo >> 8; + mdev->hw_addr[5] = lo; mutex_unlock(&mdev->io_mutex); - } - if (0 > drci_rd_reg(mdev->usb_device, DRCI_REG_NI_STATE, &link)) { + + if (drci_rd_reg(usb_device, DRCI_REG_NI_STATE, &link) < 0) { dev_err(dev, "Vendor request \"link status\" failed\n"); return -1; } - le16_to_cpus(&link); + mutex_lock(&mdev->io_mutex); mdev->link_stat = link; mutex_unlock(&mdev->io_mutex); @@ -919,7 +897,7 @@ static void wq_netinfo(struct work_struct *wq_obj) for (i = 0; i < 6; i++) prev_hw_addr[i] = mdev->hw_addr[i]; - if (0 > hdm_update_netinfo(mdev)) + if (hdm_update_netinfo(mdev) < 0) return; if ((prev_link_stat != mdev->link_stat) || (prev_hw_addr[0] != mdev->hw_addr[0]) || @@ -1009,8 +987,8 @@ struct most_dci_attribute { const char *buf, size_t count); }; -#define to_dci_attr(a) container_of(a, struct most_dci_attribute, attr) +#define to_dci_attr(a) container_of(a, struct most_dci_attribute, attr) /** * dci_attr_show - show function for dci object @@ -1107,14 +1085,14 @@ static ssize_t show_value(struct most_dci_obj *dci_obj, if (err < 0) return err; - return snprintf(buf, PAGE_SIZE, "%04x\n", le16_to_cpu(tmp_val)); + return snprintf(buf, PAGE_SIZE, "%04x\n", tmp_val); } static ssize_t store_value(struct most_dci_obj *dci_obj, struct most_dci_attribute *attr, const char *buf, size_t count) { - u16 v16; + u16 val; u16 reg_addr; int err; @@ -1137,11 +1115,11 @@ static ssize_t store_value(struct most_dci_obj *dci_obj, else return -EIO; - err = kstrtou16(buf, 16, &v16); + err = kstrtou16(buf, 16, &val); if (err) return err; - err = drci_wr_reg(dci_obj->usb_device, reg_addr, cpu_to_le16(v16)); + err = drci_wr_reg(dci_obj->usb_device, reg_addr, val); if (err < 0) return err; @@ -1248,6 +1226,7 @@ hdm_probe(struct usb_interface *interface, const struct usb_device_id *id) struct usb_host_interface *usb_iface_desc; struct usb_endpoint_descriptor *ep_desc; int ret = 0; + int err; usb_iface_desc = interface->cur_altsetting; usb_dev = interface_to_usbdev(interface); @@ -1260,11 +1239,10 @@ hdm_probe(struct usb_interface *interface, const struct usb_device_id *id) num_endpoints = usb_iface_desc->desc.bNumEndpoints; mutex_init(&mdev->io_mutex); INIT_WORK(&mdev->poll_work_obj, wq_netinfo); - init_timer(&mdev->link_stat_timer); + setup_timer(&mdev->link_stat_timer, link_stat_timer_handler, + (unsigned long)mdev); mdev->usb_device = usb_dev; - mdev->link_stat_timer.function = link_stat_timer_handler; - mdev->link_stat_timer.data = (unsigned long)mdev; mdev->link_stat_timer.expires = jiffies + (2 * HZ); mdev->iface.mod = hdm_usb_fops.owner; @@ -1328,6 +1306,13 @@ hdm_probe(struct usb_interface *interface, const struct usb_device_id *id) tmp_cap++; INIT_LIST_HEAD(&mdev->anchor_list[i]); spin_lock_init(&mdev->anchor_list_lock[i]); + err = drci_wr_reg(usb_dev, + DRCI_REG_BASE + DRCI_COMMAND + + ep_desc->bEndpointAddress * 16, + 1); + if (err < 0) + pr_warn("DCI Sync for EP %02x failed", + ep_desc->bEndpointAddress); } dev_notice(dev, "claimed gadget: Vendor=%4.4x ProdID=%4.4x Bus=%02x Device=%02x\n", le16_to_cpu(usb_dev->descriptor.idVendor), @@ -1362,7 +1347,6 @@ hdm_probe(struct usb_interface *interface, const struct usb_device_id *id) kobject_uevent(&mdev->dci->kobj, KOBJ_ADD); mdev->dci->usb_device = mdev->usb_device; - trigger_resync_vr(usb_dev); } mutex_unlock(&mdev->io_mutex); return 0; @@ -1432,7 +1416,7 @@ static int __init hdm_usb_init(void) return -EIO; } schedule_usb_work = create_workqueue("hdmu_work"); - if (schedule_usb_work == NULL) { + if (!schedule_usb_work) { pr_err("could not create workqueue\n"); usb_deregister(&hdm_usb); return -ENOMEM; diff --git a/drivers/staging/most/mostcore/core.c b/drivers/staging/most/mostcore/core.c index 7bb16db42..19852ca7e 100644 --- a/drivers/staging/most/mostcore/core.c +++ b/drivers/staging/most/mostcore/core.c @@ -36,15 +36,22 @@ static struct class *most_class; static struct device *class_glue_dir; static struct ida mdev_id; static int modref; +static int dummy_num_buffers; + +struct most_c_aim_obj { + struct most_aim *ptr; + int refs; + int num_buffers; +}; struct most_c_obj { struct kobject kobj; struct completion cleanup; atomic_t mbo_ref; atomic_t mbo_nq_level; - uint16_t channel_id; + u16 channel_id; bool is_poisoned; - bool is_started; + struct mutex start_mutex; int is_starving; struct most_interface *iface; struct most_inst_obj *inst; @@ -55,13 +62,14 @@ struct most_c_obj { spinlock_t fifo_lock; struct list_head halt_fifo; struct list_head list; - struct most_aim *first_aim; - struct most_aim *second_aim; + struct most_c_aim_obj aim0; + struct most_c_aim_obj aim1; struct list_head trash_fifo; struct task_struct *hdm_enqueue_task; struct mutex stop_task_mutex; wait_queue_head_t hdm_fifo_wq; }; + #define to_c_obj(d) container_of(d, struct most_c_obj, kobj) struct most_inst_obj { @@ -73,6 +81,7 @@ struct most_inst_obj { struct kobject kobj; struct list_head list; }; + #define to_inst_obj(d) container_of(d, struct most_inst_obj, kobj) /** @@ -108,6 +117,7 @@ struct most_c_attr { const char *buf, size_t count); }; + #define to_channel_attr(a) container_of(a, struct most_c_attr, attr) #define MOST_CHNL_ATTR(_name, _mode, _show, _store) \ @@ -190,8 +200,7 @@ static void flush_channel_fifos(struct most_c_obj *c) list_for_each_entry_safe(mbo, tmp, &c->fifo, list) { list_del(&mbo->list); spin_unlock_irqrestore(&c->fifo_lock, flags); - if (likely(mbo)) - most_free_mbo_coherent(mbo); + most_free_mbo_coherent(mbo); spin_lock_irqsave(&c->fifo_lock, flags); } spin_unlock_irqrestore(&c->fifo_lock, flags); @@ -200,8 +209,7 @@ static void flush_channel_fifos(struct most_c_obj *c) list_for_each_entry_safe(mbo, tmp, &c->halt_fifo, list) { list_del(&mbo->list); spin_unlock_irqrestore(&c->fifo_lock, hf_flags); - if (likely(mbo)) - most_free_mbo_coherent(mbo); + most_free_mbo_coherent(mbo); spin_lock_irqsave(&c->fifo_lock, hf_flags); } spin_unlock_irqrestore(&c->fifo_lock, hf_flags); @@ -242,8 +250,8 @@ static void most_channel_release(struct kobject *kobj) } static ssize_t show_available_directions(struct most_c_obj *c, - struct most_c_attr *attr, - char *buf) + struct most_c_attr *attr, + char *buf) { unsigned int i = c->channel_id; @@ -326,7 +334,6 @@ static ssize_t show_channel_starving(struct most_c_obj *c, return snprintf(buf, PAGE_SIZE, "%d\n", c->is_starving); } - #define create_show_channel_attribute(val) \ static MOST_CHNL_ATTR(val, S_IRUGO, show_##val, NULL) @@ -392,11 +399,11 @@ static ssize_t store_set_direction(struct most_c_obj *c, const char *buf, size_t count) { - if (!strcmp(buf, "dir_rx\n")) + if (!strcmp(buf, "dir_rx\n")) { c->cfg.direction = MOST_CH_RX; - else if (!strcmp(buf, "dir_tx\n")) + } else if (!strcmp(buf, "dir_tx\n")) { c->cfg.direction = MOST_CH_TX; - else { + } else { pr_info("WARN: invalid attribute settings\n"); return -EINVAL; } @@ -423,15 +430,15 @@ static ssize_t store_set_datatype(struct most_c_obj *c, const char *buf, size_t count) { - if (!strcmp(buf, "control\n")) + if (!strcmp(buf, "control\n")) { c->cfg.data_type = MOST_CH_CONTROL; - else if (!strcmp(buf, "async\n")) + } else if (!strcmp(buf, "async\n")) { c->cfg.data_type = MOST_CH_ASYNC; - else if (!strcmp(buf, "sync\n")) + } else if (!strcmp(buf, "sync\n")) { c->cfg.data_type = MOST_CH_SYNC; - else if (!strcmp(buf, "isoc_avp\n")) + } else if (!strcmp(buf, "isoc_avp\n")) { c->cfg.data_type = MOST_CH_ISOC_AVP; - else { + } else { pr_info("WARN: invalid attribute settings\n"); return -EINVAL; } @@ -488,7 +495,6 @@ create_channel_attribute(set_datatype); create_channel_attribute(set_subbuffer_size); create_channel_attribute(set_packets_per_xact); - /** * most_channel_def_attrs - array of default attributes of channel object */ @@ -554,12 +560,12 @@ create_most_c_obj(const char *name, struct kobject *parent) */ static void destroy_most_c_obj(struct most_c_obj *c) { - if (c->first_aim) - c->first_aim->disconnect_channel(c->iface, c->channel_id); - if (c->second_aim) - c->second_aim->disconnect_channel(c->iface, c->channel_id); - c->first_aim = NULL; - c->second_aim = NULL; + if (c->aim0.ptr) + c->aim0.ptr->disconnect_channel(c->iface, c->channel_id); + if (c->aim1.ptr) + c->aim1.ptr->disconnect_channel(c->iface, c->channel_id); + c->aim0.ptr = NULL; + c->aim1.ptr = NULL; mutex_lock(&deregister_mutex); flush_trash_fifo(c); @@ -593,6 +599,7 @@ struct most_inst_attribute { const char *buf, size_t count); }; + #define to_instance_attr(a) \ container_of(a, struct most_inst_attribute, attr) @@ -715,7 +722,6 @@ static struct kobj_type most_inst_ktype = { static struct kset *most_inst_kset; - /** * create_most_inst_obj - creates an instance object * @name: name of the object to be created @@ -775,11 +781,11 @@ struct most_aim_obj { char add_link[STRING_SIZE]; char remove_link[STRING_SIZE]; }; + #define to_aim_obj(d) container_of(d, struct most_aim_obj, kobj) static struct list_head aim_list; - /** * struct most_aim_attribute - to access the attributes of AIM object * @attr: attributes of an AIM @@ -796,6 +802,7 @@ struct most_aim_attribute { const char *buf, size_t count); }; + #define to_aim_attr(a) container_of(a, struct most_aim_attribute, attr) /** @@ -933,7 +940,7 @@ most_c_obj *get_channel_by_name(char *mdev, char *mdev_ch) break; } } - if (unlikely(2 > found)) + if (unlikely(found < 2)) return ERR_PTR(-EIO); return c; } @@ -983,7 +990,8 @@ static ssize_t store_add_link(struct most_aim_obj *aim_obj, return ret; if (!mdev_devnod || *mdev_devnod == 0) { - snprintf(devnod_buf, sizeof(devnod_buf), "%s-%s", mdev, mdev_ch); + snprintf(devnod_buf, sizeof(devnod_buf), "%s-%s", mdev, + mdev_ch); mdev_devnod = devnod_buf; } @@ -991,10 +999,10 @@ static ssize_t store_add_link(struct most_aim_obj *aim_obj, if (IS_ERR(c)) return -ENODEV; - if (!c->first_aim) - aim_ptr = &c->first_aim; - else if (!c->second_aim) - aim_ptr = &c->second_aim; + if (!c->aim0.ptr) + aim_ptr = &c->aim0.ptr; + else if (!c->aim1.ptr) + aim_ptr = &c->aim1.ptr; else return -ENOSPC; @@ -1048,17 +1056,18 @@ static ssize_t store_remove_link(struct most_aim_obj *aim_obj, if (IS_ERR(c)) return -ENODEV; - if (c->first_aim == aim_obj->driver) - c->first_aim = NULL; - if (c->second_aim == aim_obj->driver) - c->second_aim = NULL; + if (c->aim0.ptr == aim_obj->driver) + c->aim0.ptr = NULL; + if (c->aim1.ptr == aim_obj->driver) + c->aim1.ptr = NULL; if (aim_obj->driver->disconnect_channel(c->iface, c->channel_id)) return -EIO; return len; } static struct most_aim_attribute most_aim_attr_remove_link = - __ATTR(remove_link, S_IRUGO | S_IWUSR, show_remove_link, store_remove_link); + __ATTR(remove_link, S_IRUGO | S_IWUSR, show_remove_link, + store_remove_link); static struct attribute *most_aim_def_attrs[] = { &most_aim_attr_add_link.attr, @@ -1113,7 +1122,6 @@ static void destroy_most_aim_obj(struct most_aim_obj *p) kobject_put(&p->kobj); } - /* ___ ___ * ___C O R E___ */ @@ -1176,8 +1184,8 @@ static int hdm_enqueue_thread(void *data) while (likely(!kthread_should_stop())) { wait_event_interruptible(c->hdm_fifo_wq, - (mbo = get_hdm_mbo(c)) - || kthread_should_stop()); + (mbo = get_hdm_mbo(c)) || + kthread_should_stop()); if (unlikely(!mbo)) continue; @@ -1199,7 +1207,8 @@ static int hdm_enqueue_thread(void *data) static int run_enqueue_thread(struct most_c_obj *c, int channel_id) { struct task_struct *task = - kthread_run(&hdm_enqueue_thread, c, "hdm_fifo_%d", channel_id); + kthread_run(hdm_enqueue_thread, c, "hdm_fifo_%d", + channel_id); if (IS_ERR(task)) return PTR_ERR(task); @@ -1233,13 +1242,15 @@ static void arm_mbo(struct mbo *mbo) } spin_lock_irqsave(&c->fifo_lock, flags); + ++*mbo->num_buffers_ptr; list_add_tail(&mbo->list, &c->fifo); spin_unlock_irqrestore(&c->fifo_lock, flags); - if (c->second_aim && c->second_aim->tx_completion) - c->second_aim->tx_completion(c->iface, c->channel_id); - if (c->first_aim && c->first_aim->tx_completion) - c->first_aim->tx_completion(c->iface, c->channel_id); + if (c->aim0.refs && c->aim0.ptr->tx_completion) + c->aim0.ptr->tx_completion(c->iface, c->channel_id); + + if (c->aim1.refs && c->aim1.ptr->tx_completion) + c->aim1.ptr->tx_completion(c->iface, c->channel_id); } /** @@ -1285,6 +1296,7 @@ static int arm_mbo_chain(struct most_c_obj *c, int dir, goto _error1; } mbo->complete = compl; + mbo->num_buffers_ptr = &dummy_num_buffers; if (dir == MOST_CH_RX) { nq_hdm_mbo(mbo); atomic_inc(&c->mbo_nq_level); @@ -1341,7 +1353,7 @@ static void most_write_completion(struct mbo *mbo) c = mbo->context; if (mbo->status == MBO_E_INVAL) pr_info("WARN: Tx MBO status: invalid\n"); - if (unlikely((c->is_poisoned == true) || (mbo->status == MBO_E_CLOSE))) + if (unlikely(c->is_poisoned || (mbo->status == MBO_E_CLOSE))) trash_mbo(mbo); else arm_mbo(mbo); @@ -1375,6 +1387,22 @@ most_c_obj *get_channel_by_iface(struct most_interface *iface, int id) return i->channel[id]; } +int channel_has_mbo(struct most_interface *iface, int id) +{ + struct most_c_obj *c = get_channel_by_iface(iface, id); + unsigned long flags; + int empty; + + if (unlikely(!c)) + return -EINVAL; + + spin_lock_irqsave(&c->fifo_lock, flags); + empty = list_empty(&c->fifo); + spin_unlock_irqrestore(&c->fifo_lock, flags); + return !empty; +} +EXPORT_SYMBOL_GPL(channel_has_mbo); + /** * most_get_mbo - get pointer to an MBO of pool * @iface: pointer to interface instance @@ -1383,28 +1411,45 @@ most_c_obj *get_channel_by_iface(struct most_interface *iface, int id) * This attempts to get a free buffer out of the channel fifo. * Returns a pointer to MBO on success or NULL otherwise. */ -struct mbo *most_get_mbo(struct most_interface *iface, int id) +struct mbo *most_get_mbo(struct most_interface *iface, int id, + struct most_aim *aim) { struct mbo *mbo; struct most_c_obj *c; unsigned long flags; + int *num_buffers_ptr; c = get_channel_by_iface(iface, id); if (unlikely(!c)) return NULL; + + if (c->aim0.refs && c->aim1.refs && + ((aim == c->aim0.ptr && c->aim0.num_buffers <= 0) || + (aim == c->aim1.ptr && c->aim1.num_buffers <= 0))) + return NULL; + + if (aim == c->aim0.ptr) + num_buffers_ptr = &c->aim0.num_buffers; + else if (aim == c->aim1.ptr) + num_buffers_ptr = &c->aim1.num_buffers; + else + num_buffers_ptr = &dummy_num_buffers; + spin_lock_irqsave(&c->fifo_lock, flags); if (list_empty(&c->fifo)) { spin_unlock_irqrestore(&c->fifo_lock, flags); return NULL; } mbo = list_pop_mbo(&c->fifo); + --*num_buffers_ptr; spin_unlock_irqrestore(&c->fifo_lock, flags); + + mbo->num_buffers_ptr = num_buffers_ptr; mbo->buffer_length = c->cfg.buffer_size; return mbo; } EXPORT_SYMBOL_GPL(most_get_mbo); - /** * most_put_mbo - return buffer to pool * @mbo: buffer object @@ -1443,11 +1488,12 @@ EXPORT_SYMBOL_GPL(most_put_mbo); */ static void most_read_completion(struct mbo *mbo) { - struct most_c_obj *c; + struct most_c_obj *c = mbo->context; - c = mbo->context; - if (unlikely((c->is_poisoned == true) || (mbo->status == MBO_E_CLOSE))) - goto release_mbo; + if (unlikely(c->is_poisoned || (mbo->status == MBO_E_CLOSE))) { + trash_mbo(mbo); + return; + } if (mbo->status == MBO_E_INVAL) { nq_hdm_mbo(mbo); @@ -1460,16 +1506,15 @@ static void most_read_completion(struct mbo *mbo) c->is_starving = 1; } - if (c->first_aim && c->first_aim->rx_completion && - c->first_aim->rx_completion(mbo) == 0) + if (c->aim0.refs && c->aim0.ptr->rx_completion && + c->aim0.ptr->rx_completion(mbo) == 0) return; - if (c->second_aim && c->second_aim->rx_completion && - c->second_aim->rx_completion(mbo) == 0) + + if (c->aim1.refs && c->aim1.ptr->rx_completion && + c->aim1.ptr->rx_completion(mbo) == 0) return; - pr_info("WARN: no driver linked with this channel\n"); - mbo->status = MBO_E_CLOSE; -release_mbo: - trash_mbo(mbo); + + most_put_mbo(mbo); } /** @@ -1482,7 +1527,8 @@ release_mbo: * * Returns 0 on success or error code otherwise. */ -int most_start_channel(struct most_interface *iface, int id) +int most_start_channel(struct most_interface *iface, int id, + struct most_aim *aim) { int num_buffer; int ret; @@ -1491,11 +1537,13 @@ int most_start_channel(struct most_interface *iface, int id) if (unlikely(!c)) return -EINVAL; - if (c->is_started) - return -EBUSY; + mutex_lock(&c->start_mutex); + if (c->aim0.refs + c->aim1.refs > 0) + goto out; /* already started by other aim */ if (!try_module_get(iface->mod)) { pr_info("failed to acquire HDM lock\n"); + mutex_unlock(&c->start_mutex); return -ENOLCK; } modref++; @@ -1515,7 +1563,7 @@ int most_start_channel(struct most_interface *iface, int id) else num_buffer = arm_mbo_chain(c, c->cfg.direction, most_write_completion); - if (unlikely(0 == num_buffer)) { + if (unlikely(!num_buffer)) { pr_info("failed to allocate memory\n"); ret = -ENOMEM; goto error; @@ -1525,14 +1573,24 @@ int most_start_channel(struct most_interface *iface, int id) if (ret) goto error; - c->is_started = true; c->is_starving = 0; + c->aim0.num_buffers = c->cfg.num_buffers / 2; + c->aim1.num_buffers = c->cfg.num_buffers - c->aim0.num_buffers; atomic_set(&c->mbo_ref, num_buffer); + +out: + if (aim == c->aim0.ptr) + c->aim0.refs++; + if (aim == c->aim1.ptr) + c->aim1.refs++; + mutex_unlock(&c->start_mutex); return 0; + error: if (iface->mod) module_put(iface->mod); modref--; + mutex_unlock(&c->start_mutex); return ret; } EXPORT_SYMBOL_GPL(most_start_channel); @@ -1542,7 +1600,8 @@ EXPORT_SYMBOL_GPL(most_start_channel); * @iface: pointer to interface instance * @id: channel ID */ -int most_stop_channel(struct most_interface *iface, int id) +int most_stop_channel(struct most_interface *iface, int id, + struct most_aim *aim) { struct most_c_obj *c; @@ -1554,13 +1613,9 @@ int most_stop_channel(struct most_interface *iface, int id) if (unlikely(!c)) return -EINVAL; - if (!c->is_started) - return 0; - - /* FIXME: we need to know calling AIM to reset only one link */ - c->first_aim = NULL; - c->second_aim = NULL; - /* do not go into recursion calling aim->disconnect_channel */ + mutex_lock(&c->start_mutex); + if (c->aim0.refs + c->aim1.refs >= 2) + goto out; mutex_lock(&c->stop_task_mutex); if (c->hdm_enqueue_task) @@ -1571,6 +1626,7 @@ int most_stop_channel(struct most_interface *iface, int id) mutex_lock(&deregister_mutex); if (atomic_read(&c->inst->tainted)) { mutex_unlock(&deregister_mutex); + mutex_unlock(&c->start_mutex); return -ENODEV; } mutex_unlock(&deregister_mutex); @@ -1584,6 +1640,7 @@ int most_stop_channel(struct most_interface *iface, int id) if (c->iface->poison_channel(c->iface, c->channel_id)) { pr_err("Cannot stop channel %d of mdev %s\n", c->channel_id, c->iface->description); + mutex_unlock(&c->start_mutex); return -EAGAIN; } flush_trash_fifo(c); @@ -1592,13 +1649,20 @@ int most_stop_channel(struct most_interface *iface, int id) #ifdef CMPL_INTERRUPTIBLE if (wait_for_completion_interruptible(&c->cleanup)) { pr_info("Interrupted while clean up ch %d\n", c->channel_id); + mutex_unlock(&c->start_mutex); return -EINTR; } #else wait_for_completion(&c->cleanup); #endif c->is_poisoned = false; - c->is_started = false; + +out: + if (aim == c->aim0.ptr) + c->aim0.refs--; + if (aim == c->aim1.ptr) + c->aim1.refs--; + mutex_unlock(&c->start_mutex); return 0; } EXPORT_SYMBOL_GPL(most_stop_channel); @@ -1651,13 +1715,13 @@ int most_deregister_aim(struct most_aim *aim) } list_for_each_entry_safe(i, i_tmp, &instance_list, list) { list_for_each_entry_safe(c, tmp, &i->channel_list, list) { - if (c->first_aim == aim || c->second_aim == aim) + if (c->aim0.ptr == aim || c->aim1.ptr == aim) aim->disconnect_channel( c->iface, c->channel_id); - if (c->first_aim == aim) - c->first_aim = NULL; - if (c->second_aim == aim) - c->second_aim = NULL; + if (c->aim0.ptr == aim) + c->aim0.ptr = NULL; + if (c->aim1.ptr == aim) + c->aim1.ptr = NULL; } } list_del(&aim_obj->list); @@ -1732,7 +1796,6 @@ struct kobject *most_register_interface(struct most_interface *iface) c->keep_mbo = false; c->enqueue_halt = false; c->is_poisoned = false; - c->is_started = false; c->cfg.direction = 0; c->cfg.data_type = 0; c->cfg.num_buffers = 0; @@ -1745,6 +1808,7 @@ struct kobject *most_register_interface(struct most_interface *iface) INIT_LIST_HEAD(&c->halt_fifo); init_completion(&c->cleanup); atomic_set(&c->mbo_ref, 0); + mutex_init(&c->start_mutex); mutex_init(&c->stop_task_mutex); list_add_tail(&c->list, &inst->channel_list); } @@ -1791,7 +1855,7 @@ void most_deregister_interface(struct most_interface *iface) } list_for_each_entry(c, &i->channel_list, list) { - if (!c->is_started) + if (c->aim0.refs + c->aim1.refs <= 0) continue; mutex_lock(&c->stop_task_mutex); diff --git a/drivers/staging/most/mostcore/mostcore.h b/drivers/staging/most/mostcore/mostcore.h index 299c7d5aa..e148b3243 100644 --- a/drivers/staging/most/mostcore/mostcore.h +++ b/drivers/staging/most/mostcore/mostcore.h @@ -190,6 +190,7 @@ struct mbo { void *priv; struct list_head list; struct most_interface *ifp; + int *num_buffers_ptr; u16 hdm_channel_id; void *virt_address; dma_addr_t bus_address; @@ -254,7 +255,7 @@ struct most_interface { * struct most_aim - identifies MOST device driver to mostcore * @name: Driver name * @probe_channel: function for core to notify driver about channel connection - * @disconnect_channel: notification that a certain channel isn't available anymore + * @disconnect_channel: callback function to disconnect a certain channel * @rx_completion: completion handler for received packets * @tx_completion: completion handler for transmitted packets * @context: context pointer to be used by mostcore @@ -307,10 +308,14 @@ void most_stop_enqueue(struct most_interface *iface, int channel_idx); void most_resume_enqueue(struct most_interface *iface, int channel_idx); int most_register_aim(struct most_aim *aim); int most_deregister_aim(struct most_aim *aim); -struct mbo *most_get_mbo(struct most_interface *iface, int channel_idx); +struct mbo *most_get_mbo(struct most_interface *iface, int channel_idx, + struct most_aim *); void most_put_mbo(struct mbo *mbo); -int most_start_channel(struct most_interface *iface, int channel_idx); -int most_stop_channel(struct most_interface *iface, int channel_idx); +int channel_has_mbo(struct most_interface *iface, int channel_idx); +int most_start_channel(struct most_interface *iface, int channel_idx, + struct most_aim *); +int most_stop_channel(struct most_interface *iface, int channel_idx, + struct most_aim *); #endif /* MOST_CORE_H_ */ |