📄 serial2002.c
字号:
/* comedi/drivers/serial2002.c Skeleton code for a Comedi driver COMEDI - Linux Control and Measurement Device Interface Copyright (C) 2002 Anders Blomdell <anders.blomdell@control.lth.se> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*//*Driver: serial2002.oDescription: Driver for serial connected hardwareDevices:Author: Anders BlomdellUpdated: Fri, 7 Jun 2002 12:56:45 -0700Status: in development*/#include <linux/comedidev.h>#include <linux/delay.h>#include <linux/ioport.h>/* * Board descriptions for two imaginary boards. Describing the * boards in this way is optional, and completely driver-dependent. * Some drivers use arrays such as this, other do not. */typedef struct serial2002_board_struct { char *name;} serial2002_board;serial2002_board serial2002_boards[] = { { name: "serial2002" }};/* * Useful for shorthand access to the particular board structure */#define thisboard ((serial2002_board *)dev->board_ptr)typedef struct { // HACK... int length; comedi_krange range;} serial2002_range_table_t;typedef struct { int port; // /dev/ttyS<port> int speed; // baudrate struct file *tty; lsampl_t ao_readback[32]; unsigned char digital_in_mapping[32]; unsigned char digital_out_mapping[32]; unsigned char analog_in_mapping[32]; unsigned char analog_out_mapping[32]; serial2002_range_table_t in_range[32], out_range[32];} serial2002_private;/* * most drivers define the following macro to make it easy to * access the private structure. */#define devpriv ((serial2002_private *)dev->private)static int serial2002_attach(comedi_device *dev,comedi_devconfig *it);static int serial2002_detach(comedi_device *dev);comedi_driver driver_serial2002={ driver_name: "serial2002", module: THIS_MODULE, attach: serial2002_attach, detach: serial2002_detach, board_name: serial2002_boards, offset: sizeof(serial2002_board), num_names: sizeof(serial2002_boards) / sizeof(serial2002_board),};static int serial2002_di_rinsn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data);static int serial2002_do_winsn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data);static int serial2002_ai_rinsn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn,lsampl_t *data);static int serial2002_ao_winsn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data);static int serial2002_ao_rinsn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data);struct serial_data { enum { is_invalid, is_digital, is_channel } kind; int index; unsigned long value;};static int tty_write(struct file *f, unsigned char *buf, int count) { int result; mm_segment_t oldfs; oldfs = get_fs(); set_fs(KERNEL_DS); f->f_pos = 0; result = f->f_op->write(f, buf, count, &f->f_pos); set_fs(oldfs); return result;}static int tty_available(struct file *f) { long result = 0; mm_segment_t oldfs; oldfs = get_fs(); set_fs(KERNEL_DS); f->f_op->ioctl(f->f_dentry->d_inode, f, FIONREAD, (int)&result); set_fs(oldfs); return result;}static int tty_read(struct file *f, int timeout) { int result, retries; mm_segment_t oldfs; result = -1; if (!IS_ERR(f)) { retries = 0; oldfs = get_fs(); set_fs(KERNEL_DS); while (retries < timeout) { retries++; if (tty_available(f) > 0) { int count; unsigned char ch; f->f_pos = 0; count = f->f_op->read(f, &ch, 1, &f->f_pos); if (count == 1) { result = ch; } break; } comedi_udelay(100); } set_fs(oldfs); } return result;}static void tty_setspeed(struct file *f, int speed){ mm_segment_t oldfs; oldfs = get_fs(); set_fs(KERNEL_DS); { // Set speed struct termios settings; f->f_op->ioctl(f->f_dentry->d_inode, f, TCGETS, (int)&settings);// printk("Speed: %d\n", settings.c_cflag & (CBAUD | CBAUDEX)); settings.c_iflag = 0; settings.c_oflag = 0; settings.c_lflag = 0; settings.c_cflag = CLOCAL | CS8 | CREAD; settings.c_cc[VMIN] = 1; settings.c_cc[VTIME] = 0; switch (speed) { case 2400: { settings.c_cflag |= B2400; } break; case 4800: { settings.c_cflag |= B4800; } break; case 9600: { settings.c_cflag |= B9600; } break; case 19200: { settings.c_cflag |= B19200; } break; case 38400: { settings.c_cflag |= B38400; } break; case 57600: { settings.c_cflag |= B57600; } break; case 115200: { settings.c_cflag |= B115200; } break; default: { settings.c_cflag |= B9600; } break; } f->f_op->ioctl(f->f_dentry->d_inode, f, TCSETS, (int)&settings);// printk("Speed: %d\n", settings.c_cflag & (CBAUD | CBAUDEX)); } { // Set low latency struct serial_struct settings; int i; f->f_op->ioctl(f->f_dentry->d_inode, f, TIOCGSERIAL, (int)&settings); settings.flags |= ASYNC_LOW_LATENCY; f->f_op->ioctl(f->f_dentry->d_inode, f, TIOCSSERIAL, (int)&settings); } set_fs(oldfs);}static void poll_digital(struct file *f, int channel) { char cmd; cmd = 0x40 | (channel & 0x1f); tty_write(f, &cmd, 1);}static void poll_channel(struct file *f, int channel) { char cmd; cmd = 0x60 | (channel & 0x1f); tty_write(f, &cmd, 1);}static struct serial_data serial_read(struct file *f, int timeout) { struct serial_data result; int length; result.kind = is_invalid; result.index = 0; result.value = 0; length = 0; while (1) { int data = tty_read(f, timeout); length++; if (data < 0) { break; } else if (data & 0x80) { result.value = (result.value << 7) | (data & 0x7f); } else { if (length == 1) { switch ((data>>5) & 0x03) { case 0: { result.value = 0; result.kind = is_digital; } break; case 1: { result.value = 1; result.kind = is_digital; } break; } } else { result.value = (result.value << 2) | ((data & 0x60) >> 5); result.kind = is_channel; } result.index = data & 0x1f; break; } } return result;}static void serial_write(struct file *f, struct serial_data data) { if (data.kind == is_digital) { unsigned char ch = ((data.value<<5) & 0x20) | (data.index & 0x1f); tty_write(f, &ch, 1); } else { unsigned char ch[6]; int i = 0; if (data.value >= (1L<<30)) { ch[i] = 0x80|((data.value>>30)&0x03); i++; } if (data.value >= (1L<<23)) { ch[i] = 0x80|((data.value>>23)&0x7f); i++; } if (data.value >= (1L<<16)) { ch[i] = 0x80|((data.value>>16)&0x7f); i++; } if (data.value >= (1L<< 9)) { ch[i] = 0x80|((data.value>> 9)&0x7f); i++; } ch[i] = 0x80|((data.value>> 2)&0x7f); i++; ch[i] = ((data.value<< 5)&0x60)|(data.index & 0x1f); i++; tty_write(f, ch, i); }}static int serial_2002_open(comedi_device *dev) { char port[20]; sprintf(port, "/dev/ttyS%d", devpriv->port); devpriv->tty = filp_open(port, 0, O_RDWR); if (IS_ERR(devpriv->tty)) { printk("serial_2002: file open error = %x\n", (int)devpriv->tty); } else { typedef struct { int kind; int bits; int min; int max; } config_t; config_t dig_in_config[32]; config_t dig_out_config[32]; config_t chan_in_config[32]; config_t chan_out_config[32]; int i; for (i = 0 ; i < 32 ; i++) { dig_in_config[i].kind = 0; dig_in_config[i].bits = 0; dig_in_config[i].min = 0; dig_in_config[i].max = 0; dig_out_config[i].kind = 0; dig_out_config[i].bits = 0; dig_out_config[i].min = 0; dig_out_config[i].max = 0; chan_in_config[i].kind = 0; chan_in_config[i].bits = 0; chan_in_config[i].min = 0; chan_in_config[i].max = 0; chan_out_config[i].kind = 0; chan_out_config[i].bits = 0; chan_out_config[i].min = 0; chan_out_config[i].max = 0; } tty_setspeed(devpriv->tty, devpriv->speed); poll_channel(devpriv->tty, 31); // Start reading configuration while (1) { struct serial_data data;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -