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

📄 pcilynx.c

📁 IEE1394 火线接口驱动 for linux
💻 C
📖 第 1 页 / 共 5 页
字号:
        u32 *pcli;        int i;        int error;        /* needed for i2c communication with serial eeprom */        struct i2c_adapter i2c_adapter;        struct i2c_algo_bit_data i2c_adapter_data;        int got_valid_bus_info_block = 0; /* set to 1, if we were able to get a valid bus info block from serial eeprom */        error = -ENXIO;        if (pci_set_dma_mask(dev, 0xffffffff))                FAIL("DMA address limits not supported for PCILynx hardware");        if (pci_enable_device(dev))                FAIL("failed to enable PCILynx hardware");        pci_set_master(dev);        error = -ENOMEM;	host = hpsb_alloc_host(&lynx_driver, sizeof(struct ti_lynx));        if (!host) FAIL("failed to allocate control structure memory");        lynx = host->hostdata;	lynx->id = card_id++;        lynx->dev = dev;        lynx->state = clear;	lynx->host = host;        host->pdev = dev;        pci_set_drvdata(dev, lynx);        lynx->lock = SPIN_LOCK_UNLOCKED;        lynx->phy_reg_lock = SPIN_LOCK_UNLOCKED;#ifndef CONFIG_IEEE1394_PCILYNX_LOCALRAM        lynx->pcl_mem = pci_alloc_consistent(dev, LOCALRAM_SIZE,                                             &lynx->pcl_mem_dma);        if (lynx->pcl_mem != NULL) {                lynx->state = have_pcl_mem;                PRINT(KERN_INFO, lynx->id,                       "allocated PCL memory %d Bytes @ 0x%p", LOCALRAM_SIZE,                      lynx->pcl_mem);        } else {                FAIL("failed to allocate PCL memory area");        }#endif#ifdef CONFIG_IEEE1394_PCILYNX_PORTS        lynx->mem_dma_buffer = pci_alloc_consistent(dev, 65536,                                                    &lynx->mem_dma_buffer_dma);        if (lynx->mem_dma_buffer == NULL) {                FAIL("failed to allocate DMA buffer for aux");        }        lynx->state = have_aux_buf;#endif        lynx->rcv_page = pci_alloc_consistent(dev, PAGE_SIZE,                                              &lynx->rcv_page_dma);        if (lynx->rcv_page == NULL) {                FAIL("failed to allocate receive buffer");        }        lynx->state = have_1394_buffers;        for (i = 0; i < ISORCV_PAGES; i++) {                lynx->iso_rcv.page[i] =                        pci_alloc_consistent(dev, PAGE_SIZE,                                             &lynx->iso_rcv.page_dma[i]);                if (lynx->iso_rcv.page[i] == NULL) {                        FAIL("failed to allocate iso receive buffers");                }        }        lynx->registers = ioremap_nocache(pci_resource_start(dev,0),                                          PCILYNX_MAX_REGISTER);        lynx->local_ram = ioremap(pci_resource_start(dev,1), PCILYNX_MAX_MEMORY);        lynx->aux_port  = ioremap(pci_resource_start(dev,2), PCILYNX_MAX_MEMORY);        lynx->local_rom = ioremap(pci_resource_start(dev,PCI_ROM_RESOURCE),                                  PCILYNX_MAX_MEMORY);        lynx->state = have_iomappings;        if (lynx->registers == NULL) {                FAIL("failed to remap registers - card not accessible");        }#ifdef CONFIG_IEEE1394_PCILYNX_LOCALRAM        if (lynx->local_ram == NULL) {                FAIL("failed to remap local RAM which is required for "                     "operation");        }#endif        reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET);        /* Fix buggy cards with autoboot pin not tied low: */        reg_write(lynx, DMA0_CHAN_CTRL, 0);#ifndef __sparc__	sprintf (irq_buf, "%d", dev->irq);#else	sprintf (irq_buf, "%s", __irq_itoa(dev->irq));#endif        if (!request_irq(dev->irq, lynx_irq_handler, SA_SHIRQ,                         PCILYNX_DRIVER_NAME, lynx)) {                PRINT(KERN_INFO, lynx->id, "allocated interrupt %s", irq_buf);                lynx->state = have_intr;        } else {                FAIL("failed to allocate shared interrupt %s", irq_buf);        }        /* alloc_pcl return values are not checked, it is expected that the         * provided PCL space is sufficient for the initial allocations */#ifdef CONFIG_IEEE1394_PCILYNX_PORTS        if (lynx->aux_port != NULL) {                lynx->dmem_pcl = alloc_pcl(lynx);                aux_setup_pcls(lynx);                sema_init(&lynx->mem_dma_mutex, 1);        }#endif        lynx->rcv_pcl = alloc_pcl(lynx);        lynx->rcv_pcl_start = alloc_pcl(lynx);        lynx->async.pcl = alloc_pcl(lynx);        lynx->async.pcl_start = alloc_pcl(lynx);        lynx->iso_send.pcl = alloc_pcl(lynx);        lynx->iso_send.pcl_start = alloc_pcl(lynx);        for (i = 0; i < NUM_ISORCV_PCL; i++) {                lynx->iso_rcv.pcl[i] = alloc_pcl(lynx);        }        lynx->iso_rcv.pcl_start = alloc_pcl(lynx);        /* all allocations successful - simple init stuff follows */        reg_write(lynx, PCI_INT_ENABLE, PCI_INT_DMA_ALL);#ifdef CONFIG_IEEE1394_PCILYNX_PORTS        reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_AUX_INT);        init_waitqueue_head(&lynx->mem_dma_intr_wait);        init_waitqueue_head(&lynx->aux_intr_wait);#endif	tasklet_init(&lynx->iso_rcv.tq, (void (*)(unsigned long))iso_rcv_bh,		     (unsigned long)lynx);        lynx->iso_rcv.lock = SPIN_LOCK_UNLOCKED;        lynx->async.queue_lock = SPIN_LOCK_UNLOCKED;        lynx->async.channel = CHANNEL_ASYNC_SEND;        lynx->iso_send.queue_lock = SPIN_LOCK_UNLOCKED;        lynx->iso_send.channel = CHANNEL_ISO_SEND;                PRINT(KERN_INFO, lynx->id, "remapped memory spaces reg 0x%p, rom 0x%p, "              "ram 0x%p, aux 0x%p", lynx->registers, lynx->local_rom,              lynx->local_ram, lynx->aux_port);        /* now, looking for PHY register set */        if ((get_phy_reg(lynx, 2) & 0xe0) == 0xe0) {                lynx->phyic.reg_1394a = 1;                PRINT(KERN_INFO, lynx->id,                      "found 1394a conform PHY (using extended register set)");                lynx->phyic.vendor = get_phy_vendorid(lynx);                lynx->phyic.product = get_phy_productid(lynx);        } else {                lynx->phyic.reg_1394a = 0;                PRINT(KERN_INFO, lynx->id, "found old 1394 PHY");        }        lynx->selfid_size = -1;        lynx->phy_reg0 = -1;	INIT_LIST_HEAD(&lynx->async.queue);	INIT_LIST_HEAD(&lynx->async.pcl_queue);	INIT_LIST_HEAD(&lynx->iso_send.queue);	INIT_LIST_HEAD(&lynx->iso_send.pcl_queue);        pcl.next = pcl_bus(lynx, lynx->rcv_pcl);        put_pcl(lynx, lynx->rcv_pcl_start, &pcl);        pcl.next = PCL_NEXT_INVALID;        pcl.async_error_next = PCL_NEXT_INVALID;#ifdef __BIG_ENDIAN        pcl.buffer[0].control = PCL_CMD_RCV | 16;        pcl.buffer[1].control = PCL_LAST_BUFF | 4080;#else        pcl.buffer[0].control = PCL_CMD_RCV | PCL_BIGENDIAN | 16;        pcl.buffer[1].control = PCL_LAST_BUFF | 4080;#endif        pcl.buffer[0].pointer = lynx->rcv_page_dma;        pcl.buffer[1].pointer = lynx->rcv_page_dma + 16;        put_pcl(lynx, lynx->rcv_pcl, &pcl);                pcl.next = pcl_bus(lynx, lynx->async.pcl);        pcl.async_error_next = pcl_bus(lynx, lynx->async.pcl);        put_pcl(lynx, lynx->async.pcl_start, &pcl);        pcl.next = pcl_bus(lynx, lynx->iso_send.pcl);        pcl.async_error_next = PCL_NEXT_INVALID;        put_pcl(lynx, lynx->iso_send.pcl_start, &pcl);        pcl.next = PCL_NEXT_INVALID;        pcl.async_error_next = PCL_NEXT_INVALID;        pcl.buffer[0].control = PCL_CMD_RCV | 4;#ifndef __BIG_ENDIAN        pcl.buffer[0].control |= PCL_BIGENDIAN;#endif        pcl.buffer[1].control = PCL_LAST_BUFF | 2044;        for (i = 0; i < NUM_ISORCV_PCL; i++) {                int page = i / ISORCV_PER_PAGE;                int sec = i % ISORCV_PER_PAGE;                pcl.buffer[0].pointer = lynx->iso_rcv.page_dma[page]                         + sec * MAX_ISORCV_SIZE;                pcl.buffer[1].pointer = pcl.buffer[0].pointer + 4;                put_pcl(lynx, lynx->iso_rcv.pcl[i], &pcl);        }        pcli = (u32 *)&pcl;        for (i = 0; i < NUM_ISORCV_PCL; i++) {                pcli[i] = pcl_bus(lynx, lynx->iso_rcv.pcl[i]);        }        put_pcl(lynx, lynx->iso_rcv.pcl_start, &pcl);        /* FIFO sizes from left to right: ITF=48 ATF=48 GRF=160 */        reg_write(lynx, FIFO_SIZES, 0x003030a0);        /* 20 byte threshold before triggering PCI transfer */        reg_write(lynx, DMA_GLOBAL_REGISTER, 0x2<<24);        /* threshold on both send FIFOs before transmitting:           FIFO size - cache line size - 1 */        i = reg_read(lynx, PCI_LATENCY_CACHELINE) & 0xff;        i = 0x30 - i - 1;        reg_write(lynx, FIFO_XMIT_THRESHOLD, (i << 8) | i);        reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_1394);        reg_write(lynx, LINK_INT_ENABLE, LINK_INT_PHY_TIMEOUT                  | LINK_INT_PHY_REG_RCVD  | LINK_INT_PHY_BUSRESET                  | LINK_INT_ISO_STUCK     | LINK_INT_ASYNC_STUCK                   | LINK_INT_SENT_REJECT   | LINK_INT_TX_INVALID_TC                  | LINK_INT_GRF_OVERFLOW  | LINK_INT_ITF_UNDERFLOW                  | LINK_INT_ATF_UNDERFLOW);                reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ASYNC_RCV), 0);        reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ASYNC_RCV), 0xa<<4);        reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ASYNC_RCV), 0);        reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ASYNC_RCV),                  DMA_WORD1_CMP_MATCH_LOCAL_NODE | DMA_WORD1_CMP_MATCH_BROADCAST                  | DMA_WORD1_CMP_MATCH_EXACT    | DMA_WORD1_CMP_MATCH_BUS_BCAST                  | DMA_WORD1_CMP_ENABLE_SELF_ID | DMA_WORD1_CMP_ENABLE_MASTER);        run_pcl(lynx, lynx->rcv_pcl_start, CHANNEL_ASYNC_RCV);        reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ISO_RCV), 0);        reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ISO_RCV), 0x9<<4);        reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ISO_RCV), 0);        reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), 0);        run_sub_pcl(lynx, lynx->iso_rcv.pcl_start, 0, CHANNEL_ISO_RCV);        reg_write(lynx, LINK_CONTROL, LINK_CONTROL_RCV_CMP_VALID                  | LINK_CONTROL_TX_ISO_EN   | LINK_CONTROL_RX_ISO_EN                  | LINK_CONTROL_TX_ASYNC_EN | LINK_CONTROL_RX_ASYNC_EN                  | LINK_CONTROL_RESET_TX    | LINK_CONTROL_RESET_RX);        if (!lynx->phyic.reg_1394a) {                /* attempt to enable contender bit -FIXME- would this work                 * elsewhere? */                reg_set_bits(lynx, GPIO_CTRL_A, 0x1);                reg_write(lynx, GPIO_DATA_BASE + 0x3c, 0x1);         } else {                /* set the contender bit in the extended PHY register                 * set. (Should check that bis 0,1,2 (=0xE0) is set                 * in register 2?)                 */                i = get_phy_reg(lynx, 4);                if (i != -1) set_phy_reg(lynx, 4, i | 0x40);        }        if (!skip_eeprom)        {                i2c_adapter = bit_ops;                i2c_adapter_data = bit_data;                i2c_adapter.algo_data = &i2c_adapter_data;                i2c_adapter_data.data = lynx;		PRINTD(KERN_DEBUG, lynx->id,"original eeprom control: %d",		       reg_read(lynx, SERIAL_EEPROM_CONTROL));        	/* reset hardware to sane state */        	lynx->i2c_driven_state = 0x00000070;        	reg_write(lynx, SERIAL_EEPROM_CONTROL, lynx->i2c_driven_state);        	if (i2c_bit_add_bus(&i2c_adapter) < 0)        	{	        	PRINT(KERN_ERR, lynx->id,  "unable to register i2c");        	}        	else        	{                        /* do i2c stuff */                        unsigned char i2c_cmd = 0x10;                        struct i2c_msg msg[2] = { { 0x50, 0, 1, &i2c_cmd },                                                   { 0x50, I2C_M_RD, 20, (unsigned char*) lynx->config_rom }                                                };#ifdef CONFIG_IEEE1394_VERBOSEDEBUG                        union i2c_smbus_data data;                        if (i2c_smbus_xfer(&i2c_adapter, 80, 0, I2C_SMBUS_WRITE, 0, I2C_SMBUS_BYTE,NULL))                                PRINT(KERN_ERR, lynx->id,"eeprom read start has failed");                        else                        {                                u16 addr;                                for (addr=0x00; addr < 0x100; addr++) {                                        if (i2c_smbus_xfer(&i2c_adapter, 80, 0, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE,& data)) {                                                PRINT(KERN_ERR, lynx->id, "unable to read i2c %x", addr);                                                break;                                        }                                        else                                                PRINT(KERN_DEBUG, lynx->id,"got serial eeprom data at %x: %x",addr, data.byte);                                }                        }#endif                        /* we use i2c_transfer, because i2c_smbus_read_block_data does not work properly and we                           do it more efficiently in one transaction rather then using several reads */                        if (i2c_transfer(&i2c_adapter, msg, 2) < 0) {                                PRINT(KERN_ERR, lynx->id, "unable to read bus info block from i2c");                        } else {                                int i;                                PRINT(KERN_INFO, lynx->id, "got bus info block from serial eeprom");				/* FIXME: probably we shoud rewrite the max_rec, max_ROM(1394a),				 * generation(1394a) and link_spd(1394a) field and recalculate				 * the CRC */                                for (i = 0; i < 5 ; i++)                                        PRINTD(KERN_DEBUG, lynx->id, "Businfo block quadlet %i: %08x",					       i, be32_to_cpu(lynx->config_rom[i]));                                /* info_length, crc_length and 1394 magic number to check, if it is really a bus info block */                                if (((be32_to_cpu(lynx->config_rom[0]) & 0xffff0000) == 0x04040000) &&                                    (lynx->config_rom[1] == __constant_cpu_to_be32(0x31333934)))                                {                                        PRINT(KERN_DEBUG, lynx->id, "read a valid bus info block from");                                        got_valid_bus_info_block = 1;                                } else {                                        PRINT(KERN_WARNING, lynx->id, "read something from serial eeprom, but it does not seem to be a valid bus info block");                                }                        }                        i2c_bit_del_bus(&i2c_adapter);                }        }        if (got_valid_bus_info_block) {                memcpy(lynx->config_rom+5,lynx_csr_rom+5,sizeof(lynx_csr_rom)-20);        } else {                PRINT(KERN_INFO, lynx->id, "since we did not get a bus info block from serial eeprom, we use a generic one with a hard coded GUID");                memcpy(lynx->config_rom,lynx_csr_rom,sizeof(lynx_csr_rom));        }        hpsb_add_host(host);        lynx->state = is_host;        return 0;#undef FAIL}static size_t get_lynx_rom(struct hpsb_host *host, quadlet_t **ptr){        struct ti_lynx *lynx = host->hostdata;        *ptr = lynx->config_rom;        return sizeof(lynx_csr_rom);}static struct pci_device_id pci_table[] __devinit

⌨️ 快捷键说明

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