📄 usb-char.c
字号:
{ int retval = 0; PRINTK( KERN_DEBUG "%sopen()\n", pszMe ); /* start usb core */ retval = sa1100_usb_open( "usb-char" ); if ( retval ) return retval; /* allocate memory */ if ( usb_ref_count == 0 ) { tx_buf = (char*) kmalloc( TX_PACKET_SIZE, GFP_KERNEL | GFP_DMA ); if ( tx_buf == NULL ) { printk( "%sARGHH! COULD NOT ALLOCATE TX BUFFER\n", pszMe ); goto malloc_fail; } rx_ring.buf = (char*) kmalloc( RBUF_SIZE, GFP_KERNEL ); if ( rx_ring.buf == NULL ) { printk( "%sARGHH! COULD NOT ALLOCATE RX BUFFER\n", pszMe ); goto malloc_fail; } packet_buffer = (char*) kmalloc( RX_PACKET_SIZE, GFP_KERNEL | GFP_DMA ); if ( packet_buffer == NULL ) { printk( "%sARGHH! COULD NOT ALLOCATE RX PACKET BUFFER\n", pszMe ); goto malloc_fail; } rx_ring.in = rx_ring.out = 0; memset( &charstats, 0, sizeof( charstats ) ); sending = 0; last_tx_result = 0; last_tx_size = 0; } /* modify default descriptors */ twiddle_descriptors(); retval = sa1100_usb_start(); if ( retval ) { printk( "%sAGHH! Could not USB core\n", pszMe ); free_txrx_buffers(); return retval; } usb_ref_count++; /* must do _before_ kick_start() */ MOD_INC_USE_COUNT; kick_start_rx(); return 0; malloc_fail: free_txrx_buffers(); return -ENOMEM;}/* * Read endpoint. Note that you can issue a read to an * unconfigured endpoint. Eventually, the host may come along * and configure underneath this module and data will appear. */static ssize_t usbc_read( struct file *pFile, char *pUserBuffer, size_t stCount, loff_t *pPos ){ ssize_t retval; int flags; DECLARE_WAITQUEUE( wait, current ); PRINTK( KERN_DEBUG "%sread()\n", pszMe ); local_irq_save( flags ); if ( last_rx_result == 0 ) { local_irq_restore( flags ); } else { /* an error happended and receiver is paused */ local_irq_restore( flags ); last_rx_result = 0; kick_start_rx(); } add_wait_queue( &wq_read, &wait ); while( 1 ) { ssize_t bytes_avail; ssize_t bytes_to_end; set_current_state( TASK_INTERRUPTIBLE ); /* snap ring buf state */ local_irq_save( flags ); bytes_avail = CIRC_CNT( rx_ring.in, rx_ring.out, RBUF_SIZE ); bytes_to_end = CIRC_CNT_TO_END( rx_ring.in, rx_ring.out, RBUF_SIZE ); local_irq_restore( flags ); if ( bytes_avail != 0 ) { ssize_t bytes_to_move = MIN( stCount, bytes_avail ); retval = 0; // will be bytes transfered if ( bytes_to_move != 0 ) { size_t n = MIN( bytes_to_end, bytes_to_move ); if ( copy_to_user( pUserBuffer, &rx_ring.buf[ rx_ring.out ], n ) ) { retval = -EFAULT; break; } bytes_to_move -= n; retval += n; // might go 1 char off end, so wrap rx_ring.out = ( rx_ring.out + n ) & (RBUF_SIZE-1); if ( copy_to_user( pUserBuffer + n, &rx_ring.buf[ rx_ring.out ], bytes_to_move ) ) { retval = -EFAULT; break; } rx_ring.out += bytes_to_move; // cannot wrap retval += bytes_to_move; kick_start_rx(); } break; } else if ( last_rx_result ) { retval = last_rx_result; break; } else if ( pFile->f_flags & O_NONBLOCK ) { // no data, can't sleep retval = -EAGAIN; break; } else if ( signal_pending( current ) ) { // no data, can sleep, but signal retval = -ERESTARTSYS; break; } schedule(); // no data, can sleep } set_current_state( TASK_RUNNING ); remove_wait_queue( &wq_read, &wait ); if ( retval < 0 ) printk( "%sread error %d - %s\n", pszMe, retval, what_the_f( retval ) ); return retval;}/* * Write endpoint. This routine attempts to break the passed in buffer * into usb DATA0/1 packet size chunks and send them to the host. * (The lower-level driver tries to do this too, but easier for us * to manage things here.) * * We are at the mercy of the host here, in that it must send an IN * token to us to pull this data back, so hopefully some higher level * protocol is expecting traffic to flow in that direction so the host * is actually polling us. To guard against hangs, a 5 second timeout * is used. * * This routine takes some care to only report bytes sent that have * actually made it across the wire. Thus we try to stay in lockstep * with the completion routine and only have one packet on the xmit * hardware at a time. Multiple simultaneous writers will get * "undefined" results. * */static ssize_t usbc_write( struct file *pFile, const char * pUserBuffer, size_t stCount, loff_t *pPos ){ ssize_t retval = 0; ssize_t stSent = 0; DECLARE_WAITQUEUE( wait, current ); PRINTK( KERN_DEBUG "%swrite() %d bytes\n", pszMe, stCount ); down( &xmit_sem ); // only one thread onto the hardware at a time while( stCount != 0 && retval == 0 ) { int nThisTime = MIN( TX_PACKET_SIZE, stCount ); copy_from_user( tx_buf, pUserBuffer, nThisTime ); sending = nThisTime; retval = sa1100_usb_send( tx_buf, nThisTime, tx_done_callback ); if ( retval < 0 ) { char * p = what_the_f( retval ); printk( "%sCould not queue xmission. rc=%d - %s\n", pszMe, retval, p ); sending = 0; break; } /* now have something on the diving board */ add_wait_queue( &wq_write, &wait ); tx_timer.expires = jiffies + ( HZ * 5 ); add_timer( &tx_timer ); while( 1 ) { set_current_state( TASK_INTERRUPTIBLE ); if ( sending == 0 ) { /* it jumped into the pool */ del_timer( &tx_timer ); retval = last_tx_result; if ( retval == 0 ) { stSent += last_tx_size; pUserBuffer += last_tx_size; stCount -= last_tx_size; } else printk( "%sxmission error rc=%d - %s\n", pszMe, retval, what_the_f(retval) ); break; } else if ( signal_pending( current ) ) { del_timer( &tx_timer ); printk( "%ssignal\n", pszMe ); retval = -ERESTARTSYS; break; } schedule(); } set_current_state( TASK_RUNNING ); remove_wait_queue( &wq_write, &wait ); } up( &xmit_sem ); if ( 0 == retval ) retval = stSent; return retval;}static unsigned int usbc_poll( struct file *pFile, poll_table * pWait ){ unsigned int retval = 0; PRINTK( KERN_DEBUG "%poll()\n", pszMe ); poll_wait( pFile, &wq_poll, pWait ); if ( CIRC_CNT( rx_ring.in, rx_ring.out, RBUF_SIZE ) ) retval |= POLLIN | POLLRDNORM; if ( sa1100_usb_xmitter_avail() ) retval |= POLLOUT | POLLWRNORM; return retval;}static int usbc_ioctl( struct inode *pInode, struct file *pFile, unsigned int nCmd, unsigned long argument ){ int retval = 0; switch( nCmd ) { case USBC_IOC_FLUSH_RECEIVER: sa1100_usb_recv_reset(); rx_ring.in = rx_ring.out = 0; break; case USBC_IOC_FLUSH_TRANSMITTER: sa1100_usb_send_reset(); break; case USBC_IOC_FLUSH_ALL: sa1100_usb_recv_reset(); rx_ring.in = rx_ring.out = 0; sa1100_usb_send_reset(); break; default: retval = -ENOIOCTLCMD; break; } return retval;}static int usbc_close( struct inode *pInode, struct file * pFile ){ PRINTK( KERN_DEBUG "%sclose()\n", pszMe ); if ( --usb_ref_count == 0 ) { down( &xmit_sem ); sa1100_usb_stop(); free_txrx_buffers(); free_string_descriptors(); del_timer( &tx_timer ); sa1100_usb_close(); up( &xmit_sem ); } MOD_DEC_USE_COUNT; return 0;}#ifdef CONFIG_SA1100_EXTENEX1#include "../../../drivers/char/ex_gpio.h"void extenex_configured_notify_proc( void ){ if ( exgpio_play_string( "440,1:698,1" ) == -EAGAIN ) printk( "%sWanted to BEEP but ex_gpio not open\n", pszMe );}#endif//////////////////////////////////////////////////////////////////////////////// Initialization//////////////////////////////////////////////////////////////////////////////static struct file_operations usbc_fops = { owner: THIS_MODULE, open: usbc_open, read: usbc_read, write: usbc_write, poll: usbc_poll, ioctl: usbc_ioctl, release: usbc_close,};static struct miscdevice usbc_misc_device = { USBC_MINOR, "usb_char", &usbc_fops};/* * usbc_init() */int __init usbc_init( void ){ int rc;#if !defined( CONFIG_ARCH_SA1100 ) return -ENODEV;#endif if ( (rc = misc_register( &usbc_misc_device )) != 0 ) { printk( KERN_WARNING "%sCould not register device 10, " "%d. (%d)\n", pszMe, USBC_MINOR, rc ); return -EBUSY; } // initialize wait queues init_waitqueue_head( &wq_read ); init_waitqueue_head( &wq_write ); init_waitqueue_head( &wq_poll ); // initialize tx timeout timer init_timer( &tx_timer ); tx_timer.function = tx_timeout; printk( KERN_INFO "USB Function Character Driver Interface" " - %s, (C) 2001, Extenex Corp.\n", VERSION ); return rc;}void __exit usbc_exit( void ){}EXPORT_NO_SYMBOLS;module_init(usbc_init);module_exit(usbc_exit);// end: usb-char.c
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -