📄 sync_serial.c
字号:
avail = end - start; else avail = port->in_buffer_size - (start - end); return avail;}static inline int sync_data_avail_to_end(struct sync_port *port){ int avail; unsigned char *start; unsigned char *end; start = (unsigned char*)port->readp; /* cast away volatile */ end = (unsigned char*)port->writep; /* cast away volatile */ /* 0123456789 0123456789 * ----- ----- * ^rp ^wp ^wp ^rp */ if (end >= start) avail = end - start; else avail = port->in_buffer + port->in_buffer_size - start; return avail;}static int sync_serial_open(struct inode *inode, struct file *file){ int dev = MINOR(inode->i_rdev); sync_port* port; int mode; DEBUG(printk("Open sync serial port %d\n", dev)); if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) { DEBUG(printk("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(printk("Device is busy.. \n")); return -EBUSY; } port->busy++; /* Start port if we use it as input */ mode = IO_EXTRACT(R_SYNC_SERIAL1_CTRL, mode, port->ctrl_data_shadow); if (mode == IO_STATE_VALUE(R_SYNC_SERIAL1_CTRL, mode, master_input) || mode == IO_STATE_VALUE(R_SYNC_SERIAL1_CTRL, mode, slave_input) || mode == IO_STATE_VALUE(R_SYNC_SERIAL1_CTRL, mode, master_bidir) || mode == IO_STATE_VALUE(R_SYNC_SERIAL1_CTRL, mode, slave_bidir)) { SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_halt, running); SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, tr_enable, enable); SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, rec_enable, enable); port->started = 1; *port->ctrl_data = port->ctrl_data_shadow; if (!port->use_dma) *R_IRQ_MASK1_SET = 1 << port->data_avail_bit; DEBUG(printk("sser%d rec started\n", dev)); } return 0;}static int sync_serial_release(struct inode *inode, struct file *file){ int dev = MINOR(inode->i_rdev); sync_port* port; if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) { DEBUG(printk("Invalid minor %d\n", dev)); return -ENODEV; } port = &ports[dev]; if (port->busy) port->busy--; if (!port->busy) *R_IRQ_MASK1_CLR = ((1 << port->data_avail_bit) | (1 << port->transmitter_ready_bit)); return 0;}static unsigned int sync_serial_poll(struct file *file, poll_table *wait){ int dev = MINOR(file->f_dentry->d_inode->i_rdev); unsigned int mask = 0; sync_port* port; DEBUGPOLL( static unsigned int prev_mask = 0; ); port = &ports[dev]; poll_wait(file, &port->out_wait_q, wait); poll_wait(file, &port->in_wait_q, wait); /* Some room to write */ if (port->out_count < OUT_BUFFER_SIZE) mask |= POLLOUT | POLLWRNORM; /* At least an inbufchunk of data */ if (sync_data_avail(port) >= port->inbufchunk) mask |= POLLIN | POLLRDNORM; DEBUGPOLL(if (mask != prev_mask) printk("sync_serial_poll: mask 0x%08X %s %s\n", mask, mask&POLLOUT?"POLLOUT":"", mask&POLLIN?"POLLIN":""); prev_mask = mask; ); return mask;}static int sync_serial_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ int return_val = 0; unsigned long flags; int dev = MINOR(file->f_dentry->d_inode->i_rdev); sync_port* port; if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) { DEBUG(printk("Invalid minor %d\n", dev)); return -1; } port = &ports[dev]; save_flags(flags); cli(); /* Disable port while changing config */ if (dev) { if (port->use_dma) { RESET_DMA(4); WAIT_DMA(4); *R_DMA_CH4_CLR_INTR = IO_STATE(R_DMA_CH4_CLR_INTR, clr_eop, do) | IO_STATE(R_DMA_CH4_CLR_INTR, clr_descr, do); } SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode3, async); } else { if (port->use_dma) { RESET_DMA(8); WAIT_DMA(8); *R_DMA_CH8_CLR_INTR = IO_STATE(R_DMA_CH8_CLR_INTR, clr_eop, do) | IO_STATE(R_DMA_CH8_CLR_INTR, clr_descr, do); } SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode1, async); } *R_GEN_CONFIG_II = gen_config_ii_shadow; restore_flags(flags); switch(cmd) { case SSP_SPEED: if (GET_SPEED(arg) == CODEC) { if (dev) SETS(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, clk_sel_u3, codec); else SETS(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, clk_sel_u1, codec); SETF(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, prescaler, GET_FREQ(arg)); SETF(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, frame_rate, GET_FRAME_RATE(arg)); SETF(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, word_rate, GET_WORD_RATE(arg)); } else { SETF(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, tr_baud, GET_SPEED(arg)); if (dev) SETS(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, clk_sel_u3, baudrate); else SETS(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, clk_sel_u1, baudrate); } break; case SSP_MODE: if (arg > 5) return -EINVAL; if (arg == MASTER_OUTPUT || arg == SLAVE_OUTPUT) *R_IRQ_MASK1_CLR = 1 << port->data_avail_bit; else if (!port->use_dma) *R_IRQ_MASK1_SET = 1 << port->data_avail_bit; SETF(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, mode, arg); break; case SSP_FRAME_SYNC: if (arg & NORMAL_SYNC) SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_synctype, normal); else if (arg & EARLY_SYNC) SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_synctype, early); if (arg & BIT_SYNC) SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_syncsize, bit); else if (arg & WORD_SYNC) SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_syncsize, word); else if (arg & EXTENDED_SYNC) SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_syncsize, extended); if (arg & SYNC_ON) SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_sync, on); else if (arg & SYNC_OFF) SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_sync, off); if (arg & WORD_SIZE_8) SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size8bit); else if (arg & WORD_SIZE_12) SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size12bit); else if (arg & WORD_SIZE_16) SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size16bit); else if (arg & WORD_SIZE_24) SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size24bit); else if (arg & WORD_SIZE_32) SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size32bit); if (arg & BIT_ORDER_MSB) SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, bitorder, msb); else if (arg & BIT_ORDER_LSB) SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, bitorder, lsb); if (arg & FLOW_CONTROL_ENABLE) SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, flow_ctrl, enabled); else if (arg & FLOW_CONTROL_DISABLE) SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, flow_ctrl, disabled); if (arg & CLOCK_NOT_GATED) SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_mode, normal); else if (arg & CLOCK_GATED) SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_mode, gated); break; case SSP_IPOLARITY: /* NOTE!! negedge is considered NORMAL */ if (arg & CLOCK_NORMAL) SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_polarity, neg); else if (arg & CLOCK_INVERT) SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_polarity, pos); if (arg & FRAME_NORMAL) SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_polarity, normal); else if (arg & FRAME_INVERT) SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_polarity, inverted); if (arg & STATUS_NORMAL) SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, status_polarity, normal); else if (arg & STATUS_INVERT) SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, status_polarity, inverted); break; case SSP_OPOLARITY: if (arg & CLOCK_NORMAL) SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_driver, normal); else if (arg & CLOCK_INVERT) SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_driver, inverted); if (arg & FRAME_NORMAL) SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_driver, normal); else if (arg & FRAME_INVERT) SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_driver, inverted); if (arg & STATUS_NORMAL) SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, status_driver, normal); else if (arg & STATUS_INVERT) SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, status_driver, inverted); break; case SSP_SPI: SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, flow_ctrl, disabled); SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, bitorder, msb); SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size8bit); SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_sync, on); SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_syncsize, word); SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_synctype, normal); if (arg & SPI_SLAVE) { SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_polarity, inverted); SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_polarity, neg); SETF(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, mode, SLAVE_INPUT); } else { SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_driver, inverted); SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_driver, inverted); SETF(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, mode, MASTER_OUTPUT); } break; case SSP_INBUFCHUNK: if (arg > port->in_buffer_size/NUM_IN_DESCR) return -EINVAL; port->inbufchunk = arg; /* Make sure in_buffer_size is a multiple of inbufchunk */ port->in_buffer_size = (port->in_buffer_size/port->inbufchunk) * port->inbufchunk; DEBUG(printk("inbufchunk %i in_buffer_size: %i\n", port->inbufchunk, port->in_buffer_size)); if (port->use_dma) { if (port->port_nbr == 0) { RESET_DMA(9); WAIT_DMA(9); } else { RESET_DMA(5); WAIT_DMA(5); } start_dma_in(port); } break; default: return_val = -1; } /* Make sure we write the config without interruption */ save_flags(flags); cli(); /* Set config and enable port */ *port->ctrl_data = port->ctrl_data_shadow; nop(); nop(); nop(); nop(); *R_SYNC_SERIAL_PRESCALE = sync_serial_prescale_shadow; nop(); nop(); nop(); nop(); if (dev) SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode3, sync); else SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode1, sync); *R_GEN_CONFIG_II = gen_config_ii_shadow; restore_flags(flags); return return_val;}static ssize_t sync_serial_write(struct file * file, const char * buf, size_t count, loff_t *ppos){ int dev = MINOR(file->f_dentry->d_inode->i_rdev); DECLARE_WAITQUEUE(wait, current); sync_port *port; unsigned long flags; unsigned long c, c1; unsigned long free_outp; unsigned long outp; unsigned long out_buffer; if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) { DEBUG(printk("Invalid minor %d\n", dev)); return -ENODEV; } port = &ports[dev]; DEBUGWRITE(printk("W d%d c %lu (%d/%d)\n", port->port_nbr, count, port->out_count, OUT_BUFFER_SIZE)); /* Space to end of buffer */ /* * out_buffer <c1>012345<- c ->OUT_BUFFER_SIZE * outp^ +out_count ^free_outp * out_buffer 45<- c ->0123OUT_BUFFER_SIZE * +out_count outp^ * free_outp * */ /* Read variables that may be updated by interrupts */ save_flags(flags); cli(); count = count > OUT_BUFFER_SIZE - port->out_count ? OUT_BUFFER_SIZE - port->out_count : count; outp = (unsigned long)port->outp; free_outp = outp + port->out_count; restore_flags(flags); out_buffer = (unsigned long)port->out_buffer; /* Find out where and how much to write */ if (free_outp >= out_buffer + OUT_BUFFER_SIZE) free_outp -= OUT_BUFFER_SIZE; if (free_outp >= outp) c = out_buffer + OUT_BUFFER_SIZE - free_outp; else c = outp - free_outp; if (c > count) c = count; // DEBUGWRITE(printk("w op %08lX fop %08lX c %lu\n", outp, free_outp, c)); if (copy_from_user((void*)free_outp, buf, c)) return -EFAULT; if (c != count) { buf += c; c1 = count - c; DEBUGWRITE(printk("w2 fi %lu c %lu c1 %lu\n", free_outp-out_buffer, c, c1)); if (copy_from_user((void*)out_buffer, buf, c1)) return -EFAULT; } save_flags(flags); cli(); port->out_count += count; restore_flags(flags); /* Make sure transmitter/receiver is running */ if (!port->started) { SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_halt, running);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -