static int sync_serial_open(struct inode *inode, struct file *file) { int dev = iminor(inode); int ret = -EBUSY; sync_port *port; reg_dma_rw_cfg cfg = {.en = regk_dma_yes}; reg_dma_rw_intr_mask intr_mask = {.data = regk_dma_yes}; lock_kernel(); DEBUG(printk(KERN_DEBUG "Open sync serial port %d\n", dev)); if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled) { DEBUG(printk(KERN_DEBUG "Invalid minor %d\n", dev)); ret = -ENODEV; goto out; } port = &ports[dev]; /* Allow open this device twice (assuming one reader and one writer) */ if (port->busy == 2) { DEBUG(printk(KERN_DEBUG "Device is busy.. \n")); goto out; } if (port->init_irqs) { if (port->use_dma) { if (port == &ports[0]) { #ifdef SYNC_SER_DMA if (request_irq(DMA_OUT_INTR_VECT, tr_interrupt, 0, "synchronous serial 0 dma tr", &ports[0])) { printk(KERN_CRIT "Can't allocate sync serial port 0 IRQ"); goto out; } else if (request_irq(DMA_IN_INTR_VECT, rx_interrupt, 0, "synchronous serial 1 dma rx", &ports[0])) { free_irq(DMA_OUT_INTR_VECT, &port[0]); printk(KERN_CRIT "Can't allocate sync serial port 0 IRQ"); goto out; } else if (crisv32_request_dma(OUT_DMA_NBR, "synchronous serial 0 dma tr", DMA_VERBOSE_ON_ERROR, 0, REQ_DMA_SYNCSER)) { free_irq(DMA_OUT_INTR_VECT, &port[0]); free_irq(DMA_IN_INTR_VECT, &port[0]); printk(KERN_CRIT "Can't allocate sync serial port 0 TX DMA channel"); goto out; } else if (crisv32_request_dma(IN_DMA_NBR, "synchronous serial 0 dma rec", DMA_VERBOSE_ON_ERROR, 0, REQ_DMA_SYNCSER)) { crisv32_free_dma(OUT_DMA_NBR); free_irq(DMA_OUT_INTR_VECT, &port[0]); free_irq(DMA_IN_INTR_VECT, &port[0]); printk(KERN_CRIT "Can't allocate sync serial port 1 RX DMA channel"); goto out; } #endif } #ifdef CONFIG_ETRAXFS else if (port == &ports[1]) { #ifdef SYNC_SER_DMA if (request_irq(DMA6_INTR_VECT, tr_interrupt, 0, "synchronous serial 1 dma tr", &ports[1])) { printk(KERN_CRIT "Can't allocate sync serial port 1 IRQ"); goto out; } else if (request_irq(DMA7_INTR_VECT, rx_interrupt, 0, "synchronous serial 1 dma rx", &ports[1])) { free_irq(DMA6_INTR_VECT, &ports[1]); printk(KERN_CRIT "Can't allocate sync serial port 3 IRQ"); goto out; } else if (crisv32_request_dma( SYNC_SER1_TX_DMA_NBR, "synchronous serial 1 dma tr", DMA_VERBOSE_ON_ERROR, 0, dma_sser1)) { free_irq(DMA6_INTR_VECT, &ports[1]); free_irq(DMA7_INTR_VECT, &ports[1]); printk(KERN_CRIT "Can't allocate sync serial port 3 TX DMA channel"); goto out; } else if (crisv32_request_dma( SYNC_SER1_RX_DMA_NBR, "synchronous serial 3 dma rec", DMA_VERBOSE_ON_ERROR, 0, dma_sser1)) { crisv32_free_dma(SYNC_SER1_TX_DMA_NBR); free_irq(DMA6_INTR_VECT, &ports[1]); free_irq(DMA7_INTR_VECT, &ports[1]); printk(KERN_CRIT "Can't allocate sync serial port 3 RX DMA channel"); goto out; } #endif } #endif /* Enable DMAs */ REG_WR(dma, port->regi_dmain, rw_cfg, cfg); REG_WR(dma, port->regi_dmaout, rw_cfg, cfg); /* Enable DMA IRQs */ REG_WR(dma, port->regi_dmain, rw_intr_mask, intr_mask); REG_WR(dma, port->regi_dmaout, rw_intr_mask, intr_mask); /* Set up wordsize = 1 for DMAs. */ DMA_WR_CMD (port->regi_dmain, regk_dma_set_w_size1); DMA_WR_CMD (port->regi_dmaout, regk_dma_set_w_size1); start_dma_in(port); port->init_irqs = 0; } else { /* !port->use_dma */ #ifdef SYNC_SER_MANUAL if (port == &ports[0]) { if (request_irq(SYNCSER_INTR_VECT, manual_interrupt, 0, "synchronous serial manual irq", &ports[0])) { printk("Can't allocate sync serial manual irq"); goto out; } } #ifdef CONFIG_ETRAXFS else if (port == &ports[1]) { if (request_irq(SSER1_INTR_VECT, manual_interrupt, 0, "synchronous serial manual irq", &ports[1])) { printk(KERN_CRIT "Can't allocate sync serial manual irq"); goto out; } } #endif port->init_irqs = 0; #else panic("sync_serial: Manual mode not supported.\n"); #endif /* SYNC_SER_MANUAL */ } } /* port->init_irqs */ port->busy++; ret = 0; out: unlock_kernel(); return ret; }
static int sync_serial_open(struct inode *inode, struct file *file) { int ret = 0; int dev = iminor(inode); struct sync_port *port; #ifdef SYNC_SER_DMA reg_dma_rw_cfg cfg = { .en = regk_dma_yes }; reg_dma_rw_intr_mask intr_mask = { .data = regk_dma_yes }; #endif DEBUG(pr_debug("Open sync serial port %d\n", dev)); if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled) { DEBUG(pr_info("Invalid minor %d\n", dev)); return -ENODEV; } port = &ports[dev]; /* Allow open this device twice (assuming one reader and one writer) */ if (port->busy == 2) { DEBUG(pr_info("syncser%d is busy\n", dev)); return -EBUSY; } mutex_lock(&sync_serial_mutex); /* Clear any stale date left in the flip buffer */ port->readp = port->writep = port->flip; port->in_buffer_len = 0; port->read_ts_idx = 0; port->write_ts_idx = 0; if (port->init_irqs != no_irq_setup) { /* Init only on first call. */ port->busy++; mutex_unlock(&sync_serial_mutex); return 0; } if (port->use_dma) { #ifdef SYNC_SER_DMA const char *tmp; DEBUG(pr_info("Using DMA for syncser%d\n", dev)); tmp = dev == 0 ? "syncser0 tx" : "syncser1 tx"; if (request_irq(port->dma_out_intr_vect, tr_interrupt, 0, tmp, port)) { pr_err("Can't alloc syncser%d TX IRQ", dev); ret = -EBUSY; goto unlock_and_exit; } if (artpec_request_dma(port->dma_out_nbr, tmp, DMA_VERBOSE_ON_ERROR, 0, port->req_dma)) { free_irq(port->dma_out_intr_vect, port); pr_err("Can't alloc syncser%d TX DMA", dev); ret = -EBUSY; goto unlock_and_exit; } tmp = dev == 0 ? "syncser0 rx" : "syncser1 rx"; if (request_irq(port->dma_in_intr_vect, rx_interrupt, 0, tmp, port)) { artpec_free_dma(port->dma_out_nbr); free_irq(port->dma_out_intr_vect, port); pr_err("Can't alloc syncser%d RX IRQ", dev); ret = -EBUSY; goto unlock_and_exit; } if (artpec_request_dma(port->dma_in_nbr, tmp, DMA_VERBOSE_ON_ERROR, 0, port->req_dma)) { artpec_free_dma(port->dma_out_nbr); free_irq(port->dma_out_intr_vect, port); free_irq(port->dma_in_intr_vect, port); pr_err("Can't alloc syncser%d RX DMA", dev); ret = -EBUSY; goto unlock_and_exit; } /* Enable DMAs */ REG_WR(dma, port->regi_dmain, rw_cfg, cfg); REG_WR(dma, port->regi_dmaout, rw_cfg, cfg); /* Enable DMA IRQs */ REG_WR(dma, port->regi_dmain, rw_intr_mask, intr_mask); REG_WR(dma, port->regi_dmaout, rw_intr_mask, intr_mask); /* Set up wordsize = 1 for DMAs. */ DMA_WR_CMD(port->regi_dmain, regk_dma_set_w_size1); DMA_WR_CMD(port->regi_dmaout, regk_dma_set_w_size1); start_dma_in(port); port->init_irqs = dma_irq_setup; #endif } else { /* !port->use_dma */ #ifdef SYNC_SER_MANUAL const char *tmp = dev == 0 ? "syncser0 manual irq" : "syncser1 manual irq"; if (request_irq(port->syncser_intr_vect, manual_interrupt, 0, tmp, port)) { pr_err("Can't alloc syncser%d manual irq", dev); ret = -EBUSY; goto unlock_and_exit; } port->init_irqs = manual_irq_setup; #else panic("sync_serial: Manual mode not supported\n"); #endif /* SYNC_SER_MANUAL */ } port->busy++; ret = 0; unlock_and_exit: mutex_unlock(&sync_serial_mutex); return ret; }