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

📄 ohci1394.c

📁 这个是uClinux下的ieee1394驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
		}	}        spin_lock_init(&d->lock);	/* initialize tasklet */	if (type == DMA_CTX_ISO) {		ohci1394_init_iso_tasklet(&ohci->it_tasklet, OHCI_ISO_TRANSMIT,					  dma_rcv_tasklet, (unsigned long) d);		if (ohci1394_register_iso_tasklet(ohci,						  &ohci->it_tasklet) < 0) {			PRINT(KERN_ERR, ohci->id, "No IT DMA context available");			free_dma_trm_ctx(d);			return -EBUSY;		}	}	else		tasklet_init (&d->task, dma_trm_tasklet, (unsigned long)d);	return 0;}static u16 ohci_crc16 (u32 *ptr, int length){	int shift;	u32 crc, sum, data;	crc = 0;	for (; length > 0; length--) {		data = be32_to_cpu(*ptr++);		for (shift = 28; shift >= 0; shift -= 4) {			sum = ((crc >> 12) ^ (data >> shift)) & 0x000f;			crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ sum;		}		crc &= 0xffff;	}	return crc;}/* Config ROM macro implementation influenced by NetBSD OHCI driver */struct config_rom_unit {	u32 *start;	u32 *refer;	int length;	int refunit;};struct config_rom_ptr {	u32 *data;	int unitnum;	struct config_rom_unit unitdir[10];};#define cf_put_1quad(cr, q) (((cr)->data++)[0] = cpu_to_be32(q))#define cf_put_4bytes(cr, b1, b2, b3, b4) \	(((cr)->data++)[0] = cpu_to_be32(((b1) << 24) | ((b2) << 16) | ((b3) << 8) | (b4)))#define cf_put_keyval(cr, key, val) (((cr)->data++)[0] = cpu_to_be32(((key) << 24) | (val)))static inline void cf_put_str(struct config_rom_ptr *cr, const char *str){	int t;	char fourb[4];	while (str[0]) {		memset(fourb, 0, 4);		for (t = 0; t < 4 && str[t]; t++)			fourb[t] = str[t];		cf_put_4bytes(cr, fourb[0], fourb[1], fourb[2], fourb[3]);		str += strlen(str) < 4 ? strlen(str) : 4;	}	return;}static inline void cf_put_crc16(struct config_rom_ptr *cr, int unit){	*cr->unitdir[unit].start =		cpu_to_be32((cr->unitdir[unit].length << 16) |			    ohci_crc16(cr->unitdir[unit].start + 1,				       cr->unitdir[unit].length));}static inline void cf_unit_begin(struct config_rom_ptr *cr, int unit){	if (cr->unitdir[unit].refer != NULL) {		*cr->unitdir[unit].refer |=			cpu_to_be32 (cr->data - cr->unitdir[unit].refer);		cf_put_crc16(cr, cr->unitdir[unit].refunit);	}	cr->unitnum = unit;	cr->unitdir[unit].start = cr->data++;}static inline void cf_put_refer(struct config_rom_ptr *cr, char key, int unit){	cr->unitdir[unit].refer = cr->data;	cr->unitdir[unit].refunit = cr->unitnum;	(cr->data++)[0] = cpu_to_be32(key << 24);}static inline void cf_unit_end(struct config_rom_ptr *cr){	cr->unitdir[cr->unitnum].length = cr->data -		(cr->unitdir[cr->unitnum].start + 1);	cf_put_crc16(cr, cr->unitnum);}/* End of NetBSD derived code.  */static void ohci_init_config_rom(struct ti_ohci *ohci){	struct config_rom_ptr cr;	memset(&cr, 0, sizeof(cr));	memset(ohci->csr_config_rom_cpu, 0, sizeof (ohci->csr_config_rom_cpu));	cr.data = ohci->csr_config_rom_cpu;	/* Bus info block */	cf_unit_begin(&cr, 0);	cf_put_1quad(&cr, reg_read(ohci, OHCI1394_BusID));	cf_put_1quad(&cr, reg_read(ohci, OHCI1394_BusOptions));	cf_put_1quad(&cr, reg_read(ohci, OHCI1394_GUIDHi));	cf_put_1quad(&cr, reg_read(ohci, OHCI1394_GUIDLo));	cf_unit_end(&cr);	DBGMSG(ohci->id, "GUID: %08x:%08x", reg_read(ohci, OHCI1394_GUIDHi),		reg_read(ohci, OHCI1394_GUIDLo));	/* IEEE P1212 suggests the initial ROM header CRC should only	 * cover the header itself (and not the entire ROM). Since we do	 * this, then we can make our bus_info_len the same as the CRC	 * length.  */	ohci->csr_config_rom_cpu[0] |= cpu_to_be32(		(be32_to_cpu(ohci->csr_config_rom_cpu[0]) & 0x00ff0000) << 8);	reg_write(ohci, OHCI1394_ConfigROMhdr,		  be32_to_cpu(ohci->csr_config_rom_cpu[0]));	/* Root directory */	cf_unit_begin(&cr, 1);	/* Vendor ID */	cf_put_keyval(&cr, 0x03, reg_read(ohci,OHCI1394_VendorID) & 0xFFFFFF);	cf_put_refer(&cr, 0x81, 2);		/* Textual description unit */	cf_put_keyval(&cr, 0x0c, 0x0083c0);	/* Node capabilities */	/* NOTE: Add other unit referers here, and append at bottom */	cf_unit_end(&cr);	/* Textual description - "Linux 1394" */	cf_unit_begin(&cr, 2);	cf_put_keyval(&cr, 0, 0);	cf_put_1quad(&cr, 0);	cf_put_str(&cr, "Linux OHCI-1394");	cf_unit_end(&cr);	ohci->csr_config_rom_length = cr.data - ohci->csr_config_rom_cpu;}static size_t ohci_get_rom(struct hpsb_host *host, const quadlet_t **ptr){	struct ti_ohci *ohci=host->hostdata;	DBGMSG(ohci->id, "request csr_rom address: %p",		ohci->csr_config_rom_cpu);	*ptr = ohci->csr_config_rom_cpu;	return ohci->csr_config_rom_length * 4;}static quadlet_t ohci_hw_csr_reg(struct hpsb_host *host, int reg,                                 quadlet_t data, quadlet_t compare){	struct ti_ohci *ohci = host->hostdata;	int i;	reg_write(ohci, OHCI1394_CSRData, data);	reg_write(ohci, OHCI1394_CSRCompareData, compare);	reg_write(ohci, OHCI1394_CSRControl, reg & 0x3);	for (i = 0; i < OHCI_LOOP_COUNT; i++) {		if (reg_read(ohci, OHCI1394_CSRControl) & 0x80000000)			break;		mdelay(1);	}	return reg_read(ohci, OHCI1394_CSRData);}static struct hpsb_host_driver ohci1394_driver = {	.name =			OHCI1394_DRIVER_NAME,	.get_rom =		ohci_get_rom,	.transmit_packet =	ohci_transmit,	.devctl =		ohci_devctl,	.hw_csr_reg =		ohci_hw_csr_reg,};/*********************************** * PCI Driver Interface functions  * ***********************************/#define FAIL(err, fmt, args...)			\do {						\	PRINT_G(KERN_ERR, fmt , ## args);	\        ohci1394_pci_remove(dev);               \	return err;				\} while(0)static int __devinit ohci1394_pci_probe(struct pci_dev *dev,					const struct pci_device_id *ent){	static unsigned int card_id_counter = 0;	static int version_printed = 0;	struct hpsb_host *host;	struct ti_ohci *ohci;	/* shortcut to currently handled device */	unsigned long ohci_base;		if (version_printed++ == 0)		PRINT_G(KERN_INFO, "%s", version);        if (pci_enable_device(dev))		FAIL(-ENXIO, "Failed to enable OHCI hardware %d",		        card_id_counter++);        pci_set_master(dev);	host = hpsb_alloc_host(&ohci1394_driver, sizeof(struct ti_ohci));	if (!host) FAIL(-ENOMEM, "Failed to allocate host structure");	ohci = host->hostdata;	ohci->id = card_id_counter++;	ohci->dev = dev;	ohci->host = host;	ohci->init_state = OHCI_INIT_ALLOC_HOST;	host->pdev = dev;	pci_set_drvdata(dev, ohci);	/* We don't want hardware swapping */	pci_write_config_dword(dev, OHCI1394_PCI_HCI_Control, 0);	/* Some oddball Apple controllers do not order the selfid	 * properly, so we make up for it here.  */#ifndef __LITTLE_ENDIAN	/* XXX: Need a better way to check this. I'm wondering if we can	 * read the values of the OHCI1394_PCI_HCI_Control and the	 * noByteSwapData registers to see if they were not cleared to	 * zero. Should this work? Obviously it's not defined what these	 * registers will read when they aren't supported. Bleh! */	if (dev->vendor == PCI_VENDOR_ID_APPLE && 	    dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) {		ohci->no_swap_incoming = 1;		ohci->selfid_swap = 0;	} else		ohci->selfid_swap = 1;#endif	/* We hardwire the MMIO length, since some CardBus adaptors	 * fail to report the right length.  Anyway, the ohci spec	 * clearly says it's 2kb, so this shouldn't be a problem. */ 	ohci_base = pci_resource_start(dev, 0);	if (pci_resource_len(dev, 0) != OHCI1394_REGISTER_SIZE)		PRINT(KERN_WARNING, ohci->id, "Unexpected PCI resource length of %lx!",		      pci_resource_len(dev, 0));	/* Seems PCMCIA handles this internally. Not sure why. Seems	 * pretty bogus to force a driver to special case this.  */#ifndef PCMCIA	if (!request_mem_region (ohci_base, OHCI1394_REGISTER_SIZE, OHCI1394_DRIVER_NAME))		FAIL(-ENOMEM, "MMIO resource (0x%lx - 0x%lx) unavailable",		     ohci_base, ohci_base + OHCI1394_REGISTER_SIZE);#endif	ohci->init_state = OHCI_INIT_HAVE_MEM_REGION;	ohci->registers = ioremap(ohci_base, OHCI1394_REGISTER_SIZE);	if (ohci->registers == NULL)		FAIL(-ENXIO, "Failed to remap registers - card not accessible");	ohci->init_state = OHCI_INIT_HAVE_IOMAPPING;	DBGMSG(ohci->id, "Remapped memory spaces reg 0x%p", ohci->registers);	/* csr_config rom allocation */	ohci->csr_config_rom_cpu =		pci_alloc_consistent(ohci->dev, OHCI_CONFIG_ROM_LEN,				     &ohci->csr_config_rom_bus);	OHCI_DMA_ALLOC("consistent csr_config_rom");	if (ohci->csr_config_rom_cpu == NULL)		FAIL(-ENOMEM, "Failed to allocate buffer config rom");	ohci->init_state = OHCI_INIT_HAVE_CONFIG_ROM_BUFFER;	/* self-id dma buffer allocation */	ohci->selfid_buf_cpu = 		pci_alloc_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE,                      &ohci->selfid_buf_bus);	OHCI_DMA_ALLOC("consistent selfid_buf");		if (ohci->selfid_buf_cpu == NULL)		FAIL(-ENOMEM, "Failed to allocate DMA buffer for self-id packets");	ohci->init_state = OHCI_INIT_HAVE_SELFID_BUFFER;	if ((unsigned long)ohci->selfid_buf_cpu & 0x1fff)		PRINT(KERN_INFO, ohci->id, "SelfID buffer %p is not aligned on "		      "8Kb boundary... may cause problems on some CXD3222 chip", 		      ohci->selfid_buf_cpu);  	/* No self-id errors at startup */	ohci->self_id_errors = 0;	ohci->init_state = OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE;	/* AR DMA request context allocation */	if (alloc_dma_rcv_ctx(ohci, &ohci->ar_req_context,			      DMA_CTX_ASYNC_REQ, 0, AR_REQ_NUM_DESC,			      AR_REQ_BUF_SIZE, AR_REQ_SPLIT_BUF_SIZE,			      OHCI1394_AsReqRcvContextBase) < 0)		FAIL(-ENOMEM, "Failed to allocate AR Req context");	/* AR DMA response context allocation */	if (alloc_dma_rcv_ctx(ohci, &ohci->ar_resp_context,			      DMA_CTX_ASYNC_RESP, 0, AR_RESP_NUM_DESC,			      AR_RESP_BUF_SIZE, AR_RESP_SPLIT_BUF_SIZE,			      OHCI1394_AsRspRcvContextBase) < 0)		FAIL(-ENOMEM, "Failed to allocate AR Resp context");	/* AT DMA request context */	if (alloc_dma_trm_ctx(ohci, &ohci->at_req_context,			      DMA_CTX_ASYNC_REQ, 0, AT_REQ_NUM_DESC,			      OHCI1394_AsReqTrContextBase) < 0)		FAIL(-ENOMEM, "Failed to allocate AT Req context");	/* AT DMA response context */	if (alloc_dma_trm_ctx(ohci, &ohci->at_resp_context,			      DMA_CTX_ASYNC_RESP, 1, AT_RESP_NUM_DESC,			      OHCI1394_AsRspTrContextBase) < 0)		FAIL(-ENOMEM, "Failed to allocate AT Resp context");	/* Start off with a soft reset, to clear everything to a sane	 * state. */	ohci_soft_reset(ohci);	/* Now enable LPS, which we need in order to start accessing	 * most of the registers.  In fact, on some cards (ALI M5251),	 * accessing registers in the SClk domain without LPS enabled	 * will lock up the machine.  Wait 50msec to make sure we have	 * full link enabled.  */	reg_write(ohci, OHCI1394_HCControlSet, 0x00080000);	mdelay(50);	/* Determine the number of available IR and IT contexts. */	ohci->nb_iso_rcv_ctx =		get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet);	DBGMSG(ohci->id, "%d iso receive contexts available",	       ohci->nb_iso_rcv_ctx);	ohci->nb_iso_xmit_ctx =		get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet);	DBGMSG(ohci->id, "%d iso transmit contexts available",	       ohci->nb_iso_xmit_ctx);	/* Set the usage bits for non-existent contexts so they can't	 * be allocated */	ohci->ir_ctx_usage = ~0 << ohci->nb_iso_rcv_ctx;	ohci->it_ctx_usage = ~0 << ohci->nb_iso_xmit_ctx;	INIT_LIST_HEAD(&ohci->iso_tasklet_list);	spin_lock_init(&ohci->iso_tasklet_list_lock);	ohci->ISO_channel_usage = 0;        spin_lock_init(&ohci->IR_channel_lock);	/* IR DMA context */	if (alloc_dma_rcv_ctx(ohci, &ohci->ir_context,			      DMA_CTX_ISO, 0, IR_NUM_DESC,			      IR_BUF_SIZE, IR_SPLIT_BUF_SIZE,			      OHCI1394_IsoRcvContextBase) < 0)		FAIL(-ENOMEM, "Failed to allocate IR context");		/* IT DMA context allocation */	if (alloc_dma_trm_ctx(ohci, &ohci->it_context,			      DMA_CTX_ISO, 0, IT_NUM_DESC,			      OHCI1394_IsoXmitContextBase) < 0)		FAIL(-ENOMEM, "Failed to allocate IT context");	if (request_irq(dev->irq, ohci_irq_handler, SA_SHIRQ,			 OHCI1394_DRIVER_NAME, ohci))		FAIL(-ENOMEM, "Failed to allocate shared interrupt %d", dev->irq);	ohci->init_state = OHCI_INIT_HAVE_IRQ;	ohci_initialize(ohci);	/* Tell the highlevel this host is ready */	hpsb_add_host(host);	ohci->init_state = OHCI_INIT_DONE;	return 0;#undef FAIL}static void ohci1394_pci_remove(struct pci_dev *pdev){	struct ti_ohci *ohci;	ohci = pci_get_drvdata(pdev);	if (!ohci)		return;	switch (ohci->init_state) {	case OHCI_INIT_DONE:		hpsb_remove_host(ohci->host);	case OHCI_INIT_HAVE_IRQ:		/* Soft reset before we start - this disables		 * interrupts and clears linkEnable and LPS. */		ohci_soft_reset(ohci);		free_irq(ohci->dev->irq, ohci);	case OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE:		/* Free AR dma */		free_dma_rcv_ctx(&ohci->ar_req_context);		free_dma_rcv_ctx(&ohci->ar_resp_context);		/* Free AT dma */		free_dma_trm_ctx(&ohci->at_req_context);		free_dma_trm_ctx(&ohci->at_resp_context);		/* Free IR dma */		free_dma_rcv_ctx(&ohci->ir_context);				/* Free IT dma */		free_dma_trm_ctx(&ohci->it_context);		case OHCI_INIT_HAVE_SELFID_BUFFER:		pci_free_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE, 				    ohci->selfid_buf_cpu,				    ohci->self

⌨️ 快捷键说明

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