📄 n_hdlc.c
字号:
if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_tty_open() called\n",__FILE__,__LINE__); /* There should not be an existing table for this slot. */ if (n_hdlc) { printk (KERN_ERR"n_hdlc_tty_open:tty already associated!\n" ); return -EEXIST; } n_hdlc = n_hdlc_alloc(); if (!n_hdlc) { printk (KERN_ERR "n_hdlc_alloc failed\n"); return -ENFILE; } tty->disc_data = n_hdlc; n_hdlc->tty = tty; MOD_INC_USE_COUNT; /* Flush any pending characters in the driver and discipline. */ if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer (tty); if (tty->driver.flush_buffer) tty->driver.flush_buffer (tty); if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_tty_open() success\n",__FILE__,__LINE__); return 0; } /* end of n_tty_hdlc_open() *//* n_hdlc_send_frames() * * send frames on pending send buffer list until the * driver does not accept a frame (busy) * this function is called after adding a frame to the * send buffer list and by the tty wakeup callback * * Arguments: n_hdlc pointer to ldisc instance data * tty pointer to tty instance data * Return Value: None */static void n_hdlc_send_frames (struct n_hdlc *n_hdlc, struct tty_struct *tty){ register int actual; unsigned long flags; N_HDLC_BUF *tbuf; if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_send_frames() called\n",__FILE__,__LINE__); save_flags(flags); cli (); if (n_hdlc->tbusy) { n_hdlc->woke_up = 1; restore_flags(flags); return; } n_hdlc->tbusy = 1; restore_flags(flags); /* get current transmit buffer or get new transmit */ /* buffer from list of pending transmit buffers */ tbuf = n_hdlc->tbuf; if (!tbuf) tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list); while (tbuf) { if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)sending frame %p, count=%d\n", __FILE__,__LINE__,tbuf,tbuf->count); /* Send the next block of data to device */ n_hdlc->woke_up = 0; tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); actual = tty->driver.write(tty, 0, tbuf->buf, tbuf->count); /* if transmit error, throw frame away by */ /* pretending it was accepted by driver */ if (actual < 0) actual = tbuf->count; if (actual == tbuf->count) { if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)frame %p completed\n", __FILE__,__LINE__,tbuf); /* free current transmit buffer */ n_hdlc_buf_put(&n_hdlc->tx_free_buf_list,tbuf); /* this tx buffer is done */ n_hdlc->tbuf = NULL; /* wait up sleeping writers */ wake_up_interruptible(&n_hdlc->write_wait); /* get next pending transmit buffer */ tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list); } else { if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)frame %p pending\n", __FILE__,__LINE__,tbuf); /* buffer not accepted by driver */ /* check if wake up code called since last write call */ if (n_hdlc->woke_up) continue; /* set this buffer as pending buffer */ n_hdlc->tbuf = tbuf; break; } } if (!tbuf) tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); /* Clear the re-entry flag */ save_flags(flags); cli (); n_hdlc->tbusy = 0; restore_flags(flags); if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_send_frames() exit\n",__FILE__,__LINE__); } /* end of n_hdlc_send_frames() *//* n_hdlc_tty_wakeup() * * Callback for transmit wakeup. Called when low level * device driver can accept more send data. * * Arguments: tty pointer to associated tty instance data * Return Value: None */static void n_hdlc_tty_wakeup (struct tty_struct *tty){ struct n_hdlc *n_hdlc = tty2n_hdlc (tty); if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_tty_wakeup() called\n",__FILE__,__LINE__); if (!n_hdlc) return; if (tty != n_hdlc->tty) { tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); return; } if (!n_hdlc->tbuf) tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); else n_hdlc_send_frames (n_hdlc, tty); } /* end of n_hdlc_tty_wakeup() *//* n_hdlc_tty_room() * * Callback function from tty driver. Return the amount of * space left in the receiver's buffer to decide if remote * transmitter is to be throttled. * * Arguments: tty pointer to associated tty instance data * Return Value: number of bytes left in receive buffer */static int n_hdlc_tty_room (struct tty_struct *tty){ if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_tty_room() called\n",__FILE__,__LINE__); /* always return a larger number to prevent */ /* throttling of remote transmitter. */ return 65536;} /* end of n_hdlc_tty_root() *//* n_hdlc_tty_receive() * * Called by tty low level driver when receive data is * available. Data is interpreted as one HDLC frame. * * Arguments: tty pointer to tty isntance data * data pointer to received data * flags pointer to flags for data * count count of received data in bytes * * Return Value: None */static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 * data, char *flags, int count){ register struct n_hdlc *n_hdlc = tty2n_hdlc (tty); register N_HDLC_BUF *buf; if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_tty_receive() called count=%d\n", __FILE__,__LINE__, count); /* This can happen if stuff comes in on the backup tty */ if (n_hdlc == 0 || tty != n_hdlc->tty) return; /* verify line is using HDLC discipline */ if (n_hdlc->magic != HDLC_MAGIC) { printk("%s(%d) line not using HDLC discipline\n", __FILE__,__LINE__); return; } /* get a free HDLC buffer */ buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list); if (!buf) { /* no buffers in free list, attempt to allocate another rx buffer */ /* unless the maximum count has been reached */ if (n_hdlc->rx_buf_list.count < MAX_RX_BUF_COUNT) buf = (N_HDLC_BUF*)kmalloc(sizeof(N_HDLC_BUF),GFP_ATOMIC); } if (!buf) { printk("%s(%d) no more rx buffers, data discarded\n", __FILE__,__LINE__); return; } /* copy received data to HDLC buffer */ memcpy(buf->buf,data,count); buf->count=count; /* add HDLC buffer to list of received frames */ n_hdlc_buf_put(&n_hdlc->rx_buf_list,buf); /* wake up any blocked reads and perform async signalling */ wake_up_interruptible (&n_hdlc->read_wait); if (n_hdlc->tty->fasync != NULL) kill_fasync (n_hdlc->tty->fasync, SIGIO);} /* end of n_hdlc_tty_receive() *//* n_hdlc_tty_read() * * Called to retreive one frame of data (if available) * * Arguments: * * tty pointer to tty instance data * file pointer to open file object * buf pointer to returned data buffer * nr size of returned data buffer * * Return Value: * * Number of bytes returned or error code */static rw_ret_t n_hdlc_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf, rw_count_t nr){ struct n_hdlc *n_hdlc = tty2n_hdlc(tty); int error; rw_ret_t ret; N_HDLC_BUF *rbuf; if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_tty_read() called\n",__FILE__,__LINE__); /* Validate the pointers */ if (!n_hdlc) return -EIO; /* verify user access to buffer */ error = verify_area (VERIFY_WRITE, buf, nr); if (error != 0) { printk(KERN_WARNING"%s(%d) n_hdlc_tty_read() can't verify user " "buffer\n",__FILE__,__LINE__); return (error); } for (;;) { n_hdlc = tty2n_hdlc (tty); if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC || tty != n_hdlc->tty) return 0; rbuf = n_hdlc_buf_get(&n_hdlc->rx_buf_list); if (rbuf) break; /* no data */ if (file->f_flags & O_NONBLOCK) return -EAGAIN; /* TODO: no timeout? current->timeout = 0;*/ interruptible_sleep_on (&n_hdlc->read_wait); if (signal_pending(current)) return -EINTR; } if (rbuf->count > nr) { /* frame too large for caller's buffer (discard frame) */ ret = (rw_ret_t)-EOVERFLOW; } else { /* Copy the data to the caller's buffer */ COPY_TO_USER(error,buf,rbuf->buf,rbuf->count); if (error) ret = (rw_ret_t)error; else ret = (rw_ret_t)rbuf->count; } /* return HDLC buffer to free list unless the free list */ /* count has exceeded the default value, in which case the */ /* buffer is freed back to the OS to conserve memory */ if (n_hdlc->rx_free_buf_list.count > DEFAULT_RX_BUF_COUNT) kfree(rbuf); else n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,rbuf); return ret; } /* end of n_hdlc_tty_read() *//* n_hdlc_tty_write() * * write a single frame of data to device * * Arguments: tty pointer to associated tty device instance data * file pointer to file object data * data pointer to transmit data (one frame) * count size of transmit frame in bytes * * Return Value: number of bytes written (or error code) */static rw_ret_t n_hdlc_tty_write (struct tty_struct *tty, struct file *file, const __u8 * data, rw_count_t count){ struct n_hdlc *n_hdlc = tty2n_hdlc (tty); int error = 0; struct wait_queue wait = {current, NULL}; N_HDLC_BUF *tbuf; if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_tty_write() called count=%d\n", __FILE__,__LINE__,count); /* Verify pointers */ if (!n_hdlc) return -EIO; if (n_hdlc->magic != HDLC_MAGIC) return -EIO; /* verify frame size */ if (count > MAX_HDLC_FRAME_SIZE) { if (debuglevel & DEBUG_LEVEL_INFO) printk (KERN_WARNING "n_hdlc_tty_write: truncating user packet " "from %lu to %d\n", (unsigned long) count, MAX_HDLC_FRAME_SIZE); count = MAX_HDLC_FRAME_SIZE; } /* Allocate transmit buffer */ tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list); if (!tbuf) { /* sleep until transmit buffer available */ add_wait_queue(&n_hdlc->write_wait, &wait); while (!tbuf) { /* TODO: no timeout? current->timeout = 0;*/ current->state = TASK_INTERRUPTIBLE; schedule(); n_hdlc = tty2n_hdlc (tty); if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC || tty != n_hdlc->tty) { printk("n_hdlc_tty_write: %p invalid after wait!\n", n_hdlc); error = -EIO; break; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -