⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dv1394.c

📁 Ieee1394驱动实现
💻 C
📖 第 1 页 / 共 5 页
字号:
		status.dropped_frames = video->dropped_frames;

		/* reset dropped_frames */
		video->dropped_frames = 0;

		spin_unlock_irqrestore(&video->spinlock, flags);

		if (copy_to_user(argp, &status, sizeof(status))) {
			ret = -EFAULT;
			goto out;
		}

		ret = 0;
		break;
	}

	default:
		break;
	}

 out:
	mutex_unlock(&video->mtx);
	return ret;
}

/*** DEVICE FILE INTERFACE CONTINUED ***************************************/

static int dv1394_open(struct inode *inode, struct file *file)
{
	struct video_card *video = NULL;

	if (file->private_data) {
		video = (struct video_card*) file->private_data;

	} else {
		/* look up the card by ID */
		unsigned long flags;

		spin_lock_irqsave(&dv1394_cards_lock, flags);
		if (!list_empty(&dv1394_cards)) {
			struct video_card *p;
			list_for_each_entry(p, &dv1394_cards, list) {
				if ((p->id) == ieee1394_file_to_instance(file)) {
					video = p;
					break;
				}
			}
		}
		spin_unlock_irqrestore(&dv1394_cards_lock, flags);

		if (!video) {
			debug_printk("dv1394: OHCI card %d not found", ieee1394_file_to_instance(file));
			return -ENODEV;
		}

		file->private_data = (void*) video;
	}

#ifndef DV1394_ALLOW_MORE_THAN_ONE_OPEN

	if ( test_and_set_bit(0, &video->open) ) {
		/* video is already open by someone else */
		return -EBUSY;
 	}

#endif

	return 0;
}


static int dv1394_release(struct inode *inode, struct file *file)
{
	struct video_card *video = file_to_video_card(file);

	/* OK to free the DMA buffer, no more mappings can exist */
	do_dv1394_shutdown(video, 1);

	/* clean up async I/O users */
	dv1394_fasync(-1, file, 0);

	/* give someone else a turn */
	clear_bit(0, &video->open);

	return 0;
}


/*** DEVICE DRIVER HANDLERS ************************************************/

static void it_tasklet_func(unsigned long data)
{
	int wake = 0;
	struct video_card *video = (struct video_card*) data;

	spin_lock(&video->spinlock);

	if (!video->dma_running)
		goto out;

	irq_printk("ContextControl = %08x, CommandPtr = %08x\n",
	       reg_read(video->ohci, video->ohci_IsoXmitContextControlSet),
	       reg_read(video->ohci, video->ohci_IsoXmitCommandPtr)
	       );


	if ( (video->ohci_it_ctx != -1) &&
	    (reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & (1 << 10)) ) {

		struct frame *f;
		unsigned int frame, i;


		if (video->active_frame == -1)
			frame = 0;
		else
			frame = video->active_frame;

		/* check all the DMA-able frames */
		for (i = 0; i < video->n_frames; i++, frame = (frame+1) % video->n_frames) {

			irq_printk("IRQ checking frame %d...", frame);
			f = video->frames[frame];
			if (f->state != FRAME_READY) {
				irq_printk("clear, skipping\n");
				/* we don't own this frame */
				continue;
			}

			irq_printk("DMA\n");

			/* check the frame begin semaphore to see if we can free the previous frame */
			if ( *(f->frame_begin_timestamp) ) {
				int prev_frame;
				struct frame *prev_f;



				/* don't reset, need this later *(f->frame_begin_timestamp) = 0; */
				irq_printk("  BEGIN\n");

				prev_frame = frame - 1;
				if (prev_frame == -1)
					prev_frame += video->n_frames;
				prev_f = video->frames[prev_frame];

				/* make sure we can actually garbage collect
				   this frame */
				if ( (prev_f->state == FRAME_READY) &&
				    prev_f->done && (!f->done) )
				{
					frame_reset(prev_f);
					video->n_clear_frames++;
					wake = 1;
					video->active_frame = frame;

					irq_printk("  BEGIN - freeing previous frame %d, new active frame is %d\n", prev_frame, frame);
				} else {
					irq_printk("  BEGIN - can't free yet\n");
				}

				f->done = 1;
			}


			/* see if we need to set the timestamp for the next frame */
			if ( *(f->mid_frame_timestamp) ) {
				struct frame *next_frame;
				u32 begin_ts, ts_cyc, ts_off;

				*(f->mid_frame_timestamp) = 0;

				begin_ts = le32_to_cpu(*(f->frame_begin_timestamp));

				irq_printk("  MIDDLE - first packet was sent at cycle %4u (%2u), assigned timestamp was (%2u) %4u\n",
					   begin_ts & 0x1FFF, begin_ts & 0xF,
					   f->assigned_timestamp >> 12, f->assigned_timestamp & 0xFFF);

				/* prepare next frame and assign timestamp */
				next_frame = video->frames[ (frame+1) % video->n_frames ];

				if (next_frame->state == FRAME_READY) {
					irq_printk("  MIDDLE - next frame is ready, good\n");
				} else {
					debug_printk("dv1394: Underflow! At least one frame has been dropped.\n");
					next_frame = f;
				}

				/* set the timestamp to the timestamp of the last frame sent,
				   plus the length of the last frame sent, plus the syt latency */
				ts_cyc = begin_ts & 0xF;
				/* advance one frame, plus syt latency (typically 2-3) */
				ts_cyc += f->n_packets + video->syt_offset ;

				ts_off = 0;

				ts_cyc += ts_off/3072;
				ts_off %= 3072;

				next_frame->assigned_timestamp = ((ts_cyc&0xF) << 12) + ts_off;
				if (next_frame->cip_syt1) {
					next_frame->cip_syt1->b[6] = next_frame->assigned_timestamp >> 8;
					next_frame->cip_syt1->b[7] = next_frame->assigned_timestamp & 0xFF;
				}
				if (next_frame->cip_syt2) {
					next_frame->cip_syt2->b[6] = next_frame->assigned_timestamp >> 8;
					next_frame->cip_syt2->b[7] = next_frame->assigned_timestamp & 0xFF;
				}

			}

			/* see if the frame looped */
			if ( *(f->frame_end_timestamp) ) {

				*(f->frame_end_timestamp) = 0;

				debug_printk("  END - the frame looped at least once\n");

				video->dropped_frames++;
			}

		} /* for (each frame) */
	}

	if (wake) {
		kill_fasync(&video->fasync, SIGIO, POLL_OUT);

		/* wake readers/writers/ioctl'ers */
		wake_up_interruptible(&video->waitq);
	}

out:
	spin_unlock(&video->spinlock);
}

