📄 serproto.c
字号:
static int serial_chars_in_buffer (struct tty_struct *tty){ struct serproto_dev *device; int n; //dbg_rx(4,"entered"); if ((device = tty->driver_data) == NULL) { dbg_rx (1, "not presently connected -> FAIL"); return (-EINVAL); } read_lock (&device->rwlock); n = device->queued_bytes; read_unlock (&device->rwlock); //dbg_rx(4,"->%d",n); return (n);}static struct tty_driver serial_tty_driver = { magic:TTY_DRIVER_MAGIC, driver_name:"usbd-serial", name:"usb", major:SERIAL_TTY_MAJOR, minor_start:0, num:SERIAL_TTY_MINORS, type:TTY_DRIVER_TYPE_SERIAL, subtype:SERIAL_TYPE_NORMAL, flags:TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS, refcount:&serial_refcount, table:serial_tty, termios:serial_termios, termios_locked:serial_termios_locked, open:serial_open, close:serial_close, flush_buffer:serial_flush, write:serial_write, write_room:serial_write_room, ioctl:serial_ioctl, set_termios:serial_set_termios, throttle:serial_throttle, unthrottle:serial_unthrottle, chars_in_buffer:serial_chars_in_buffer,};/* Library Interface Functions ***************************************************************** *//** * serproto_modinit - initialize the serproto library * @name: name * @num: number of interfaces to allow * */int serproto_modinit (char *name, int num){ dbg_init (1, "%s[%d]", name, num); rwlock_init (&serproto_rwlock); serproto_devices = num; if (!(serproto_device_array = kmalloc (sizeof (struct serproto_dev *) * num, GFP_KERNEL))) { dbg_init (0, "kmalloc failed"); return -EINVAL; } memset (serproto_device_array, 0, sizeof (struct serproto_dev *) * num); dbg_loop (1, "LOOPBACK mode"); return 0;}static void wakeup_writers (void *private){ struct serproto_dev *device = (struct serproto_dev *) private; struct tty_struct *tty; if (NULL != device && NULL != (tty = device->tty)) { if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && NULL != tty->ldisc.write_wakeup) { (tty->ldisc.write_wakeup) (tty); } wake_up_interruptible (&tty->write_wait); } MOD_DEC_USE_COUNT;}/** * serproto_create - create a serial interface * @name: name * @xmit_data: callback to transmit data * @max_queue_entries: maximum number of outstanding requests to allow * @max_queue_bytes: maximum number of bytes to allow * * Create a serial interface, providing an xmit data function. * * A returned value greater or equal to zero indicates success. This value can be * used with subsequent function calls to indicate the created serial interface. */int serproto_create (char *name, int (*xmit_data) (int, unsigned char *, int), int tx_size, int max_queue_entries, int max_queue_bytes, int blocked, int trailer){ struct serproto_dev *device; int i; dbg_init (1, "array: %p name: %p[%s] xmit: %p", serproto_device_array, name, name, xmit_data); if (!serproto_device_array) { dbg_init (1, "invalid args -> FAIL"); return (-EINVAL); } /* Note: the tty layer assumes that if *_write_room() returns n > 0, that n more bytes can be queued up in UPTO n CALLS TO *_write(). It does not re-verify the available room. This means that if we are limiting the number of queued entries, and we indicate that 64 _bytes_ can be queued, there may be upto 64 *_write(1) calls, which is probably going to overflow the queue. It would also seem that the tty layer does not check the return value of the *_write() calls, so that calls which fail due to insufficient queue entries are simply lost. For this reason, setting max_queue_entries to 0 allows unlimitied queueing. */ if (!serproto_device_array || !name || !strlen (name) || !xmit_data || max_queue_entries < 0 || max_queue_bytes <= 0) { dbg_init (1, "invalid args -> FAIL"); return (-EINVAL); } { unsigned long flags; write_lock_irqsave (&serproto_rwlock, flags); for (i = 0; i < serproto_devices; i++) { if (!(device = serproto_device_array[i])) { break; } } if (i == serproto_devices) { write_unlock_irqrestore (&serproto_rwlock, flags); dbg_init (1, "name: %s cannot find empty serproto_device slot", name); return (-ENOMEM); } if (!(device = kmalloc (sizeof (struct serproto_dev), GFP_ATOMIC))) { write_unlock_irqrestore (&serproto_rwlock, flags); dbg_init (1, "name: %s kmalloc failed", name); return (-ENOMEM); } memset (device, 0, sizeof (struct serproto_dev)); rwlock_init (&device->rwlock); device->xmit_data = xmit_data; device->tx_size = MIN (256, tx_size); // maximum 256 bytes device->max_queue_entries = max_queue_entries; device->max_queue_bytes = max_queue_bytes; device->write_wakeup_task.routine = wakeup_writers; device->write_wakeup_task.data = device; device->blocked = blocked; device->trailer = trailer; memcpy (&device->tty_driver, &serial_tty_driver, sizeof (struct tty_driver)); device->tty_driver.init_termios = tty_std_termios; device->tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; // Turn off echo fight with standard UNIX USB Host serial drivers. device->tty_driver.init_termios.c_lflag &= ~(ECHO | ICANON); /* We don't need \n -> \r\n output conversion */ device->tty_driver.init_termios.c_oflag &= ~ONLCR; serproto_device_array[i] = device; write_unlock_irqrestore (&serproto_rwlock, flags); } if (tty_register_driver (&device->tty_driver)) { unsigned long flags; write_lock_irqsave (&serproto_rwlock, flags); serproto_device_array[i] = NULL; kfree (device); write_unlock_irqrestore (&serproto_rwlock, flags); printk (KERN_ERR __FUNCTION__ "(%s) - failed to register tty driver\n", name); dbg_init (1, "try registration failed"); return (-EINVAL); } dbg_init (2, "name: %s -> %d", name, i); return (i);}/** * serproto_done - transmit done * @interface: device interface * @data: data buffer * @len: data length * @rc: non-zero indicates failure * */int serproto_done (int interface, void *data, int len, int rc){ struct serproto_dev *device; unsigned long flags; dbg_tx (4, "interface: %d", interface); // Must be done with interrupts off, since sync may // be set by another (different) call to queue_task() write_lock_irqsave (&device->rwlock, flags); if ((device = serproto_device_array[interface]) == NULL) { write_unlock_irqrestore (&device->rwlock, flags); dbg_tx (1, "no device -> FAIL"); return (-EINVAL); } device->queued_entries--; device->queued_bytes -= len; if (!device->write_wakeup_task.sync) { // Queue a wakeup for anyone waiting to write, // but lock the module in place first. MOD_INC_USE_COUNT; queue_task (&device->write_wakeup_task, &tq_immediate); mark_bh (IMMEDIATE_BH); } write_unlock_irqrestore (&device->rwlock, flags); return 0;}/** * serproto_recv - receive data * @data: data buffer * @length: length of valid data */int serproto_recv (int interface, unsigned char *data, int length){ struct serproto_dev *device; struct tty_struct *tty; unsigned long flags; int i; dbg_rx (4, "length=%d", length); dbg_rx (5, "interface: %d data: %p serproto_device_array: %p", interface, data, serproto_device_array); dbg_rx (5, "device: %p", serproto_device_array[interface]); if ((device = serproto_device_array[interface]) == NULL) { dbg_rx (1, "no device -> FAIL"); return (-EINVAL); }#if 0 if (0 != dbgflg_loopback) { // serproto_done() will free data when transmission complete device->xmit_data (device->number, data, length); write_lock_irqsave (&device->rwlock, flags); device->queued_entries++; device->queued_bytes += length; write_unlock_irqrestore (&device->rwlock, flags); dbg_rx (3, "loopback->0"); return (0); }#endif if (device->opencnt <= 0 || (tty = device->tty) == NULL) { dbg_rx (1, "no tty -> FAIL"); //kfree(data); return (-EINVAL); } // XXX bail if not open for reading.... for (i = 0; i < length; ++i) { tty_insert_flip_char (tty, data[i], 0); } tty_flip_buffer_push (tty); //kfree(data); dbg_rx (4, "->0"); return 0;}/** * serproto_control - control serial interface * @interface: serial interface * @operation: operation * * Control a serial interface, */int serproto_control (int interface, int operation){ struct serproto_dev *device; unsigned long flags; dbg_mgmt (1, "interface: %d op=%d", interface, operation); if ((device = serproto_device_array[interface]) == NULL) { dbg_mgmt (1, "no device"); return (-ENODEV); } switch (operation) { case SERPROTO_CONNECT: write_lock_irqsave (&device->rwlock, flags); device->connected = TRUE; /* Wake up anybody who might have blocked waiting for the connection. */ // Must be done with interrupts off, since sync may // be set by another (different) call to queue_task() if (!device->write_wakeup_task.sync) { // Queue a wakeup for anyone waiting to write, // but lock the module in place first. MOD_INC_USE_COUNT; queue_task (&device->write_wakeup_task, &tq_immediate); mark_bh (IMMEDIATE_BH); } write_unlock_irqrestore (&device->rwlock, flags); break; case SERPROTO_DISCONNECT: device->connected = FALSE; /* Send a HANGUP to anybody involved with this device. */ if (device->tty && !device->clocal) { dbg_mgmt (1, "calling hangup"); tty_hangup (device->tty); } } return 0;}/** * serproto_destroy - destroy a serial interface * @interface: serial interface * * Call to tear down a previously created serial interface */int serproto_destroy (int interface){ struct serproto_dev *device; unsigned int flags; dbg_init (1, "interface: %d", interface); if ((device = serproto_device_array[interface]) == NULL) { dbg_init (1, "no device"); return (0); } // grab device lock and delete device entry from serproto device array write_lock_irqsave (&serproto_rwlock, flags); device = serproto_device_array[interface]; serproto_device_array[interface] = NULL; // Let write_wakeup_task know this device is toast. device->tty = NULL; write_unlock_irqrestore (&serproto_rwlock, flags); // remove serial interace tty_unregister_driver (&device->tty_driver); // XXXX make sure write_wakeup_task is not scheduled!!! kfree (device); dbg_init (2, "->0"); return 0;}/** * serproto_modexit - unload library * */void serproto_modexit (void){ int i; int devices; struct serproto_dev **device_array; unsigned int flags; dbg_init (1, "entered"); if (0 == serproto_devices) { // nothing to do return; } /* This should never be called from an interrupt context, so irq save/restore shouldn't be required, but it isn't going to be called often enough for the extra overhead to hurt either. */ write_lock_irqsave (&serproto_rwlock, flags); devices = serproto_devices; serproto_devices = 0; write_unlock_irqrestore (&serproto_rwlock, flags); for (i = 0; i < devices; i++) { serproto_destroy (i); } write_lock_irqsave (&serproto_rwlock, flags); device_array = serproto_device_array; serproto_device_array = NULL; write_unlock_irqrestore (&serproto_rwlock, flags); kfree (serproto_device_array);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -