示例#1
0
static int audio_ioctl(struct inode *inode, struct file *file,
		       uint cmd, ulong arg)
{
	audio_state_t *state = (audio_state_t *)file->private_data;
	audio_stream_t *os = state->output_stream;
	audio_stream_t *is = state->input_stream;
	long val;

	/* dispatch based on command */
	switch (cmd) {
	case OSS_GETVERSION:
		return put_user(SOUND_VERSION, (int *)arg);

	case SNDCTL_DSP_GETBLKSIZE:
		if (file->f_mode & FMODE_WRITE)
			return put_user(os->fragsize, (int *)arg);
		else
			return put_user(is->fragsize, (int *)arg);

	case SNDCTL_DSP_GETCAPS:
		val = DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP;
		if (is && os)
			val |= DSP_CAP_DUPLEX;
		return put_user(val, (int *)arg);

	case SNDCTL_DSP_SETFRAGMENT:
		if (get_user(val, (long *) arg))
			return -EFAULT;
		if (file->f_mode & FMODE_READ) {
			int ret = audio_set_fragments(is, val);
			if (ret < 0)
				return ret;
			ret = put_user(ret, (int *)arg);
			if (ret)
				return ret;
		}
		if (file->f_mode & FMODE_WRITE) {
			int ret = audio_set_fragments(os, val);
			if (ret < 0)
				return ret;
			ret = put_user(ret, (int *)arg);
			if (ret)
				return ret;
		}
		return 0;

	case SNDCTL_DSP_SYNC:
		return audio_sync(file);

	case SNDCTL_DSP_SETDUPLEX:
		return 0;

	case SNDCTL_DSP_POST:
		return 0;

	case SNDCTL_DSP_GETTRIGGER:
		val = 0;
		if (file->f_mode & FMODE_READ && is->active && !is->stopped)
			val |= PCM_ENABLE_INPUT;
		if (file->f_mode & FMODE_WRITE && os->active && !os->stopped)
			val |= PCM_ENABLE_OUTPUT;
		return put_user(val, (int *)arg);

	case SNDCTL_DSP_SETTRIGGER:
		if (get_user(val, (int *)arg))
			return -EFAULT;
		if (file->f_mode & FMODE_READ) {
			if (val & PCM_ENABLE_INPUT) {
				if (!is->active) {
					if (!is->buffers && audio_setup_buf(is))
						return -ENOMEM;
					audio_prime_dma(is);
				}
				audio_check_tx_spin(state);
				if (is->stopped) {
					is->stopped = 0;
					sa1100_dma_resume(is->dma_ch);
				}
			} else {
				sa1100_dma_stop(is->dma_ch);
				is->stopped = 1;
			}
		}
		if (file->f_mode & FMODE_WRITE) {
			if (val & PCM_ENABLE_OUTPUT) {
				if (!os->active) {
					if (!os->buffers && audio_setup_buf(os))
						return -ENOMEM;
					if (os->mapped)
						audio_prime_dma(os);
				}
				if (os->stopped) {
					os->stopped = 0;
					sa1100_dma_resume(os->dma_ch);
				}
			} else {
				sa1100_dma_stop(os->dma_ch);
				os->stopped = 1;
			}
		}
		return 0;

	case SNDCTL_DSP_GETOPTR:
	case SNDCTL_DSP_GETIPTR:
	    {
		count_info inf = { 0, };
		audio_stream_t *s = (cmd == SNDCTL_DSP_GETOPTR) ? os : is;
		audio_buf_t *b;
		dma_addr_t ptr;
		int bytecount, offset, flags;

		if ((s == is && !(file->f_mode & FMODE_READ)) ||
		    (s == os && !(file->f_mode & FMODE_WRITE)))
			return -EINVAL;
		if (s->active) {
			save_flags_cli(flags);
			if (sa1100_dma_get_current(s->dma_ch, (void *)&b, &ptr) == 0) {
				offset = ptr - b->dma_addr;
				inf.ptr = (b - s->buffers) * s->fragsize + offset;
			} else offset = 0;
			bytecount = s->bytecount + offset;
			s->bytecount = -offset;
			inf.blocks = s->fragcount;
			s->fragcount = 0;
			restore_flags(flags);
			if (bytecount < 0)
				bytecount = 0;
			inf.bytes = bytecount;
		}
		return copy_to_user((void *)arg, &inf, sizeof(inf));
	    }

	case SNDCTL_DSP_GETOSPACE:
	    {
		audio_buf_info inf = { 0, };
		int i;

		if (!(file->f_mode & FMODE_WRITE))
			return -EINVAL;
		if (!os->buffers && audio_setup_buf(os))
			return -ENOMEM;
		for (i = 0; i < os->nbfrags; i++) {
			if (atomic_read(&os->buffers[i].sem.count) > 0) {
				if (os->buffers[i].size == 0)
					inf.fragments++;
				inf.bytes += os->fragsize - os->buffers[i].size;
			}
		}
		inf.fragstotal = os->nbfrags;
		inf.fragsize = os->fragsize;
		return copy_to_user((void *)arg, &inf, sizeof(inf));
	    }

	case SNDCTL_DSP_GETISPACE:
	    {
		audio_buf_info inf = { 0, };
		int i;

		if (!(file->f_mode & FMODE_READ))
			return -EINVAL;
		if (!is->buffers && audio_setup_buf(is))
			return -ENOMEM;
		for (i = 0; i < is->nbfrags; i++) {
			if (atomic_read(&is->buffers[i].sem.count) > 0) {
				if (is->buffers[i].size == is->fragsize)
					inf.fragments++;
				inf.bytes += is->buffers[i].size;
			}
		}
		inf.fragstotal = is->nbfrags;
		inf.fragsize = is->fragsize;
		return copy_to_user((void *)arg, &inf, sizeof(inf));
	    }

	case SNDCTL_DSP_NONBLOCK:
		file->f_flags |= O_NONBLOCK;
		return 0;

        case SNDCTL_DSP_GETODELAY: {
                int count = 0;
                int i;
		int flags;
		audio_buf_t *b;
		dma_addr_t ptr;
		if (!(file->f_mode & FMODE_WRITE))
			return -EINVAL;
		if (!os->buffers && audio_setup_buf(os))
			return -ENOMEM;
		save_flags_cli(flags);
		for (i = 0; i < os->nbfrags; i++) {
                        /* if contains data */
			if (atomic_read(&os->buffers[i].sem.count) <= 0) {
				count += os->fragsize;
			}
		}
		if (sa1100_dma_get_current(os->dma_ch, (void *)&b, &ptr) == 0)
			count -= ptr - b->dma_addr;
		restore_flags(flags);
                return put_user(count, (int *)arg);
        }

	case SNDCTL_DSP_RESET:
		if (file->f_mode & FMODE_READ) {
			if (state->tx_spinning) {
				sa1100_dma_set_spin(os->dma_ch, 0, 0);
				state->tx_spinning = 0;
			}
			audio_reset_buf(is);
		}
		if (file->f_mode & FMODE_WRITE) {
			audio_reset_buf(os);
		}
		return 0;

	default:
		/*
		 * Let the client of this module handle the
		 * non generic ioctls
		 */
		return state->client_ioctl(inode, file, cmd, arg);
	}

	return 0;
}
示例#2
0
static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev)
{
	struct sk_buff *skb = si->rxskb;
	dma_addr_t dma_addr;
	unsigned int len, stat, data;

	if (!skb) {
		printk(KERN_ERR "sa1100_ir: SKB is NULL!\n");
		return;
	}

	/*
	 * Get the current data position.
	 */
	sa1100_dma_get_current(si->rxdma, NULL, &dma_addr);
	len = dma_addr - si->rxbuf_dma;
	pci_unmap_single(NULL, si->rxbuf_dma, len, PCI_DMA_FROMDEVICE);

	do {
		/*
		 * Read Status, and then Data.
		 */
		stat = Ser2HSSR1;
		rmb();
		data = Ser2HSDR;

		if (stat & (HSSR1_CRE | HSSR1_ROR)) {
			si->stats.rx_errors++;
			if (stat & HSSR1_CRE)
				si->stats.rx_crc_errors++;
			if (stat & HSSR1_ROR)
				si->stats.rx_frame_errors++;
		} else
			skb->data[len++] = data;

		/*
		 * If we hit the end of frame, there's
		 * no point in continuing.
		 */
		if (stat & HSSR1_EOF)
			break;
	} while (Ser2HSSR0 & HSSR0_EIF);

	if (stat & HSSR1_EOF) {
		si->rxskb = NULL;

		skb_put(skb, len);
		skb->dev = dev;
		skb->mac.raw = skb->data;
		skb->protocol = htons(ETH_P_IRDA);
		si->stats.rx_packets++;
		si->stats.rx_bytes += len;

		/*
		 * Before we pass the buffer up, allocate a new one.
		 */
		sa1100_irda_rx_alloc(si);

		netif_rx(skb);
	} else {
		/*
		 * Remap the buffer.
		 */
		si->rxbuf_dma = pci_map_single(NULL, si->rxskb->data,
						HPSIR_MAX_RXLEN,
						PCI_DMA_FROMDEVICE);
	}
}