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

📄 dmascc.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
  /* If no adapter found, return error */  printk("dmascc: no adapters found\n");  return -EIO;}__initfunc(int setup_adapter(int io, int h, int n)){  int i, irq, chip;  struct scc_info *info;  struct device *dev;  struct scc_priv *priv;  unsigned long time;  unsigned int irqs;  int tmr = io + hw[h].tmr_offset;  int scc = io + hw[h].scc_offset;  int cmd = scc + SCCA_CMD;  char *chipnames[] = CHIPNAMES;  /* Reset 8530 */  write_scc(cmd, R9, FHWRES | MIE | NV);  /* Determine type of chip by enabling SDLC/HDLC enhancements */  write_scc(cmd, R15, SHDLCE);  if (!read_scc(cmd, R15)) {    /* WR7' not present. This is an ordinary Z8530 SCC. */    chip = Z8530;  } else {    /* Put one character in TX FIFO */    write_scc(cmd, R8, 0);    if (read_scc(cmd, R0) & Tx_BUF_EMP) {      /* TX FIFO not full. This is a Z85230 ESCC with a 4-byte FIFO. */      chip = Z85230;    } else {      /* TX FIFO full. This is a Z85C30 SCC with a 1-byte FIFO. */      chip = Z85C30;    }  }  write_scc(cmd, R15, 0);  /* Start IRQ auto-detection */  sti();  irqs = probe_irq_on();  /* Enable interrupts */  switch (h) {  case TYPE_PI:  case TYPE_PI2:    outb_p(0, io + PI_DREQ_MASK);    write_scc(cmd, R15, CTSIE);    write_scc(cmd, R0, RES_EXT_INT);    write_scc(cmd, R1, EXT_INT_ENAB);    break;  case TYPE_TWIN:    outb_p(0, io + TWIN_DMA_CFG);    inb_p(io + TWIN_CLR_TMR1);    inb_p(io + TWIN_CLR_TMR2);    outb_p(TWIN_EI, io + TWIN_SERIAL_CFG);    break;  }  /* Start timer */  outb_p(1, tmr + TMR_CNT1);  outb_p(0, tmr + TMR_CNT1);  /* Wait and detect IRQ */  time = jiffies; while (jiffies - time < 2 + HZ / TMR_0_HZ);  irq = probe_irq_off(irqs);  /* Clear pending interrupt, disable interrupts */  switch (h) {  case TYPE_PI:  case TYPE_PI2:    write_scc(cmd, R1, 0);    write_scc(cmd, R15, 0);    write_scc(cmd, R0, RES_EXT_INT);    break;  case TYPE_TWIN:    inb_p(io + TWIN_CLR_TMR1);    outb_p(0, io + TWIN_SERIAL_CFG);    break;  }  if (irq <= 0) {    printk("dmascc: could not find irq of %s at %#3x (irq=%d)\n",	   hw[h].name, io, irq);    return -1;  }  /* Allocate memory */  info = kmalloc(sizeof(struct scc_info), GFP_KERNEL | GFP_DMA);  if (!info) {    printk("dmascc: could not allocate memory for %s at %#3x\n",	   hw[h].name, io);    return -1;  }  /* Set up data structures */  memset(info, 0, sizeof(struct scc_info));  info->type = h;  info->chip = chip;  info->scc_base = io + hw[h].scc_offset;  info->tmr_base = io + hw[h].tmr_offset;  info->twin_serial_cfg = 0;  for (i = 0; i < 2; i++) {    dev = &info->dev[i];    priv = &info->priv[i];    sprintf(priv->name, "dmascc%i", 2*n+i);    priv->info = info;    priv->channel = i;    priv->cmd = info->scc_base + (i ? SCCB_CMD : SCCA_CMD);    priv->data = info->scc_base + (i ? SCCB_DATA : SCCA_DATA);    priv->tmr = info->tmr_base + (i ? TMR_CNT2 : TMR_CNT1);    priv->param.pclk_hz = hw[h].pclk_hz;    priv->param.brg_tc = -1;    priv->param.clocks = TCTRxCP | RCRTxCP;    priv->param.txdelay = TMR_0_HZ * 10 / 1000;    priv->param.txtime = HZ * 3;    priv->param.sqdelay = TMR_0_HZ * 1 / 1000;    priv->param.slottime = TMR_0_HZ * 10 / 1000;    priv->param.waittime = TMR_0_HZ * 100 / 1000;    priv->param.persist = 32;    priv->rx_task.routine = rx_bh;    priv->rx_task.data = dev;    dev->priv = priv;    dev->name = priv->name;    dev->base_addr = io;    dev->irq = irq;    dev->open = scc_open;    dev->stop = scc_close;    dev->do_ioctl = scc_ioctl;    dev->hard_start_xmit = scc_send_packet;    dev->get_stats = scc_get_stats;    dev->hard_header = ax25_encapsulate;    dev->rebuild_header = ax25_rebuild_header;    dev->set_mac_address = scc_set_mac_address;    SET_DEV_INIT(dev->init);    dev->type = ARPHRD_AX25;    dev->hard_header_len = 73;    dev->mtu = 1500;    dev->addr_len = 7;    dev->tx_queue_len = 64;    memcpy(dev->broadcast, ax25_broadcast, 7);    memcpy(dev->dev_addr, ax25_test, 7);    dev_init_buffers(dev);    if (register_netdevice(dev)) {      printk("dmascc: could not register %s\n", dev->name);      dev->name = NULL;    }  }  request_region(io, hw[h].io_size, "dmascc");  info->next = first;  first = info;  printk("dmascc: found %s (%s) at %#3x, irq %d\n", hw[h].name,	 chipnames[chip], io, irq);  return 0;}/* Driver functions */static inline void write_scc(int ctl, int reg, int val){  outb_p(reg, ctl);  outb_p(val, ctl);}static inline int read_scc(int ctl, int reg){  outb_p(reg, ctl);  return inb_p(ctl);}static int scc_open(struct device *dev){  struct scc_priv *priv = dev->priv;  struct scc_info *info = priv->info;  int io = dev->base_addr;  int cmd = priv->cmd;  /* Request IRQ if not already used by other channel */  if (!info->open) {    if (request_irq(dev->irq, scc_isr, SA_INTERRUPT, "dmascc", info))      return -EAGAIN;  }  /* Request DMA if required */  if (dev->dma && request_dma(dev->dma, "dmascc")) {    if (!info->open) free_irq(dev->irq, info);    return -EAGAIN;  }  /* Initialize local variables */  dev->tbusy = 0;  priv->rx_ptr = 0;  priv->rx_over = 0;  priv->rx_head = priv->rx_tail = priv->rx_count = 0;  priv->tx_state = TX_IDLE;  priv->tx_head = priv->tx_tail = priv->tx_count = 0;  priv->tx_ptr = 0;  priv->tx_sem = 0;  /* Reset channel */  write_scc(cmd, R9, (priv->channel ? CHRB : CHRA) | MIE | NV);  /* X1 clock, SDLC mode */  write_scc(cmd, R4, SDLC | X1CLK);  /* DMA */  write_scc(cmd, R1, EXT_INT_ENAB | WT_FN_RDYFN);  /* 8 bit RX char, RX disable */  write_scc(cmd, R3, Rx8);  /* 8 bit TX char, TX disable */  write_scc(cmd, R5, Tx8);  /* SDLC address field */  write_scc(cmd, R6, 0);  /* SDLC flag */  write_scc(cmd, R7, FLAG);  switch (info->chip) {  case Z85C30:    /* Select WR7' */    write_scc(cmd, R15, SHDLCE);    /* Auto EOM reset */    write_scc(cmd, R7, AUTOEOM);    write_scc(cmd, R15, 0);    break;  case Z85230:    /* Select WR7' */    write_scc(cmd, R15, SHDLCE);    /* RX FIFO half full (interrupt only), Auto EOM reset,       TX FIFO empty (DMA only) */    write_scc(cmd, R7, AUTOEOM | (dev->dma ? TXFIFOE : RXFIFOH));    write_scc(cmd, R15, 0);    break;  }  /* Preset CRC, NRZ(I) encoding */  write_scc(cmd, R10, CRCPS | (priv->param.nrzi ? NRZI : NRZ));  /* Configure baud rate generator */  if (priv->param.brg_tc >= 0) {    /* Program BR generator */    write_scc(cmd, R12, priv->param.brg_tc & 0xFF);    write_scc(cmd, R13, (priv->param.brg_tc>>8) & 0xFF);    /* BRG source = SYS CLK; enable BRG; DTR REQ function (required by       PackeTwin, not connected on the PI2); set DPLL source to BRG */    write_scc(cmd, R14, SSBR | DTRREQ | BRSRC | BRENABL);    /* Enable DPLL */    write_scc(cmd, R14, SEARCH | DTRREQ | BRSRC | BRENABL);  } else {    /* Disable BR generator */    write_scc(cmd, R14, DTRREQ | BRSRC);  }  /* Configure clocks */  if (info->type == TYPE_TWIN) {    /* Disable external TX clock receiver */    outb_p((info->twin_serial_cfg &=	    ~(priv->channel ? TWIN_EXTCLKB : TWIN_EXTCLKA)), 	   io + TWIN_SERIAL_CFG);  }  write_scc(cmd, R11, priv->param.clocks);  if ((info->type == TYPE_TWIN) && !(priv->param.clocks & TRxCOI)) {    /* Enable external TX clock receiver */    outb_p((info->twin_serial_cfg |=	    (priv->channel ? TWIN_EXTCLKB : TWIN_EXTCLKA)),	   io + TWIN_SERIAL_CFG);  }  /* Configure PackeTwin */  if (info->type == TYPE_TWIN) {    /* Assert DTR, enable interrupts */    outb_p((info->twin_serial_cfg |= TWIN_EI |	    (priv->channel ? TWIN_DTRB_ON : TWIN_DTRA_ON)),	   io + TWIN_SERIAL_CFG);  }  /* Read current status */  priv->status = read_scc(cmd, R0);  /* Enable SYNC, DCD, and CTS interrupts */  write_scc(cmd, R15, DCDIE | CTSIE | SYNCIE);  /* Configure PI2 DMA */  if (info->type <= TYPE_PI2) outb_p(1, io + PI_DREQ_MASK);  dev->start = 1;  info->open++;  MOD_INC_USE_COUNT;  return 0;}static int scc_close(struct device *dev){  struct scc_priv *priv = dev->priv;  struct scc_info *info = priv->info;  int io = dev->base_addr;  int cmd = priv->cmd;  dev->start = 0;  info->open--;  MOD_DEC_USE_COUNT;  if (info->type == TYPE_TWIN)    /* Drop DTR */    outb_p((info->twin_serial_cfg &=	    (priv->channel ? ~TWIN_DTRB_ON : ~TWIN_DTRA_ON)),	   io + TWIN_SERIAL_CFG);  /* Reset channel, free DMA */  write_scc(cmd, R9, (priv->channel ? CHRB : CHRA) | MIE | NV);  if (dev->dma) {    if (info->type == TYPE_TWIN) outb_p(0, io + TWIN_DMA_CFG);    free_dma(dev->dma);  }  if (!info->open) {    if (info->type <= TYPE_PI2) outb_p(0, io + PI_DREQ_MASK);    free_irq(dev->irq, info);  }  return 0;}static int scc_ioctl(struct device *dev, struct ifreq *ifr, int cmd){  int rc;  struct scc_priv *priv = dev->priv;    switch (cmd) {  case SIOCGSCCPARAM:    rc = verify_area(VERIFY_WRITE, ifr->ifr_data, sizeof(struct scc_param));    if (rc) return rc;    copy_to_user(ifr->ifr_data, &priv->param, sizeof(struct scc_param));    return 0;  case SIOCSSCCPARAM:    if (!suser()) return -EPERM;    rc = verify_area(VERIFY_READ, ifr->ifr_data, sizeof(struct scc_param));    if (rc) return rc;    if (dev->start) return -EAGAIN;    copy_from_user(&priv->param, ifr->ifr_data, sizeof(struct scc_param));    dev->dma = priv->param.dma;    return 0;  default:    return -EINVAL;  }}static int scc_send_packet(struct sk_buff *skb, struct device *dev){  struct scc_priv *priv = dev->priv;  struct scc_info *info = priv->info;  int cmd = priv->cmd;  unsigned long flags;  int i;  /* Block a timer-based transmit from overlapping */  if (test_and_set_bit(0, (void *) &priv->tx_sem) != 0) {    atomic_inc((void *) &priv->stats.tx_dropped);    dev_kfree_skb(skb);    return 0;  }  /* Return with an error if we cannot accept more data */  if (dev->tbusy) {    priv->tx_sem = 0;    return -1;  }  /* Transfer data to DMA buffer */  i = priv->tx_head;  memcpy(priv->tx_buf[i], skb->data+1, skb->len-1);  priv->tx_len[i] = skb->len-1;  save_flags(flags);  cli();  /* Set the busy flag if we just filled up the last buffer */  priv->tx_head = (i + 1) % NUM_TX_BUF;  priv->tx_count++;  if (priv->tx_count == NUM_TX_BUF) dev->tbusy = 1;  /* Set new TX state */  if (priv->tx_state == TX_IDLE) {    /* Assert RTS, start timer */    priv->tx_state = TX_TXDELAY;    if (info->type <= TYPE_PI2) outb_p(0, dev->base_addr + PI_DREQ_MASK);    write_scc(cmd, R5, TxCRC_ENAB | RTS | TxENAB | Tx8);    if (info->type <= TYPE_PI2) outb_p(1, dev->base_addr + PI_DREQ_MASK);    priv->tx_start = jiffies;    delay(dev, priv->param.txdelay);  }  restore_flags(flags);  dev_kfree_skb(skb);  priv->tx_sem = 0;  return 0;}static struct enet_statistics *scc_get_stats(struct device *dev){  struct scc_priv *priv = dev->priv;  return &priv->stats;}static int scc_set_mac_address(struct device *dev, void *sa){  memcpy(dev->dev_addr, ((struct sockaddr *)sa)->sa_data, dev->addr_len);  return 0;}static void scc_isr(int irq, void *dev_id, struct pt_regs * regs){  struct scc_info *info = dev_id;  int is, io = info->dev[0].base_addr;  /* We're a fast IRQ handler and are called with interrupts disabled */  /* IRQ sharing doesn't make sense due to ISA's edge-triggered     interrupts, hence it is safe to return if we have found and     processed a single device. */  /* Interrupt processing: We loop until we know that the IRQ line is     low. If another positive edge occurs afterwards during the ISR,     another interrupt will be triggered by the interrupt controller     as soon as the IRQ level is enabled again (see asm/irq.h). */  switch (info->type) {  case TYPE_PI:  case TYPE_PI2:    outb_p(0, io + PI_DREQ_MASK);    z8530_isr(info);    outb_p(1, io + PI_DREQ_MASK);    return;  case TYPE_TWIN:    while ((is = ~inb_p(io + TWIN_INT_REG)) &	   TWIN_INT_MSK) {      if (is & TWIN_SCC_MSK) {	z8530_isr(info);      } else if (is & TWIN_TMR1_MSK) {	inb_p(io + TWIN_CLR_TMR1);	tm_isr(&info->dev[0]);

⌨️ 快捷键说明

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