static void ir_tasklet_func(unsigned long data)
{
	int wake = 0;
	struct video_card *video = (struct video_card*) data;

	spin_lock(&video->spinlock);

	if (!video->dma_running)
		goto out;

	if ( (video->ohci_ir_ctx != -1) &&
	    (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) ) {

		int sof=0; /* start-of-frame flag */
		struct frame *f;
		u16 packet_length, packet_time;
		int i, dbc=0;
		struct DMA_descriptor_block *block = NULL;
		u16 xferstatus;

		int next_i, prev_i;
		struct DMA_descriptor_block *next = NULL;
		dma_addr_t next_dma = 0;
		struct DMA_descriptor_block *prev = NULL;

		/* loop over all descriptors in all frames */
		for (i = 0; i < video->n_frames*MAX_PACKETS; i++) {
			struct packet *p = dma_region_i(&video->packet_buf, struct packet, video->current_packet);

			/* make sure we are seeing the latest changes to p */
			dma_region_sync_for_cpu(&video->packet_buf,
						(unsigned long) p - (unsigned long) video->packet_buf.kvirt,
						sizeof(struct packet));

			packet_length = le16_to_cpu(p->data_length);
			packet_time   = le16_to_cpu(p->timestamp);

			irq_printk("received packet %02d, timestamp=%04x, length=%04x, sof=%02x%02x\n", video->current_packet,
				   packet_time, packet_length,
				   p->data[0], p->data[1]);

			/* get the descriptor based on packet_buffer cursor */
			f = video->frames[video->current_packet / MAX_PACKETS];
			block = &(f->descriptor_pool[video->current_packet % MAX_PACKETS]);
			xferstatus = le32_to_cpu(block->u.in.il.q[3]) >> 16;
			xferstatus &= 0x1F;
			irq_printk("ir_tasklet_func: xferStatus/resCount [%d] = 0x%08x\n", i, le32_to_cpu(block->u.in.il.q[3]) );

			/* get the current frame */
			f = video->frames[video->active_frame];

			/* exclude empty packet */
			if (packet_length > 8 && xferstatus == 0x11) {
				/* check for start of frame */
				/* DRD> Changed to check section type ([0]>>5==0)
				   and dif sequence ([1]>>4==0) */
				sof = ( (p->data[0] >> 5) == 0 && (p->data[1] >> 4) == 0);

				dbc = (int) (p->cip_h1 >> 24);
				if ( video->continuity_counter != -1 && dbc > ((video->continuity_counter + 1) % 256) )
				{
					printk(KERN_WARNING "dv1394: discontinuity detected, dropping all frames\n" );
					video->dropped_frames += video->n_clear_frames + 1;
					video->first_frame = 0;
					video->n_clear_frames = 0;
					video->first_clear_frame = -1;
				}
				video->continuity_counter = dbc;

				if (!video->first_frame) {
					if (sof) {
						video->first_frame = 1;
					}

				} else if (sof) {
					/* close current frame */
					frame_reset(f);  /* f->state = STATE_CLEAR */
					video->n_clear_frames++;
					if (video->n_clear_frames > video->n_frames) {
						video->dropped_frames++;
						printk(KERN_WARNING "dv1394: dropped a frame during reception\n" );
						video->n_clear_frames = video->n_frames-1;
						video->first_clear_frame = (video->first_clear_frame + 1) % video->n_frames;
					}
					if (video->first_clear_frame == -1)
						video->first_clear_frame = video->active_frame;

					/* get the next frame */
					video->active_frame = (video->active_frame + 1) % video->n_frames;
					f = video->frames[video->active_frame];
					irq_printk("   frame received, active_frame = %d, n_clear_frames = %d, first_clear_frame = %d\n",
						   video->active_frame, video->n_clear_frames, video->first_clear_frame);
				}
				if (video->first_frame) {
					if (sof) {
						/* open next frame */
						f->state = FRAME_READY;
					}

					/* copy to buffer */
					if (f->n_packets > (video->frame_size / 480)) {
						printk(KERN_ERR "frame buffer overflow during receive\n");
					}

					frame_put_packet(f, p);

				} /* first_frame */
			}

			/* stop, end of ready packets */
			else if (xferstatus == 0) {
				break;
			}

			/* reset xferStatus & resCount */
			block->u.in.il.q[3] = cpu_to_le32(512);

			/* terminate dma chain at this (next) packet */
			next_i = video->current_packet;
			f = video->frames[next_i / MAX_PACKETS];
			next = &(f->descriptor_pool[next_i % MAX_PACKETS]);
			next_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma;
			next->u.in.il.q[0] |= 3 << 20; /* enable interrupt */
			next->u.in.il.q[2] = 0; /* disable branch */

			/* link previous to next */
			prev_i = (next_i == 0) ? (MAX_PACKETS * video->n_frames - 1) : (next_i - 1);
			f = video->frames[prev_i / MAX_PACKETS];
			prev = &(f->descriptor_pool[prev_i % MAX_PACKETS]);
			if (prev_i % (MAX_PACKETS/2)) {
				prev->u.in.il.q[0] &= ~(3 << 20); /* no interrupt */
			} else {
				prev->u.in.il.q[0] |= 3 << 20; /* enable interrupt */
			}
			prev->u.in.il.q[2] = cpu_to_le32(next_dma | 1); /* set Z=1 */
			wmb();

			/* wake up DMA in case it fell asleep */
			reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12));

			/* advance packet_buffer cursor */
			video->current_packet = (video->current_packet + 1) % (MAX_PACKETS * video->n_frames);

		} /* for all packets */

		wake = 1; /* why the hell not? */

	} /* receive interrupt */

	if (wake) {
		kill_fasync(&video->fasync, SIGIO, POLL_IN);

		/* wake readers/writers/ioctl'ers */
		wake_up_interruptible(&video->waitq);
	}

out:
	spin_unlock(&video->spinlock);
}

static struct cdev dv1394_cdev;
static const struct file_operations dv1394_fops=
{
	.owner =	THIS_MODULE,
	.poll =         dv1394_poll,
	.unlocked_ioctl = dv1394_ioctl,
#ifdef CONFIG_COMPAT
	.compat_ioctl = dv1394_compat_ioctl,
#endif
	.mmap =		dv1394_mmap,
	.open =		dv1394_open,
	.write =        dv1394_write,
	.read =         dv1394_read,
	.release =	dv1394_release,
	.fasync =       dv1394_fasync,
};


/*** HOTPLUG STUFF **********************************************************/
/*
 * Export information about protocols/devices supported by this driver.
 */
static struct ieee1394_device_id dv1394_id_table[] = {
	{
		.match_flags	= IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
		.specifier_id	= AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
		.version	= AVC_SW_VERSION_ENTRY & 0xffffff
	},
	{ }
};

MODULE_DEVICE_TABLE(ieee1394, dv1394_id_table);

static struct hpsb_protocol_driver dv1394_driver = {
	.name		= "dv1394",
	.id_table	= dv1394_id_table,
};


/*** IEEE1394 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -