Commit f49f60e4 authored by Jody McIntyre's avatar Jody McIntyre

Fixes a bug in the channel reservation :

If dma resources allocation fails, the channel was not freed.  I fixed
that by marking the channel allocated after the dma resources allocation
succeeded.  Also changed the error return value from ioctl.

Signed-off-by: Philippe De Muyter <phdm at macqel dot be>
Signed-off-by: default avatarDan Dennedy <dan@dennedy.org>
Signed-off-by: default avatarJody McIntyre <scjody@modernduck.com>
parent c914a1a9
...@@ -16,14 +16,25 @@ ...@@ -16,14 +16,25 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, * along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* NOTES:
*
* jds -- add private data to file to keep track of iso contexts associated
* with each open -- so release won't kill all iso transfers.
*
* Damien Douxchamps: Fix failure when the number of DMA pages per frame is
* one.
*
* ioctl return codes:
* EFAULT is only for invalid address for the argp
* EINVAL for out of range values
* EBUSY when trying to use an already used resource
* ESRCH when trying to free/stop a not used resource
* EAGAIN for resource allocation failure that could perhaps succeed later
* ENOTTY for unsupported ioctl request
*
*/ */
/* jds -- add private data to file to keep track of iso contexts associated
with each open -- so release won't kill all iso transfers */
/* Damien Douxchamps: Fix failure when the number of DMA pages per frame is
one */
#include <linux/config.h> #include <linux/config.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/list.h> #include <linux/list.h>
...@@ -723,7 +734,12 @@ static int __video1394_ioctl(struct file *file, ...@@ -723,7 +734,12 @@ static int __video1394_ioctl(struct file *file,
/* if channel < 0, find lowest available one */ /* if channel < 0, find lowest available one */
if (v.channel < 0) { if (v.channel < 0) {
mask = (u64)0x1; mask = (u64)0x1;
for (i=0; i<ISO_CHANNELS; i++) { for (i=0; ; i++) {
if (i == ISO_CHANNELS) {
PRINT(KERN_ERR, ohci->host->id,
"No free channel found");
return EAGAIN;
}
if (!(ohci->ISO_channel_usage & mask)) { if (!(ohci->ISO_channel_usage & mask)) {
v.channel = i; v.channel = i;
PRINT(KERN_INFO, ohci->host->id, "Found free channel %d", i); PRINT(KERN_INFO, ohci->host->id, "Found free channel %d", i);
...@@ -731,42 +747,40 @@ static int __video1394_ioctl(struct file *file, ...@@ -731,42 +747,40 @@ static int __video1394_ioctl(struct file *file,
} }
mask = mask << 1; mask = mask << 1;
} }
} } else if (v.channel >= ISO_CHANNELS) {
if (v.channel<0 || v.channel>(ISO_CHANNELS-1)) {
PRINT(KERN_ERR, ohci->host->id, PRINT(KERN_ERR, ohci->host->id,
"Iso channel %d out of bounds", v.channel); "Iso channel %d out of bounds", v.channel);
return -EFAULT; return -EINVAL;
} else {
mask = (u64)0x1<<v.channel;
} }
mask = (u64)0x1<<v.channel; PRINT(KERN_INFO, ohci->host->id, "mask: %08X%08X usage: %08X%08X\n",
printk("mask: %08X%08X usage: %08X%08X\n", (u32)(mask>>32),(u32)(mask&0xffffffff),
(u32)(mask>>32),(u32)(mask&0xffffffff), (u32)(ohci->ISO_channel_usage>>32),
(u32)(ohci->ISO_channel_usage>>32), (u32)(ohci->ISO_channel_usage&0xffffffff));
(u32)(ohci->ISO_channel_usage&0xffffffff));
if (ohci->ISO_channel_usage & mask) { if (ohci->ISO_channel_usage & mask) {
PRINT(KERN_ERR, ohci->host->id, PRINT(KERN_ERR, ohci->host->id,
"Channel %d is already taken", v.channel); "Channel %d is already taken", v.channel);
return -EFAULT; return -EBUSY;
} }
ohci->ISO_channel_usage |= mask;
if (v.buf_size == 0 || v.buf_size > VIDEO1394_MAX_SIZE) { if (v.buf_size == 0 || v.buf_size > VIDEO1394_MAX_SIZE) {
PRINT(KERN_ERR, ohci->host->id, PRINT(KERN_ERR, ohci->host->id,
"Invalid %d length buffer requested",v.buf_size); "Invalid %d length buffer requested",v.buf_size);
return -EFAULT; return -EINVAL;
} }
if (v.nb_buffers == 0 || v.nb_buffers > VIDEO1394_MAX_SIZE) { if (v.nb_buffers == 0 || v.nb_buffers > VIDEO1394_MAX_SIZE) {
PRINT(KERN_ERR, ohci->host->id, PRINT(KERN_ERR, ohci->host->id,
"Invalid %d buffers requested",v.nb_buffers); "Invalid %d buffers requested",v.nb_buffers);
return -EFAULT; return -EINVAL;
} }
if (v.nb_buffers * v.buf_size > VIDEO1394_MAX_SIZE) { if (v.nb_buffers * v.buf_size > VIDEO1394_MAX_SIZE) {
PRINT(KERN_ERR, ohci->host->id, PRINT(KERN_ERR, ohci->host->id,
"%d buffers of size %d bytes is too big", "%d buffers of size %d bytes is too big",
v.nb_buffers, v.buf_size); v.nb_buffers, v.buf_size);
return -EFAULT; return -EINVAL;
} }
if (cmd == VIDEO1394_IOC_LISTEN_CHANNEL) { if (cmd == VIDEO1394_IOC_LISTEN_CHANNEL) {
...@@ -777,7 +791,7 @@ static int __video1394_ioctl(struct file *file, ...@@ -777,7 +791,7 @@ static int __video1394_ioctl(struct file *file,
if (d == NULL) { if (d == NULL) {
PRINT(KERN_ERR, ohci->host->id, PRINT(KERN_ERR, ohci->host->id,
"Couldn't allocate ir context"); "Couldn't allocate ir context");
return -EFAULT; return -EAGAIN;
} }
initialize_dma_ir_ctx(d, v.sync_tag, v.flags); initialize_dma_ir_ctx(d, v.sync_tag, v.flags);
...@@ -798,7 +812,7 @@ static int __video1394_ioctl(struct file *file, ...@@ -798,7 +812,7 @@ static int __video1394_ioctl(struct file *file,
if (d == NULL) { if (d == NULL) {
PRINT(KERN_ERR, ohci->host->id, PRINT(KERN_ERR, ohci->host->id,
"Couldn't allocate it context"); "Couldn't allocate it context");
return -EFAULT; return -EAGAIN;
} }
initialize_dma_it_ctx(d, v.sync_tag, initialize_dma_it_ctx(d, v.sync_tag,
v.syt_offset, v.flags); v.syt_offset, v.flags);
...@@ -814,8 +828,12 @@ static int __video1394_ioctl(struct file *file, ...@@ -814,8 +828,12 @@ static int __video1394_ioctl(struct file *file,
v.channel); v.channel);
} }
if (copy_to_user(argp, &v, sizeof(v))) if (copy_to_user((void *)arg, &v, sizeof(v))) {
/* FIXME : free allocated dma resources */
return -EFAULT; return -EFAULT;
}
ohci->ISO_channel_usage |= mask;
return 0; return 0;
} }
...@@ -829,16 +847,16 @@ static int __video1394_ioctl(struct file *file, ...@@ -829,16 +847,16 @@ static int __video1394_ioctl(struct file *file,
if (copy_from_user(&channel, argp, sizeof(int))) if (copy_from_user(&channel, argp, sizeof(int)))
return -EFAULT; return -EFAULT;
if (channel<0 || channel>(ISO_CHANNELS-1)) { if (channel < 0 || channel >= ISO_CHANNELS) {
PRINT(KERN_ERR, ohci->host->id, PRINT(KERN_ERR, ohci->host->id,
"Iso channel %d out of bound", channel); "Iso channel %d out of bound", channel);
return -EFAULT; return -EINVAL;
} }
mask = (u64)0x1<<channel; mask = (u64)0x1<<channel;
if (!(ohci->ISO_channel_usage & mask)) { if (!(ohci->ISO_channel_usage & mask)) {
PRINT(KERN_ERR, ohci->host->id, PRINT(KERN_ERR, ohci->host->id,
"Channel %d is not being used", channel); "Channel %d is not being used", channel);
return -EFAULT; return -ESRCH;
} }
/* Mark this channel as unused */ /* Mark this channel as unused */
...@@ -849,7 +867,7 @@ static int __video1394_ioctl(struct file *file, ...@@ -849,7 +867,7 @@ static int __video1394_ioctl(struct file *file,
else else
d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, channel); d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, channel);
if (d == NULL) return -EFAULT; if (d == NULL) return -ESRCH;
PRINT(KERN_INFO, ohci->host->id, "Iso context %d " PRINT(KERN_INFO, ohci->host->id, "Iso context %d "
"stop talking on channel %d", d->ctx, channel); "stop talking on channel %d", d->ctx, channel);
free_dma_iso_ctx(d); free_dma_iso_ctx(d);
...@@ -870,7 +888,7 @@ static int __video1394_ioctl(struct file *file, ...@@ -870,7 +888,7 @@ static int __video1394_ioctl(struct file *file,
if ((v.buffer<0) || (v.buffer>d->num_desc)) { if ((v.buffer<0) || (v.buffer>d->num_desc)) {
PRINT(KERN_ERR, ohci->host->id, PRINT(KERN_ERR, ohci->host->id,
"Buffer %d out of range",v.buffer); "Buffer %d out of range",v.buffer);
return -EFAULT; return -EINVAL;
} }
spin_lock_irqsave(&d->lock,flags); spin_lock_irqsave(&d->lock,flags);
...@@ -879,7 +897,7 @@ static int __video1394_ioctl(struct file *file, ...@@ -879,7 +897,7 @@ static int __video1394_ioctl(struct file *file,
PRINT(KERN_ERR, ohci->host->id, PRINT(KERN_ERR, ohci->host->id,
"Buffer %d is already used",v.buffer); "Buffer %d is already used",v.buffer);
spin_unlock_irqrestore(&d->lock,flags); spin_unlock_irqrestore(&d->lock,flags);
return -EFAULT; return -EBUSY;
} }
d->buffer_status[v.buffer]=VIDEO1394_BUFFER_QUEUED; d->buffer_status[v.buffer]=VIDEO1394_BUFFER_QUEUED;
...@@ -933,7 +951,7 @@ static int __video1394_ioctl(struct file *file, ...@@ -933,7 +951,7 @@ static int __video1394_ioctl(struct file *file,
if ((v.buffer<0) || (v.buffer>d->num_desc)) { if ((v.buffer<0) || (v.buffer>d->num_desc)) {
PRINT(KERN_ERR, ohci->host->id, PRINT(KERN_ERR, ohci->host->id,
"Buffer %d out of range",v.buffer); "Buffer %d out of range",v.buffer);
return -EFAULT; return -EINVAL;
} }
/* /*
...@@ -976,7 +994,7 @@ static int __video1394_ioctl(struct file *file, ...@@ -976,7 +994,7 @@ static int __video1394_ioctl(struct file *file,
PRINT(KERN_ERR, ohci->host->id, PRINT(KERN_ERR, ohci->host->id,
"Buffer %d is not queued",v.buffer); "Buffer %d is not queued",v.buffer);
spin_unlock_irqrestore(&d->lock, flags); spin_unlock_irqrestore(&d->lock, flags);
return -EFAULT; return -ESRCH;
} }
/* set time of buffer */ /* set time of buffer */
...@@ -1015,7 +1033,7 @@ static int __video1394_ioctl(struct file *file, ...@@ -1015,7 +1033,7 @@ static int __video1394_ioctl(struct file *file,
if ((v.buffer<0) || (v.buffer>d->num_desc)) { if ((v.buffer<0) || (v.buffer>d->num_desc)) {
PRINT(KERN_ERR, ohci->host->id, PRINT(KERN_ERR, ohci->host->id,
"Buffer %d out of range",v.buffer); "Buffer %d out of range",v.buffer);
return -EFAULT; return -EINVAL;
} }
if (d->flags & VIDEO1394_VARIABLE_PACKET_SIZE) { if (d->flags & VIDEO1394_VARIABLE_PACKET_SIZE) {
...@@ -1044,7 +1062,7 @@ static int __video1394_ioctl(struct file *file, ...@@ -1044,7 +1062,7 @@ static int __video1394_ioctl(struct file *file,
spin_unlock_irqrestore(&d->lock,flags); spin_unlock_irqrestore(&d->lock,flags);
if (psizes) if (psizes)
kfree(psizes); kfree(psizes);
return -EFAULT; return -EBUSY;
} }
if (d->flags & VIDEO1394_VARIABLE_PACKET_SIZE) { if (d->flags & VIDEO1394_VARIABLE_PACKET_SIZE) {
...@@ -1118,7 +1136,7 @@ static int __video1394_ioctl(struct file *file, ...@@ -1118,7 +1136,7 @@ static int __video1394_ioctl(struct file *file,
if ((v.buffer<0) || (v.buffer>d->num_desc)) { if ((v.buffer<0) || (v.buffer>d->num_desc)) {
PRINT(KERN_ERR, ohci->host->id, PRINT(KERN_ERR, ohci->host->id,
"Buffer %d out of range",v.buffer); "Buffer %d out of range",v.buffer);
return -EFAULT; return -EINVAL;
} }
switch(d->buffer_status[v.buffer]) { switch(d->buffer_status[v.buffer]) {
...@@ -1144,11 +1162,11 @@ static int __video1394_ioctl(struct file *file, ...@@ -1144,11 +1162,11 @@ static int __video1394_ioctl(struct file *file,
default: default:
PRINT(KERN_ERR, ohci->host->id, PRINT(KERN_ERR, ohci->host->id,
"Buffer %d is not queued",v.buffer); "Buffer %d is not queued",v.buffer);
return -EFAULT; return -ESRCH;
} }
} }
default: default:
return -EINVAL; return -ENOTTY;
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment