📄 usb-char.c
字号:
wake_up_interruptible( &wq_poll );}//////////////////////////////////////////////////////////////////////////////// Workers//////////////////////////////////////////////////////////////////////////////#ifdef CONFIG_MIZIstatic void usbc_alloc_mem(void){ PRINTK("\n"); tx_buf = (char*) kmalloc( TX_PACKET_SIZE, GFP_KERNEL | GFP_DMA ); if ( tx_buf == NULL ) { PRINTK( "%sARGHH! COULD NOT ALLOCATE TX BUFFER\n", pszMe ); } rx_ring.buf = (char*) kmalloc( RBUF_SIZE, GFP_KERNEL ); if ( rx_ring.buf == NULL ) { PRINTK( "%sARGHH! COULD NOT ALLOCATE RX BUFFER\n", pszMe ); } 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); } //usbc_ioctl(0, 0, USBC_IOC_FLUSH_ALL, 0);}#endifstatic int usbc_open( struct inode *pInode, struct file *pFile ){ MOD_INC_USE_COUNT; kick_start_rx(); return 0;}/* * 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( "count=%d", stCount); 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 );#ifndef CONFIG_MIZI if ( retval < 0 ) printk( "%sread error %d - %s\n", pszMe, retval, what_the_f( retval ) );#endif 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 = s3c2410_usb_send( tx_buf, nThisTime, tx_done_callback ); if ( retval < 0 ) {#ifndef CONFIG_MIZI char * p = what_the_f( retval ); printk( "%sCould not queue xmission. rc=%d - %s\n", pszMe, retval, p );#endif 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; }#ifndef CONFIG_MIZI else printk( "%sxmission error rc=%d - %s\n", pszMe, retval, what_the_f(retval) );#endif 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 ( s3c2410_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: s3c2410_usb_recv_reset(); rx_ring.in = rx_ring.out = 0; break; case USBC_IOC_FLUSH_TRANSMITTER: s3c2410_usb_send_reset(); break; case USBC_IOC_FLUSH_ALL: s3c2410_usb_recv_reset(); rx_ring.in = rx_ring.out = 0; s3c2410_usb_send_reset(); break; default: retval = -ENOIOCTLCMD; break; } return retval;}#ifdef CONFIG_MIZIstatic intusbc_activate(void){ int retval = 0; PRINTK("\n"); /* start usb core */ retval = s3c2410_usb_open( "usb-char" ); twiddle_descriptors(); retval = s3c2410_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() */ kick_start_rx(); return 0;}static voidusbc_deactivate(void){ PRINTK("\n"); down( &xmit_sem ); s3c2410_usb_stop(); del_timer( &tx_timer ); s3c2410_usb_close(); up( &xmit_sem );}#endifstatic int usbc_close( struct inode *pInode, struct file * pFile ){ PRINTK( KERN_DEBUG "%sclose()\n", pszMe );#ifdef CONFIG_MIZI --usb_ref_count;#else if ( --usb_ref_count == 0 ) { down( &xmit_sem ); s3c2410_usb_stop(); free_txrx_buffers(); free_string_descriptors(); del_timer( &tx_timer ); s3c2410_usb_close(); up( &xmit_sem ); }#endif MOD_DEC_USE_COUNT; return 0;}//////////////////////////////////////////////////////////////////////////////// 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_S3C2410 ) 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;#ifdef CONFIG_MIZI memset( &charstats, 0, sizeof( charstats ) ); sending = 0; last_tx_result = 0; last_tx_size = 0;#endif printk( KERN_INFO "USB Function Character Driver Interface" " - %s, (C) 2001, Extenex Corp.\n", VERSION); #ifdef CONFIG_MIZI#ifdef CONFIG_PM usb_char_pm_dev = pm_register(PM_SYS_DEV, PM_SYS_MISC, usbchar_pm_callback);#endif usbc_alloc_mem(); usbc_activate();#endif return rc;}void __exit usbc_exit( void ){#ifdef CONFIG_MIZI usbc_deactivate(); free_txrx_buffers(); free_string_descriptors();#ifdef CONFIG_PM if (usb_char_pm_dev) pm_unregister(usb_char_pm_dev);#endif #endif misc_deregister( &usbc_misc_device );}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 + -