📄 sx.c
字号:
data_in_buffer = (sx_read_channel_byte (port, hi_txipos) - sx_read_channel_byte (port, hi_txopos)) & 0xff; /* XXX Must be "HIGH_WATER" for SI card according to doc. */ if (data_in_buffer < LOW_WATER) port->gs.flags &= ~GS_TX_INTEN; func_exit();}static void sx_disable_rx_interrupts (void * ptr) { /* struct sx_port *port = ptr; */ func_enter(); func_exit();}static void sx_enable_rx_interrupts (void * ptr) { /* struct sx_port *port = ptr; */ func_enter(); func_exit();}/* Jeez. Isn't this simple? */static int sx_get_CD (void * ptr) { struct sx_port *port = ptr; func_enter2(); func_exit(); return ((sx_read_channel_byte (port, hi_ip) & IP_DCD) != 0);}/* Jeez. Isn't this simple? */static int sx_chars_in_buffer (void * ptr) { struct sx_port *port = ptr; func_enter2(); func_exit(); return ((sx_read_channel_byte (port, hi_txipos) - sx_read_channel_byte (port, hi_txopos)) & 0xff);}static void sx_shutdown_port (void * ptr) { struct sx_port *port = ptr; func_enter(); port->gs.flags &= ~ GS_ACTIVE; if (port->gs.tty && (port->gs.tty->termios->c_cflag & HUPCL)) { sx_setsignals (port, 0, 0); sx_reconfigure_port(port); } func_exit();}/* ********************************************************************** * * Here are the routines that actually * * interface with the rest of the system * * ********************************************************************** */static int sx_open (struct tty_struct * tty, struct file * filp){ struct sx_port *port; int retval, line; func_enter(); if (!sx_initialized) { return -EIO; } line = MINOR(tty->device); sx_dprintk (SX_DEBUG_OPEN, "%d: opening line %d. tty=%p ctty=%p, np=%d)\n", current->pid, line, tty, current->tty, sx_nports); if ((line < 0) || (line >= SX_NPORTS) || (line >= sx_nports)) return -ENODEV; port = & sx_ports[line]; port->c_dcd = 0; /* Make sure that the first interrupt doesn't detect a 1 -> 0 transition. */ sx_dprintk (SX_DEBUG_OPEN, "port = %p c_dcd = %d\n", port, port->c_dcd); tty->driver_data = port; port->gs.tty = tty; if (!port->gs.count) MOD_INC_USE_COUNT; port->gs.count++; sx_dprintk (SX_DEBUG_OPEN, "starting port\n"); /* * Start up serial port */ retval = gs_init_port(&port->gs); sx_dprintk (SX_DEBUG_OPEN, "done gs_init\n"); if (retval) { port->gs.count--; if (port->gs.count) MOD_DEC_USE_COUNT; return retval; } port->gs.flags |= GS_ACTIVE; sx_setsignals (port, 1,1);#if 0 if (sx_debug & SX_DEBUG_OPEN) my_hd ((unsigned char *)port, sizeof (*port));#else if (sx_debug & SX_DEBUG_OPEN) my_hd ((unsigned char *)port->board->base + port->ch_base, sizeof (*port));#endif if (sx_send_command (port, HS_LOPEN, -1, HS_IDLE_OPEN) != 1) { printk (KERN_ERR "sx: Card didn't respond to LOPEN command.\n"); port->gs.count--; if (!port->gs.count) MOD_DEC_USE_COUNT; return -EIO; } retval = gs_block_til_ready(port, filp); sx_dprintk (SX_DEBUG_OPEN, "Block til ready returned %d. Count=%d\n", retval, port->gs.count); if (retval) { /* * Don't lower gs.count here because sx_close() will be called later */ return retval; } /* tty->low_latency = 1; */ if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)) { if (tty->driver.subtype == SERIAL_TYPE_NORMAL) *tty->termios = port->gs.normal_termios; else *tty->termios = port->gs.callout_termios; sx_set_real_termios (port); } port->gs.session = current->session; port->gs.pgrp = current->pgrp; port->c_dcd = sx_get_CD (port); sx_dprintk (SX_DEBUG_OPEN, "at open: cd=%d\n", port->c_dcd); func_exit(); return 0;}/* I haven't the foggiest why the decrement use count has to happen here. The whole linux serial drivers stuff needs to be redesigned. My guess is that this is a hack to minimize the impact of a bug elsewhere. Thinking about it some more. (try it sometime) Try running minicom on a serial port that is driven by a modularized driver. Have the modem hangup. Then remove the driver module. Then exit minicom. I expect an "oops". -- REW */static void sx_hungup (void *ptr){ /* struct sx_port *port = ptr; */ func_enter (); /* Don't force the SX card to close. mgetty doesn't like it !!!!!! -- pvdl */ /* For some reson we added this code. Don't know why anymore ;-( -- pvdl */ /* sx_setsignals (port, 0, 0); sx_reconfigure_port(port); sx_send_command (port, HS_CLOSE, 0, 0); if (sx_read_channel_byte (port, hi_hstat) != HS_IDLE_CLOSED) { if (sx_send_command (port, HS_FORCE_CLOSED, -1, HS_IDLE_CLOSED) != 1) { printk (KERN_ERR "sx: sent the force_close command, but card didn't react\n"); } else sx_dprintk (SX_DEBUG_CLOSE, "sent the force_close command.\n"); } */ MOD_DEC_USE_COUNT; func_exit ();}static void sx_close (void *ptr){ struct sx_port *port = ptr; /* Give the port 5 seconds to close down. */ int to = 5 * HZ; func_enter (); sx_setsignals (port, 0, 0); sx_reconfigure_port(port); sx_send_command (port, HS_CLOSE, 0, 0); while (to-- && (sx_read_channel_byte (port, hi_hstat) != HS_IDLE_CLOSED)) { current->state = TASK_INTERRUPTIBLE; schedule_timeout (1); if (signal_pending (current)) break; } current->state = TASK_RUNNING; if (sx_read_channel_byte (port, hi_hstat) != HS_IDLE_CLOSED) { if (sx_send_command (port, HS_FORCE_CLOSED, -1, HS_IDLE_CLOSED) != 1) { printk (KERN_ERR "sx: sent the force_close command, but card didn't react\n"); } else sx_dprintk (SX_DEBUG_CLOSE, "sent the force_close command.\n"); } sx_dprintk (SX_DEBUG_CLOSE, "waited %d jiffies for close. count=%d\n", 5 * HZ - to - 1, port->gs.count); if(port->gs.count) { sx_dprintk(SX_DEBUG_CLOSE, "WARNING port count:%d\n", port->gs.count); port->gs.count = 0; } MOD_DEC_USE_COUNT; func_exit ();}/* This is relatively thorough. But then again it is only 20 lines. */#define MARCHUP for (i=min;i<max;i++) #define MARCHDOWN for (i=max-1;i>=min;i--)#define W0 write_sx_byte (board, i, 0x55)#define W1 write_sx_byte (board, i, 0xaa)#define R0 if (read_sx_byte (board, i) != 0x55) return 1#define R1 if (read_sx_byte (board, i) != 0xaa) return 1/* This memtest takes a human-noticable time. You normally only do it once a boot, so I guess that it is worth it. */static int do_memtest (struct sx_board *board, int min, int max){ int i; /* This is a marchb. Theoretically, marchb catches much more than simpler tests. In practise, the longer test just catches more intermittent errors. -- REW (For the theory behind memory testing see: Testing Semiconductor Memories by A.J. van de Goor.) */ MARCHUP {W0;} MARCHUP {R0;W1;R1;W0;R0;W1;} MARCHUP {R1;W0;W1;} MARCHDOWN {R1;W0;W1;W0;} MARCHDOWN {R0;W1;W0;} return 0;}#undef MARCHUP#undef MARCHDOWN#undef W0#undef W1#undef R0#undef R1#define MARCHUP for (i=min;i<max;i+=2) #define MARCHDOWN for (i=max-1;i>=min;i-=2)#define W0 write_sx_word (board, i, 0x55aa)#define W1 write_sx_word (board, i, 0xaa55)#define R0 if (read_sx_word (board, i) != 0x55aa) return 1#define R1 if (read_sx_word (board, i) != 0xaa55) return 1#if 0/* This memtest takes a human-noticable time. You normally only do it once a boot, so I guess that it is worth it. */static int do_memtest_w (struct sx_board *board, int min, int max){ int i; MARCHUP {W0;} MARCHUP {R0;W1;R1;W0;R0;W1;} MARCHUP {R1;W0;W1;} MARCHDOWN {R1;W0;W1;W0;} MARCHDOWN {R0;W1;W0;} return 0;}#endifstatic int sx_fw_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){ int rc = 0; int *descr = (int *)arg, i; static struct sx_board *board = NULL; int nbytes, offset; unsigned long data; char *tmp; func_enter();#if 0 /* Removed superuser check: Sysops can use the permissions on the device file to restrict access. Recommendation: Root only. (root.root 600) */ if (!capable(CAP_SYS_ADMIN)) { return -EPERM; }#endif sx_dprintk (SX_DEBUG_FIRMWARE, "IOCTL %x: %lx\n", cmd, arg); if (!board) board = &boards[0]; if (board->flags & SX_BOARD_PRESENT) { sx_dprintk (SX_DEBUG_FIRMWARE, "Board present! (%x)\n", board->flags); } else { sx_dprintk (SX_DEBUG_FIRMWARE, "Board not present! (%x) all:", board->flags); for (i=0;i< SX_NBOARDS;i++) sx_dprintk (SX_DEBUG_FIRMWARE, "<%x> ", boards[i].flags); sx_dprintk (SX_DEBUG_FIRMWARE, "\n"); return -EIO; } switch (cmd) { case SXIO_SET_BOARD: sx_dprintk (SX_DEBUG_FIRMWARE, "set board to %ld\n", arg); if (arg > SX_NBOARDS) return -EIO; sx_dprintk (SX_DEBUG_FIRMWARE, "not out of range\n"); if (!(boards[arg].flags & SX_BOARD_PRESENT)) return -EIO; sx_dprintk (SX_DEBUG_FIRMWARE, ".. and present!\n"); board = &boards[arg]; break; case SXIO_GET_TYPE: rc = -ENOENT; /* If we manage to miss one, return error. */ if (IS_SX_BOARD (board)) rc = SX_TYPE_SX; if (IS_CF_BOARD (board)) rc = SX_TYPE_CF; if (IS_SI_BOARD (board)) rc = SX_TYPE_SI; if (IS_EISA_BOARD (board)) rc = SX_TYPE_SI; sx_dprintk (SX_DEBUG_FIRMWARE, "returning type= %d\n", rc); break; case SXIO_DO_RAMTEST: if (sx_initialized) /* Already initialized: better not ramtest the board. */ return -EPERM; if (IS_SX_BOARD (board)) { rc = do_memtest (board, 0, 0x7000); if (!rc) rc = do_memtest (board, 0, 0x7000); /*if (!rc) rc = do_memtest_w (board, 0, 0x7000);*/ } else { rc = do_memtest (board, 0, 0x7ff8); /* if (!rc) rc = do_memtest_w (board, 0, 0x7ff8); */ } sx_dprintk (SX_DEBUG_FIRMWARE, "returning memtest result= %d\n", rc); break; case SXIO_DOWNLOAD: if (sx_initialized) /* Already initialized */ return -EEXIST; if (!sx_reset (board)) return -EIO; sx_dprintk (SX_DEBUG_INIT, "reset the board...\n"); tmp = kmalloc (SX_CHUNK_SIZE, GFP_USER); if (!tmp) return -ENOMEM; Get_user (nbytes, descr++); Get_user (offset, descr++); Get_user (data, descr++); while (nbytes && data) { for (i=0;i<nbytes;i += SX_CHUNK_SIZE) { copy_from_user (tmp, (char *)data+i, (i+SX_CHUNK_SIZE>nbytes)?nbytes-i:SX_CHUNK_SIZE); memcpy_toio ((char *) (board->base2 + offset + i), tmp, (i+SX_CHUNK_SIZE>nbytes)?nbytes-i:SX_CHUNK_SIZE); } Get_user (nbytes, descr++); Get_user (offset, descr++); Get_user (data, descr++); } kfree (tmp); sx_nports += sx_init_board (board); rc = sx_nports; break; case SXIO_INIT: if (sx_initialized) /* Already initialized */ return -EEXIST; /* This is not allowed until all boards are initialized... */ for (i=0;i<SX_NBOARDS;i++) { if ( (boards[i].flags & SX_BOARD_PRESENT) && !(boards[i].flags & SX_BOARD_INITIALIZED)) return -EIO; } for (i=0;i<SX_NBOARDS;i++) if (!(boards[i].flags & SX_BOARD_PRESENT)) break; sx_dprintk (SX_DEBUG_FIRMWARE, "initing portstructs, %d boards, " "%d channels, first board: %d ports\n", i, sx_nports, boards[0].nports); rc = sx_init_portstructs (i, sx_nports); sx_init_drivers (); if (rc >= 0) sx_initialized++; break; case SXIO_SETDEBUG: sx_debug = arg; break; case SXIO_GETDEBUG: rc = sx_debug; break; case SXIO_GETGSDEBUG: case SXIO_SETGSDEBUG: rc = -EINVAL; break; case SXIO_GETNPORTS: rc = sx_nports; break; default: printk (KERN_WARNING "Unknown ioctl on firmware device (%x).\n", cmd); break; } func_exit (); return rc;}static void sx_break (struct tty_struct * tty, int flag){ struct sx_port *port = tty->driver_data; int rv; if (flag)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -