ircard_cs.c
来自「linux操作系统下的红外驱动的测试程序」· C语言 代码 · 共 1,368 行 · 第 1/3 页
C
1,368 行
self->tx_q.tail = SHMEM_TX_START + idev->io.membase; ircard_probe(idev); /* Initialize QoS for this device */ irda_init_max_qos_capabilies(&idev->qos); /* The only value we must override it the baudrate */ idev->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| IR_115200|IR_576000|IR_1152000 |(IR_4000000 << 8); idev->qos.min_turn_time.bits = qos_mtt_bits; irda_qos_bits_to_value(&idev->qos); idev->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_SHM|IFF_PIO; /* Specify which buffer allocation policy we need */ idev->rx_buff.flags = GFP_KERNEL; idev->tx_buff.flags = GFP_KERNEL; /* We still need the SIR buffer since we don't use shmem for that */ idev->rx_buff.truesize = 4000; idev->tx_buff.truesize = 4000; /* Initialize callbacks */ idev->change_speed = &ircard_change_speed; idev->wait_until_sent = &ircard_wait_until_sent; idev->is_receiving = &ircard_is_receiving; /* Override the network functions we need to use */ idev->netdev.init = &ircard_net_init; idev->netdev.hard_start_xmit = &irport_hard_xmit; /* used for SIR */ idev->netdev.open = &ircard_net_open; idev->netdev.stop = &ircard_net_close; /* Open the IrDA device */ irda_device_open(idev, (char *) dev_info, self); /*irda_device_open(idev, dev_name, self);*/ link->state &= ~DEV_CONFIG_PENDING; return; cs_failed: cs_error(link->handle, last_fn, last_ret); ircard_release((u_long)link);}/* * Function ircard_release (arg) * * After a card is removed, ircard_release() will unregister the net * device, and release the PCMCIA configuration. If the device is still * open, this will be postponed until it is closed. * */static void ircard_release(u_long arg){ dev_link_t *link = (dev_link_t *) arg; struct ircard_cb *self; struct irda_device *idev; DEBUG(0, __FUNCTION__ "(0x%p)\n", link); self = (struct ircard_cb *) link->priv; idev = &self->idev; if (link->open) { DEBUG(1, "ircard_cs: release postponed, '%s' still open\n", self->node.dev_name); link->state |= DEV_STALE_CONFIG; return; } CardServices(ReleaseWindow, link->win); iounmap((void *)idev->io.membase); CardServices(ReleaseConfiguration, link->handle); CardServices(ReleaseIO, link->handle, &link->io); CardServices(ReleaseIRQ, link->handle, &link->irq); link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING);}/* * Function ircard_event (event, priority, args) * * The card status event handler. Mostly, this schedules other stuff to * run after an event is received. A CARD_REMOVAL event also sets some * flags to discourage the net drivers from trying to talk to the card * any more. * */static int ircard_event(event_t event, int priority, event_callback_args_t *args){ dev_link_t *link = args->client_data; struct irda_device *idev; struct ircard_cb *self; DEBUG(1, __FUNCTION__ "(0x%06x)\n", event); self = (struct ircard_cb *) link->priv; idev = &self->idev; ASSERT(self != NULL, return -1;); ASSERT(self->magic == IRCARD_MAGIC, return -1;); switch (event) { case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { self->stop = 1; link->release.expires = RUN_AT(HZ/20); add_timer(&link->release); } break; case CS_EVENT_CARD_INSERTION: link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; ircard_config(link); break; case CS_EVENT_PM_SUSPEND: link->state |= DEV_SUSPEND; /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: /* Mark the device as stopped, to block IO until later */ self->stop = 1; if (link->state & DEV_CONFIG) CardServices(ReleaseConfiguration, link->handle); break; case CS_EVENT_PM_RESUME: link->state &= ~DEV_SUSPEND; /* Fall through... */ case CS_EVENT_CARD_RESET: if (link->state & DEV_CONFIG) CardServices(RequestConfiguration, link->handle, &link->conf); self->stop = 0; /* * In a normal driver, additional code may go here to restore * the device state and restart IO. */ irport_start(idev, idev->io.iobase2); ircard_change_speed(idev, 9600); break; } return 0;}/* * Function ircard_probe (iobase, iobase2, irq, dma) * * * */static int ircard_probe(struct irda_device *idev){ int revision; int iobase; iobase = idev->io.iobase; /* Read revision ID */ switch_bank(iobase, 3); revision = inb(iobase+REVISION_ID); /* (bank 3) */ printk("IBM 31T1502 controller revision %d\n", revision); /* Initialize shared memory page register */ outb(0, iobase+SH_MEM_PAGE); /* (bank 3) */ /* Enable Tx CRC just in case */ switch_bank(iobase, 0); outb(TX_CTRL2_EN_TX_CRC, iobase+TX_CTRL2); switch_bank(iobase, 3); outb(0, iobase+SH_MEM_PAGE); /* (bank 3) */ outb(0, iobase+TX_DMA_ADDR_LOW); /* (bank 3) */ outb(PAGE_DISABLE, iobase+TX_DMA_ADDR_HIGH); /* (bank 3) */ return 0;}/* * Function ircard_sir_to_fir (iobase) * * Some code to make the tranceiver switch from SIR to FIR mode * */static void ircard_sir_to_fir(struct irda_device *idev, int iobase){ DEBUG(4, __FUNCTION__ "()\n"); __switch_bank(iobase, 2); /* Set XCRVOFF */ outb(IR_TRANS_CTRL_XCVROFF, iobase+IR_TRANS_CTRL); /* Wait a minimum of 2 us */ udelay(2); /* Set TXD_FORCE */ outb(IR_TRANS_CTRL_XCVROFF|IR_TRANS_CTRL_TXD_FRC, iobase+IR_TRANS_CTRL); /* Wait a minimum of 2 us */ udelay(2); /* Clear XCRVOFF */ outb(IR_TRANS_CTRL_TXD_FRC, iobase+IR_TRANS_CTRL); /* Wait a minimum of 2 us */ udelay(2); /* Clear TXD_FORCE */ outb(0, iobase+IR_TRANS_CTRL);}/* * Function ircard_fir_to_sir (iobase) * * Some code to make the tranceiver switch from FIR to SIR mode * */static void ircard_fir_to_sir(struct irda_device *idev, int iobase){ DEBUG(4, __FUNCTION__ "()\n"); __switch_bank(iobase, 2); /* Set XCRVOFF */ outb(IR_TRANS_CTRL_XCVROFF, iobase+IR_TRANS_CTRL); /* Wait a minimum of 2 us */ udelay(2); /* Clear XCRVOFF */ outb(0, iobase+IR_TRANS_CTRL);}/* * Function ircard_change_speed (idev, baud) * * Change the speed of the device * */static void ircard_change_speed(struct irda_device *idev, __u32 speed){ struct ircard_cb *self; unsigned long flags; int iobase; DEBUG(4, __FUNCTION__ "()\n"); ASSERT(idev != NULL, return;); ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); self = (struct ircard_cb *) idev->priv; iobase = idev->io.iobase; /* Serialize access to the driver */ spin_lock_irqsave(&idev->lock, flags); /* Check if we are switching from FIR to SIR, or SIR to FIR */ if ((idev->io.baudrate > 1152000) && (speed < 4000000)) ircard_fir_to_sir(idev, iobase); else if ((idev->io.baudrate < 4000000) && (speed > 1152000)) ircard_sir_to_fir(idev, iobase); /* Update accounting for new speed */ idev->io.baudrate = speed; if (speed > 115200) /* Install the FIR transmit handler */ idev->netdev.hard_start_xmit = &ircard_hard_xmit; else /* Install the SIR transmit handler */ idev->netdev.hard_start_xmit = &irport_hard_xmit; /* Reset hardware */ __switch_bank(iobase, 0); outb_p(0x07, iobase+7); /* Switch to bank2 and disable interrupts */ __switch_bank(iobase, 2); switch (speed) { default: DEBUG(4, __FUNCTION__ "(), unknown baud rate of %d\n", speed); /* FALLTHROUGH */ case 9600: /* FALLTHROUGH */ case 19200: /* FALLTHROUGH */ case 37600: /* FALLTHROUGH */ case 57600: /* FALLTHROUGH */ case 115200: irport_start(idev, idev->io.iobase2); irport_change_speed(idev, speed); outb_p(IR_CONF_SIR, iobase+IR_CONF); break; case 576000: DEBUG(0, __FUNCTION__ "(), handling baud of 576000\n"); irport_stop(idev, idev->io.iobase2); outb_p(IR_CONF_MIR_576|IR_CONF_MIR, iobase+IR_CONF); break; case 1152000: DEBUG(0, __FUNCTION__ "(), handling baud of 1152000\n"); irport_stop(idev, idev->io.iobase2); outb_p(IR_CONF_MIR_1152|IR_CONF_MIR, iobase+IR_CONF); break; case 4000000: DEBUG(4, __FUNCTION__ "(), handling baud of 4000000\n"); irport_stop(idev, idev->io.iobase2); outb_p(IR_CONF_FIR, iobase+IR_CONF); break; } idev->netdev.tbusy = 0; /* Enable some interrupts so we can receive frames */ if (speed > 115200) { /* Enable receiving, interrupts and go to bank 0*/ ircard_receive(idev, iobase); } spin_unlock_irqrestore(&idev->lock, flags);}/* * Function ircard_hard_xmit (skb, dev) * * Transmit the frame! * */static int ircard_hard_xmit(struct sk_buff *skb, struct net_device *dev){ struct irda_device *idev; struct ircard_cb *self; unsigned long flags; int mtt, diff; idev = (struct irda_device *) dev->priv; self = idev->priv; /* Lock transmit buffer */ if (irda_lock((void *) &dev->tbusy) == FALSE) return -EBUSY; /* Serialize access to the driver */ spin_lock_irqsave(&idev->lock, flags); switch_bank(idev->io.iobase, 0); /* Register this frame */ self->tx_q.queue[self->tx_q.free].start = self->tx_q.tail; self->tx_q.queue[self->tx_q.free].len = skb->len; self->tx_q.tail += skb->len; /* Copy data to transmit part of shared memory */ copy_to_pc((void *) self->tx_q.queue[self->tx_q.free].start, skb->data, skb->len); self->tx_q.len++; self->tx_q.free++; /* Start transmit only if there is currently no transmit going on */ if (self->tx_q.len == 1) { /* Extract minimum turnaround time from skb */ mtt = irda_get_mtt(skb); /* Currently we just use udelay for the MTT delay */ if (mtt) { /* Check how much time we have used already */ do_gettimeofday(&self->now); diff = self->now.tv_usec - self->stamp.tv_usec; if (diff < 0) diff += 1000000; /* Check if the mtt is larger than the time we have * already used by all the protocol processing */ if (mtt > diff) { DEBUG(4, __FUNCTION__ "(), delay=%d us\n", mtt-diff); /* Currently we just use udelay for the MTT * delay */ udelay(mtt-diff); } } ircard_dma_write(idev, idev->io.iobase); } spin_unlock_irqrestore(&idev->lock, flags); dev_kfree_skb(skb); /* Not busy transmitting anymore */ dev->tbusy = 0; /* Return success */ return 0;}/* * Function ircard_dma_write (idev, iobase) * * Transmit data using shared memory (local DMA) * */static void ircard_dma_write(struct irda_device *idev, int iobase){ struct ircard_cb *self; int addr; int ptr; self = idev->priv; ptr = self->tx_q.ptr; /* Disable Rx DMA */ switch_bank(iobase, 0); outb(0, iobase+MISC); /* (bank 0) */ idev->io.direction = IO_XMIT; ircard_set_mcr(iobase, MCR_INTR_EN|MCR_TX_EN, 0); /* Set early EOM level */ outb(TX_CTRL2_EN_TX_CRC|TX_CTRL2_EARLY_EOM_16, iobase+TX_CTRL2); /* Load the byte count to the transmit byte count register */ switch_bank(iobase, 1); outb(self->tx_q.queue[ptr].len & 0xff, iobase+TX_BYTE_COUNT_LOW); outb((self->tx_q.queue[ptr].len >> 8) & 0x1f, iobase+TX_BYTE_COUNT_HIGH); /* Set the Tx DMA start address (0 for the first transfer) */ switch_bank(iobase, 3); outb(0, iobase+SH_MEM_PAGE); /* (bank 3) */ /* Compute chip address */ addr = self->tx_q.queue[ptr].start - idev->io.membase; outb(addr & 0xff, iobase+TX_DMA_ADDR_LOW); /* (bank 3) */ outb(PAGE_DISABLE|((addr >> 8) & 0x3f), iobase+TX_DMA_ADDR_HIGH); /* Set host DMA controller for transmission */ switch_bank(iobase, 0); outb(0xc0, iobase+MISC); /* (bank 0) */ /*udelay(6);*/ /* Set RTS */ switch_bank(iobase, 0); outb(TX_CTRL1_RTS|TX_CTRL1_UNDR_EOM_I/*|TX_CTRL1_AUTO_RST_EOM*/, iobase+TX_CTRL1); /* (bank 0) */}/* * Function ircard_xmit_complete (idev, underrun) * * Finished transmitting a frame
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?