📄 ohci1394.c
字号:
} } 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 + -